I think I'd better stop here. There are a few more things I could add, but they won't improve it very much, seem quite difficult to implement, and I've already done what I've set out to do. Also there's a deadline very soon.
Since the last update, I've added the ability to undo moves, made some buttons for people who can't handle keyboard shortcuts, fixed a few bugs involving pawn promotion, and made the AI slightly less aimless in the opening part of the game (it's still utterly aimless in endgames: if you have only a king, and it has two rooks, it won't ever let you capture the rooks, but it will dance around with until it happens to checkmate you).
Now I have to fill in all these forms, reports, reviews and conclusions that the examiners love so much. Sigh...
Oh, and I'll put the source code up, if anybody is at all interested in how I did something: Link to source code
And I just realised I haven't put up any new screenshots. So here:
Matt Rumble's Extended Project
Designing and building a chess AI
Saturday, 16 February 2013
Wednesday, 13 February 2013
Update
Since the last update I have:
Made it an awful let quicker, thanks to a great suggestion by an anonymous guy on an anonymous internet forum. The majority of the time taken for the AI to move was spent just copying chess board data structures (this had to be done about 500,000 times, and each board was an array of 120 items). The suggestion was to add a function that undoes a chess move, and then I could do the following in my recursive function:
recursive function:
makeMove
call recursive function again
undoMove
end function
Because of the beauty of recursion, I only ever need one board to accomplish this, it's fantastic. This has sped up the time the AI takes on a very tricky configuration from a maximum of 13 seconds to 3 seconds.
I also made a few little petty optimisations, added an icon, and displayed where the AI last moved (because I found if I blinked when it moved, I couldn't work out where it had moved to/from).
Made it an awful let quicker, thanks to a great suggestion by an anonymous guy on an anonymous internet forum. The majority of the time taken for the AI to move was spent just copying chess board data structures (this had to be done about 500,000 times, and each board was an array of 120 items). The suggestion was to add a function that undoes a chess move, and then I could do the following in my recursive function:
recursive function:
makeMove
call recursive function again
undoMove
end function
Because of the beauty of recursion, I only ever need one board to accomplish this, it's fantastic. This has sped up the time the AI takes on a very tricky configuration from a maximum of 13 seconds to 3 seconds.
I also made a few little petty optimisations, added an icon, and displayed where the AI last moved (because I found if I blinked when it moved, I couldn't work out where it had moved to/from).
Thursday, 7 February 2013
Added a list of where the pieces are
The program has sped up considerably after I made this small change. Whereas before, it took 5-10 seconds to look 3 moves ahead, and took forever to look 4 moves ahead, now it can look 3 moves ahead instantly (pretty much), and 5-10 seconds to look 4 moves ahead.
Before, when generating all the moves from a board, I searched every square on the board, and then found the squares with pieces on them, from which I could generate moves. Now, I've "attached" two lists to each board, one with all the indexes containing white pieces, and one for black pieces. So when I look for all the pieces, I can just loop through all the pieces in one of the lists. Yay, optimisation!
Before, when generating all the moves from a board, I searched every square on the board, and then found the squares with pieces on them, from which I could generate moves. Now, I've "attached" two lists to each board, one with all the indexes containing white pieces, and one for black pieces. So when I look for all the pieces, I can just loop through all the pieces in one of the lists. Yay, optimisation!
Monday, 4 February 2013
So how can I improve this?
As mentioned in previous posts, the program works, but it can certainly be improved. And here are some possible ways how that can be done:
- Avoid searching for the pieces in every board: When the moves are generated for a board, every square on the board is checked to see if it contains a piece that can make a move. I imagine quite a bit of time could be saved if I attached to the board a list of all the squares containing the white pieces, and all the squares containing the black pieces.
- Move ordering: A core part of alpha-beta pruning is not following up a move if it isn't going to be better than previous ones. This works much better when the first moves checked are most likely to be the better moves.
- Opening moves library: This would put the AI in a much better position for the rest of the game; using tried and tested opening moves, because it certainly cannot look forward enough itself to work out good opening moves.
- Endgame moves library: Although it performs fairly well and quickly in the endgame phase (because there are a small number of moves to analyse), it would be made as close to unbeatable as possible if some sort of endgame library was introduced when there are, say, 5 or fewer pieces. This link gives an example of what I'm talking about.
Sunday, 3 February 2013
What needs to be done
At present, my program plays completely bug-free (as far as I can tell). The problems now are the speed, and the number of moves it can look ahead at.
Speed:
The following image is a graph showing time taken against number of moves analysed. For a large amount of moves (generally during the mid-game phase), the maximum time taken is about 24 seconds. This is quite annoying when playing, and it would be nice if this time could be reduced.
Number of moves:
At present, the program looks 3 moves ahead (that is, a computer move, followed by a player move, followed by a computer move). While this works well in most situations, it makes the program rather useless at evading checkmate, in particular, it can't avoid Fool's Mate. I have programmed it to not actually detect check when looking forward (because testing whether every move leads to check would take far too long), instead it evaluates the boards, and if the king has been taken, the board will have a very low score (because the king is given a value much, much higher than any other piece), and it will infer from that, that there was check a move ago. So because of this, it can't look far enough ahead to avoid most checkmates. Silly thing.
Speed:
The following image is a graph showing time taken against number of moves analysed. For a large amount of moves (generally during the mid-game phase), the maximum time taken is about 24 seconds. This is quite annoying when playing, and it would be nice if this time could be reduced.
Number of moves:
At present, the program looks 3 moves ahead (that is, a computer move, followed by a player move, followed by a computer move). While this works well in most situations, it makes the program rather useless at evading checkmate, in particular, it can't avoid Fool's Mate. I have programmed it to not actually detect check when looking forward (because testing whether every move leads to check would take far too long), instead it evaluates the boards, and if the king has been taken, the board will have a very low score (because the king is given a value much, much higher than any other piece), and it will infer from that, that there was check a move ago. So because of this, it can't look far enough ahead to avoid most checkmates. Silly thing.
Friday, 1 February 2013
IT IS GLORIOUS!
After an hour or so of persuading myself that I should start working on my Extended Project again, I started working on my Extended Project, and within a few minutes found a tiny oversight in the code (I put 119 where it should have been 121) which explains why the computer was playing so randomly when it was meant to be looking at least 2 moves ahead. So I fixed that, then tested it, and I've only played 1 game so far, but the program actually seems to be looking ahead for moves.
Anyway, I was in the middle of this game, and the most wonderful thing happened. The program forked me (see image, it moved the black knight). It made an intelligent move. It was magical. It's the cleverest thing that something I've made has done. This must be what it feels like to raise a child, and then watching that child grow up to be an astronaut, or a hotshot lawyer.
Anyway, I was in the middle of this game, and the most wonderful thing happened. The program forked me (see image, it moved the black knight). It made an intelligent move. It was magical. It's the cleverest thing that something I've made has done. This must be what it feels like to raise a child, and then watching that child grow up to be an astronaut, or a hotshot lawyer.
Saturday, 12 January 2013
Check and checkmate implemented.
After a lot of bugs, I've finally implemented check and checkmate in to my program. So now, a player can't move in to check, a player has to move out of check, and checkmate can be detected, and will end the game.
I also tidied up the code a fair bit, it's very easy for subroutines to get out of hand on a project like this.
And pawn promotion is done. Although you can only promote a pawn to a queen, but it's just not worth implementing pawn promotion to any piece.
One strange little glitch I'm having is when a game is won and the board is reset, a seemingly random piece appears on the square shown in the picture. How peculiar.
I also tidied up the code a fair bit, it's very easy for subroutines to get out of hand on a project like this.
And pawn promotion is done. Although you can only promote a pawn to a queen, but it's just not worth implementing pawn promotion to any piece.
One strange little glitch I'm having is when a game is won and the board is reset, a seemingly random piece appears on the square shown in the picture. How peculiar.
Thursday, 10 January 2013
Another bug
Because I've already established examiners love problem-solving abilities, I'll post another problem. I tried to add a function that will work out whether or not a player is in check after the opponent makes their move, but what it does is constantly tell everyone they're in check, after every single move. So I'll fix it and then edit this post to explain how I fixed it. I hate posting mundane stuff like this.
EDIT:
Well, here's what the problem was. As I might have explained somewhere else on the blog, each different chess piece is represented by a number, 1 being a pawn, 2 being a rook, etc. Positive number are white pieces, negative numbers are black pieces (-1 is a black pawn, 1 is a white pawn). To work out whether the king was in check, I traced outwards from the king, looking for certain pieces in certain directions (i.e. bishops or queens diagonally). In the check for these pieces, I compared the absolute value of the piece to the pieces I was looking for, because it required less thought than trying to work out the correct sign. That is, if I was looking for a bishop diagonally, I'd check in all diagonal directions whether the absolute value of the piece was 4 (the bishop's number). Stupidly enough, I didn't realise this would also include piece's that belonged to the player, along with the opponent's pieces. So basically, each player's queen kept putting that player in to check.
EDIT:
Well, here's what the problem was. As I might have explained somewhere else on the blog, each different chess piece is represented by a number, 1 being a pawn, 2 being a rook, etc. Positive number are white pieces, negative numbers are black pieces (-1 is a black pawn, 1 is a white pawn). To work out whether the king was in check, I traced outwards from the king, looking for certain pieces in certain directions (i.e. bishops or queens diagonally). In the check for these pieces, I compared the absolute value of the piece to the pieces I was looking for, because it required less thought than trying to work out the correct sign. That is, if I was looking for a bishop diagonally, I'd check in all diagonal directions whether the absolute value of the piece was 4 (the bishop's number). Stupidly enough, I didn't realise this would also include piece's that belonged to the player, along with the opponent's pieces. So basically, each player's queen kept putting that player in to check.
Wednesday, 9 January 2013
Glitches
Some strange glitches are occurring whilst I'm playing my chess game involving the computer's moves. The computer attempted to take my pawn with its bishop, but his bishop disappeared. Later, it attempted to move a queen, and the queen disappeared. I'm posting this because it will hopefully demonstrate my problem-solving abilities. Examiners love problem-solving abilities.
EDIT:
I fixed the problem. Turns out where I wrote 39 and 89 in two lines should have been 38 and 88. Obviously. Here's a picture, in case you're unsure as to what those numbers look like.
EDIT:
I fixed the problem. Turns out where I wrote 39 and 89 in two lines should have been 38 and 88. Obviously. Here's a picture, in case you're unsure as to what those numbers look like.
Monday, 7 January 2013
It plays!
I've gotten to the point where you can actually play against the computer now. It does, for now, pick its moves randomly, and there is, for now, no way of detecting check or checkmate, but at least it plays.
(Obligatory picture which looks the same as all previous pictures):
Sunday, 6 January 2013
A flowchart
This is a flowchart that I have used to determine what to do when a square on the board is clicked by the user.
DISCLAIMER: This was not posted because I felt I really needed to post something soon because I haven't posted anything for a while. This is definitely actual work.
DISCLAIMER: This was not posted because I felt I really needed to post something soon because I haven't posted anything for a while. This is definitely actual work.
Monday, 12 November 2012
Claude Shannon Paper
I read the paper 'Programming a Computer for Playing Chess' by Claude Shannon (1949). I thought it would be difficult to read, but it was fine, and certainly very useful from a theory point of view. It's remarkable how relevant most of it is today, more than 60 years later.
Download link
Download link
Move Generation
Move generation is sorted, apart from special cases like castling, en passant and not allowing moves in to check. I have to be careful with them, they're rare cases so if I implement them badly, they'll slow the search down with next to no gain. Here are some pictures with green squares illustrated available moves for a certain piece:
Monday, 5 November 2012
New Pieces Icons
I've found some good looking icons to replace my horrible home made icons for the chess pieces.
Look how pretty they are:
Icons are from Clker, which are all public domain images.
Look how pretty they are:
Icons are from Clker, which are all public domain images.
Sunday, 4 November 2012
First Version of Something
I finally got round to making an actual thing:
All it does so far is let the user place pieces and remove them ( all the pieces are included, not just white queens).
It can be quite difficult to make this, because you have to be very forward thinking. You don't want to implement a clumsy mechanism early on because it'll probably make things so much harder later on in the project.
The next thing to do is move generation, which I'll then test thoroughly for as many different configurations as I can be bothered to do. If I can implement it successfully, I may use Perft, which is an algorithm designed to test the move generation system.
After that, I'll make sure the whole thing is optimized as much as reasonably possible, and everything is done probably (as in, no messy short cuts that may cause problems in the future).
All it does so far is let the user place pieces and remove them ( all the pieces are included, not just white queens).
It can be quite difficult to make this, because you have to be very forward thinking. You don't want to implement a clumsy mechanism early on because it'll probably make things so much harder later on in the project.
The next thing to do is move generation, which I'll then test thoroughly for as many different configurations as I can be bothered to do. If I can implement it successfully, I may use Perft, which is an algorithm designed to test the move generation system.
After that, I'll make sure the whole thing is optimized as much as reasonably possible, and everything is done probably (as in, no messy short cuts that may cause problems in the future).
Subscribe to:
Posts (Atom)