A while back somebody showed me a casual gaming site where people play each other at a variety of card games. No money, you just play for points and to gain ranking among the thousands of players present there. The site offers a limited amount of daily free play time, beyond which you have to pay to get a subscription. I gave it a shot and played for a bit.
But then my AI instinct started thinking about how to make a computer play cards. Could I write a program that would play perfectly? And could I hack the system to obtain the stream of game data necessary for an automated player to participate in real, live games? It seemed an interesting technical challenge for a small project.
Having decided the particular card game to play, I had to figure out how to make the computer play it. I figured that with appropriate game play data I could implement a minimax type algorithm and a heuristic evaluation function to do a decent job. So that’s what I did, with a little tuning to get the heuristic correct and some basic probability judgements as to what cards could be dealt.
Now came the hard part, getting the program to read in the game information as it’s being played. The program has to be in sync, seeing everything that happens in order to make its moves. A human just looks at the screen and sees the cards that are dealt, played, the points etc, but a program sitting on your computer can’t do that easily.
In fact, the visual route is one of three I considered. What it entails is capturing screenshots of the gaming area continuously, and then using sophisticated image recognition algorithms to detect dealt cards, played cards, scores and other visual components. It’s tricky and computationally expensive in real time. The game I selected plays very quickly, people make their moves in seconds, so it would be almost impossible in a mini project.
The second route I thought of was capturing network traffic with the gaming site. Since all the game information has to be transmitted to the game client (in the browser) then you could in theory monitor the connection and sniff out what you need. I brought up a browser console and looked at the requests and returned info. Not good. It seemed that the traffic was encoded with some scheme precisely to make it unreadable. Not something to be reverse engineered in a couple of days.
Now, something I haven’t said until now is that this gaming site uses java applets embedded in the web browser to create the gaming client interface, i.e. the gaming window where you see cards, players, make your moves etc. I inspected the html and found references to the code files (jar files). What about decompiling said code and trying to read the reverse engineered source code to see what was going on?
I ran a decompiler and started looking at the reconstructed package structure and source classes. It was a lot, and some names were cryptic, but I managed to spot some files and packages that had meaningful names. Tracing calls between 20 or so files narrowed down the search to a candidate file that looked promising, its methods represented meaningful game events, and parameters and attributes appeared to contain the desired game state information.
But then what? Even if I could trace the code to the important locations, how could I get it to talk to my program? After all, that code could not be modified, it would come from the gaming site’s server. And even if there was some way to locally alter the client, the code would not compile after a decompiling process that was flaky.
Didn’t seem to be an easy way around this… except for using a tracing tool based on code instrumentation. Btrace allows you to inject code into an external jvm process at methods which you specify via type signatures. The code you can inject is subject to strong restrictions and requires you to use a special API to access the host code’s parameters and state. It’s cumbersome, but it works well. You connect to an external vm and it does its magic.
What I had to do, then, was inject the key methods with code to access the important information. I could output this data as text, and then pipe it to my program which would parse the input, synchronize game state, and run its minimax algorithm. The result would be a set of possible moves and scores, along with a search tree so that you could review the computer’s thinking.
All that was left was trying it out. Which meant connecting to the gaming site, launching the tracing tool piped to the game program, and making its moves manually in the browser. I could have done a bit more work to get the program to play directly, but the main interesting bits were done.
So, how did it do? Well, the whole setup had a 90%+ winning rate. Not surprising given the card data that it streamed combined with minimax. After a few days of free playing the rating shot up very quickly, and could easily achieve the top spot out of approximately 8000 players.
Wrapping up, it was an interesting technical challenge for a small project.
You’re probably thinking, isn’t using a computer bot cheating? Of course it’s cheating, that’s why I call this a hack, even though it’s just the game client that got hacked. The site should plug these holes so that people can’t do this to win systematically, especially considering that it’s a paid service. Although I suspect that anybody (more like nobody) setting up something like this is doing it for the challenge and shelves the solution as soon as it’s working.Note: feel free to contact me for details if you think your site is the victim!