How I programmed a solver for the knight and bishop checkmate
Me, playing chess with my son who usually beats me
THE KNIGHT AND BISHOP CHECKMATE
In 1999, I programmed a solver for the knight and bishop checkmate. I had not seen that done before. I talked about that in my last post. A few people asked me to talk a little about my algorithm.
In those days, it really caught my attention that some strong chess programs didn't solve the problem and took too much time to analyze a knight and bishop endgame. I thought: "why?, how difficult could it be to include all the answers of known endings inside the program, so it doesn't lose time thinking. Getting all those answers must be easy if we're talking about only four pieces over the board".
Easy?... Really?...
Yes, of course.
I was sure about that.
First, we must find out how many positions we're talking about.
That's easy: 64 squares and 4 pieces:
644 = 64 x 64 x 64 x 64 = 16777216 (beautiful number for programmers).
That's a start.
We have thus clearly defined the limits of this universe. Now we know how many different ways a white king, a white knight, a white bishop and a black king can be arranged over the chessboard. The value 16777216 includes a number of invalid positions (i.e. two or more pieces in the same square) but we can manage that later.
BASIC STRUCTURE TO LOOK FOR THE ANSWERS
See the image:
Those 24 bits are going to be used to orderly go through all the positions. Any four pieces chess position can be represented using a Long Integer. We need only three bytes but in my program I used a four bytes integer (Long Integer). The variable Position is a Long Integer.
See this simple but powerful code:
For Position = 0 to 16777215
Mark_Position_As(32) 'Not yet solved
Next
Do
For Position = 0 to 16777215
if Not_Valid(Position) then Mark_Position_As(0): break
if Winning_Possible(Position) then Mark_Position_As(Move_Number): break
if Mate_in_Zero(Position) then Mark_Position_As(30): break
if Draw(Position) then Mark_Position_As(31): break
Next
Repeat Until No_More_Changes_In_Solutions
The above code is the basic structure that solves the problem, it finds all the solutions for the knight and bishop checkmate. All the solutions should be saved in a file with a size of 16777216 bytes (one byte per answer) . Out of this code, everything should be easy to infere. Let me explain a little the works done by the functions Not_Valid, Winning_Possible, Mate_in_Zero and Draw.
NOT_VALID
A position is not valid when:
- Two pieces are in the same square.
- The kings are in adjacent squares.
- Black is in check but not checkmated (Remember: It's always white's turn to move).
WINNING POSSIBLE
Here we check if one of the available moves put the black king in checkmate or force it to another position already marked as Winning_Possible. Every move available must be given a value. The values of Move_Number range from 1 to 29, being 29 the maximum possible number of moves with a knight (8 moves), a bishop (13 moves) and a king (8 moves).
MATE_IN_ZERO
In the position the black king is already checkmated.
DRAW
The position is a draw when:
- The black king is stalemated.
- All available moves leads to stalemate or losing a piece.
(Now I know there are only 39 positions where the stalemate or the loss of a piece are unavoidable).
This is pretty short and pretty simple (and pretty powerful).
If you see closely, you may realize that you can use it to solve any four pieces ending.
May be I omitted something. I tried to keep it short. Let the questions come.
Greetings from Venezuela.
Thanks for posting, this is great and very understandable. Of course the devil would be in the details of these functions/classes: Not_Valid(), Winning_Possible(), Mate_in_Zero(), Draw(), Mark_Position_As() how much memory how much time.
A very interesting and similar concept that I use in my chess program. I use nested loops and one single dimension 1000 elements array, that I break up into ten board. Sixty four elements for the board and 36 elements for variables. This allows me to just pass the entire array and only use one global counter variable.
If you didn’t keep it short initially you might find yourself talking in circles :). Now what I didn’t see was “Best_Possible()” on the way to checkmate,
Again This Is Really Great:
LOL @Amaponian, I hope you didn’t take the reply as offensive.
Understood!
Understood!
Again it was a great post.
Never.
Why should I?
LOL
Congratulations!
✅ Good job. Your post has been appreciated and has received support from CHESS BROTHERS ♔ 💪
♟ We invite you to use our hashtag #chessbrothers and learn more about us.
♟♟ You can also reach us on our Discord server and promote your posts there.
♟♟♟ Consider joining our curation trail so we work as a team and you get rewards automatically.
♞♟ Check out our @chessbrotherspro account to learn about the curation process carried out daily by our team.
Kindly
The CHESS BROTHERS team
Hey @amaponian! What an enlightening post but I don't play chess much and know nothing about programming...😄...but your post makes sense. I see more of mathematical strategies in this.
Well done! So did the solver for the knight and bishop checkmate programming work? Hehe. 🙂
I'm sorry, I delayed this answer and then forgot about it.
I'm glad to see you won this week's prompt in theinkwell.
I didn't write there this week,
I've been a bit busy lately and I'll probably be busier from now on.
Keep writing, you're great at it, but you already know that.
Greetings from Venezuela.
P.S. Yes! the solver worked, like a charm, 23 years ago.
Thanks a lot, @amaponian. I appreciate your comment and it can come at anytime because I understand life can get busy sometimes.
I hope you return back to writing, especially in the Inkwell soon.
Great! 😄