Saturday, September 8, 2012

Chess Bot for PlayChess

     As you know I have always been interested in automating things, so creating bots is a passion for me.I have created many bots for games, as well as for websites where you need to automate things. Any program that automates some process is defined as a bot for me.

     Notice that I didn't use the more common term Chess AI because I didn't create it. AI is just about making a decision where bots include scraping data, processing data and outputing data. Chess AI needs a well formatted board state, but if you are writing a chess bot for example for PlayChess.com you don't have the well defined structure in your hands. You need to somehow scrape the data out of it, either by memory reading which can get really tedious if developers added a security measure for it, or by image processing which is easier for most of the cases.

     If it wasn't a native application, and it was but a javascript web application there is a third and easier way, scraping and manipulating DOM. So writing bots for web applications are very easy compared to native applications with some security measures.

     I usually use C#.NET to write bots and most of my projects since I don't care about portability of my pet-projects.

     Part 1) Scraping the data via image processing


     I noticed that everytime I open a new chess game on playchess the board starts at the same pixel coordinates, so that saved me from a great work, I also noticed that the tiles are 64*64 pixels. So using the CopyFromScreen  function I copied the screen to a bitmap and tiled that to 64 bitmaps which are each 64*64 pixels.There are 13 types of tiles possible, 6 white pieces, 6 black pieces, and 1 empty tile. At first I identified all of these pieces uniquely through image processing. But then I realized I don't have to do that. The only thing I need to do is to identify the color of the tile, either white, or black or empty. Because I was creating a fully-autonomous bot, it will never involve in a game in the middle. I mean from the start on it will see all the positions. So if I know all the moves in terms of source and destination coordinates, and if I know the starting position which is well defined and static, so it is enough to know the only piece colors not the piece types. Because latter one can be derived from the known things. So I dropped out the unique piece determining and I continued with color identifying which is easier and more error-prone. This may only cause a problem when opponent is promoting a pawn, you wouldn't know which type of piece it is but it is queen 99% of the time. After getting the board position we must format it so we can pass it to the Chess AI if the AI is not written by us. (mine wasn't)

    Part 2) Passing the board state to a Chess AI


     Picking a Chess Engine is important, if you have your own engine that is good , you can probably connect that easily to your bot, but if that is not the case, you must use 2 functions, first one should convert the board state to a format that engine can understand, and the second one should convert the engine moves to a format that yours output layer can understand.

     If the engine you found is open-source your job is easier since you will obviously have access to code. I found crafty chess engine which is both open source, robust and powerful, you can find it here http://www.craftychess.com/ . But I don't use crafty's open source property, since crafty already gave me enough options. For example the command "output long" makes crafty to output moves like Nb1c3 which is easier to parse, normally chess moves are like Nc3, so you have to calculate the starting position which is a hard work for example when two pieces can move to the same location it gets even harder.
Another command "xboard" mutes crafty's unwanted data, it only outputs it's moves which is also better for us because we don't care about how many positions it analyzed and those kinds of information.

     I got crafty's exe and in my loop everytime a new game starts I start a process too, and redirect it's standart input and output to my C# program.

    Part 3) Passing the result of Chess AI to PlayChess client


     Now the last part is to make the move on the native application. You can try many things, you may intercept TCP packets and send your own tcp packets, or an easier way is to use Windows' SendMessage and SendInput API to make the move. I used this library http://inputsimulator.codeplex.com/ for it's simplicity for this project. You should turn the Chess AI's move output to source and destination coordinates, after that you can write a function like this and make your moves !!

public void makeMove(int r1, int c1, int r2, int c2)
        {
            InputSimulator inputsimul = new InputSimulator();
            inputsimul .Mouse.MoveMouseTo((c1*64+32+76) * (65535.0 / 1366.0), (r1*64+32+161) * (65535 / 768.0));
            System.Threading.Thread.Sleep(200);
             inputsimul  .Mouse.LeftButtonDown();
            System.Threading.Thread.Sleep(200);
             inputsimul  .Mouse.MoveMouseTo((c2 * 64 + 32 + 76) * (65535.0 / 1366.0), (r2 * 64 + 32 + 161) * (65535 / 768.0));
            System.Threading.Thread.Sleep(200);
             inputsimul  .Mouse.LeftButtonUp();
        }

This makes a drap-drop move from r1,c1 to r2,c2 where these variables represent tile coordinates, not pixel coordinates. +32 is used for clicking in the middle, 76 is offset of my board and the inputsimulator library takes input from 0 to 65535 where 65535 represents the maximum width or height of your screen.


Here is a video of my bot working,


http://www.youtube.com/watch?v=sjuB0__N8bE

No comments:

Post a Comment