For this project I targeted a popular play-money web application for No Limit Texas Hold Em, and developed a complete async network client for the game in python with asyncio. This includes an HTTP client for their REST(ish) internal API, as well as a fully functional websocket client for in game messages to automate collecting chips and playing tables.
In addition to the clients, the real fun part is in the scripts using those clients. I developed a taskrunner that continuously ran tasks that were scheduled every x minutes, which basically amounted to automatically collecting free chips on huge number of accounts in the botfarm. As well as a cli that provided me an administrative route to control all those bots.
This page will provide a general rundown of the project without any real concrete specifics, but if there’s interest I may expand further on a few sections of the project in multiple blog posts.
As a huge fan of watching and playing poker, I initially wanted to try my hand at developing a poker bot. But before I could write a bot that could play poker well, I was going to have to write a bot that could play poker at all. By that I mean, I needed to find a platform to play on, a way to get info about the game state, and a way to send actions to the game. So for this project I decided I would build out an entire network client, rather than do something primitive and limited like screen scraping and sending click commands to the OS.
Let’s face it, having a ton of chips never hurt. The site that I played on offered free chips every few hours to accounts, as well as a few ways to get some additional free chips. So I figured why not have a bunch of accounts collect a bunch of chips, a botfarm.
Because this project is so large in scope I’ll provide a quick description of each component and then go into more detail for each one individually later:
The reason why I chose to implement a complete Network Client, with all of it’s added complexity was simply because a screen scraping and clicking method would be far too limited. Limited in the sense that I could only run a few bots at any one time with a method like that because I’m limited by what fits on the screen. It would also be really brittle as it would either rely on computer vision and be fairly slow for multiple clients, or hardcoded pixel offsets to find information.
Let’s take a look at the Web Client in the browser before we look at my client.
In the above diagram, a client (in this case, a web browser) sends HTTP Requests to the site and site lets the client establish a websocket connection with one of the game servers. In this case the Poker Site handles most stuff like querying data through a REST(ish) interface and the Game Servers handle all the game-related processing like assigning tables and managing hands being played at any one given table.
The HTTP Client handles a large portion of the functionality that the website provides, namely:
Basically everything that isn’t directly related to a hand of actual poker being played.
Once an HTTP client logs in to the site and establishes which Game Server (Casino) it’s going to be using, then the websocket connection is opened with that game server and the websocket client sends an authentication message with the token that the HTTP client was given. In order for me to develop this websocket client i had to first discover how the websocket messages were structured, and what kind of encryption or encoding they might be using.
After looking at a few of the messages being sent ending with the = sign I figured the messages were probably being Base64 Encoded. After decoding them with Base 64 they still looked like gibberish, so I went into the obfuscated code in the web app and after some looking around I found a protocol buffers definition. I cleaned up the .json file inside the obfuscated code with the protocol buffers definitions in them and compiled my own python library from those definitons with the Protobuf Compiler.
With the Base 64 decoded string I then tried to use the protobuf generated python to parseFromString
and it worked! Success! Now I was able to send and receive valid messages to the poker app. As an example a ping message in the application would look like this in .proto
form and its websocket message form.
# proto3 file
message Ping {
int32 pingId = 1;
}
# Websocket Message
oAYJSgMI40g=
Using the Click python library I built out a CLI that utilized the Clients to automate some tasks with the parameters that I provided. This allowed me to easily handle any administrative duties I had to do on the botfarm, like:
Finally, I wrote a simple python script that continuously runs, and executes a scheduled task every n minutes that it was scheduled to run for. Basically, I’ve got a a few main tasks:
Here are some of my ideas for future additions to the project:
In Pot Limit Omaha each player gets 4 hole cards. That means with 3 bots at the table I could know up to 18 cards in the deck, which makes the probability calculations alone much more certain. (4*3 = 12 hole cards + 5 Community Cards). Would be cool to develop a strategy for colluding bots that could work together to extract maximal value out of opponents.
Now that I’ve got all the infrastructure built out, I’d like to go back to that original goal of developing a bot that can play poker well.
Having a way of viewing the status of the bots, scheduling tasks, and running commands all from a web browser would be ideal so I could manage the botfarm without having to go to the cli.
Assuming they even care to catch botters, there’s a few things they could do to stop botting/cheating.