How I programmed a solver for the knight and bishop checkmate

avatar
(Edited)

playing chess with my son (1).jpg
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:
position.jpg

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:

  1. Two pieces are in the same square.
  2. The kings are in adjacent squares.
  3. 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:

  1. The black king is stalemated.
  2. 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.



Text credits and images: Amaponian Visitor (@amaponian)


Introducemyself

Mis Tonterías



0
0
0.000
8 comments
avatar

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:

  1. Was there not a need to evaluate the strength of each move? Maybe not since this is brute force but how is the move sequence identified?
0
0
0.000
avatar
(Edited)

"the devil would be in the details"
I dont believe that. But it depends on how you see it.
In 1999 I had to manage things with reduced reosurces
that's why I tried to keep everything small.

"I use nested loops"
The ifs here may be should be nested.

"that I break up into ten board"
I didn't use a single board, but I probably could do that because of the very few pieces.

"Now what I didn’t see was “Best_Possible()” on the way to checkmate"
May be not easy to see it here. Let me try to explain:
Not move sequence. We have positions.
For every position we only analyse one move ahead.
If we don't find a mate or a draw, we keep going.
The next revision (see the word REPEAT?)
would get more positions solved.

In the first revision
all Not_Valid positions will be found.
all Mate_In_Zero positions will be found.
all Draw positions will also be found.

In the second revision
Some Mate_in_One will be found

In the third revision
Some Mate_in_One may be found
Some Mate_in_two will be found

In the fourth revision
Some Mate_in_One may be found
Some Mate_in_two may be found
Some Mate_in_three will be found

And so on...

Not sequence of moves,
not going deep to the center of the earth.
Just one move ahead per analysis (easy).
The BestMove is always the number of the first move that leads to mate or to another position cathegorized as Winning_Position (values 1 to 29). I'm almost sure that move is the shortest way to a mate. I think the way this is built assures that. It looks so when you see the solver working.

0
0
0.000
avatar

LOL @Amaponian, I hope you didn’t take the reply as offensive.

p1.pngUnderstood!

p2.png
Understood!

Again it was a great post.

0
0
0.000
avatar
(Edited)

I hope you didn’t take the reply as offensive.

Never.
Why should I?
LOL

0
0
0.000
avatar

Congratulations!


You have obtained a vote from CHESS BROTHERS PROJECT

✅ 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

0
0
0.000
avatar

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. 🙂

0
0
0.000
avatar

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.

0
0
0.000
avatar

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.

Yes! the solver worked, like a charm, 23 years ago.

Great! 😄

0
0
0.000