17 September 2019

An unfinished chess engine playing against itself

I am looking at the fascinating, hard world of the computer chess programming. This is a resource surely known by all those who share this interest:

I have currently started four projects in four different languages: C, Perl6, GNU AWK (yes!) and Ada (of course). My purpose isn’t to write strong chess engines: it would be a demanding and absorbing aim, and moreover there are many open source chess engines written in several languages (not Perl6 or AWK, though, and just one in Ada, AdaChess); one of the strongest, if not the strongest, is Stockfish. Competing in this serious business would be more than simply hard, and it would be also pointless.

So far the only project that begins to “play” is the one written in Perl6.

Let’s see its first checkmate against itself.

Moves list

These are the moves, so that you can import them in your preferred chess analysis software. Of course you won’t learn anything: the Perl6 engine is able to generate legal moves (except en-passant so far) but not to play seriously.1

1. d4 f5 2. d5 e5 3. Nc3 g6 4. e3 Qg5 5. Nf3 Qh6 6. Nxe5 Qg5 7. Nb5 Be7 8. Nxc7+ Kd8 9. Nxa8 Bd6 10. a4 Bxe5 11. Bd3 Qxg2 12. Qe2 Qxd5 13. Kd2 Qxh1 14. Bb5 Qxh2 15. Qe1 Nf6 16. Kd3 Ne8 17. Qf1 Bd6 18. Kc4 Bf8 19. Kd3 Qd6+ 20. Kc4 Qc6+ 21. Kd3 Qd6+ 22. Kc3 Bg7+ 23. Kc4 Qc6+ 24. Kd3 Qd6+ 25. Ke2 Rf8 26. a5 Qe7 27. Qh3 Qe6 28. Qxh7 Be5 29. Rb1 g5 30. Ra1 d6 31. Rb1 Nf6 32. Qg6 Qd5 33. Qxg5 Qxb5+ 34. Kf3 Qxa5 35. Ke2 Qa6+ 36. Kd1 b5 37. Qg1 Rh8 38. Qg6 Rh4 39. Ke2 b4+ 40. Kd1 Rh1+ 41. Kd2 Ne4#

Analysis

(This analysis was reviewed later using https://www.chess.com/analysis.)

According to ChessX, Pellegrino (this is the current name of the future engine) played the Dutch opening, A80, for the first two moves. This is totally not intentional — it just played two random moves! In fact 2.d5 is an inaccuracy already…

Black plays 2.… e5, but white doesn’t capture because Pellegrino doesn’t know how to do an en-passant capture yet (that is, not all the legal moves are generated yet).

The move 3.♘c3 is another random move, but it looks as if white wanted a) to develop the knight, and b) to protect the pawn in d5 — however it is another inaccuracy.

With 5.♘f3 it seems white wants to attack the black Queen which went outside too soon, and this was the best move possible. But indeed this is another random move! And so it is the retreat 5.… ♛h6. Then the attack on g5 ceases (white knight see an opportunity to eat the pawn in e5) and the black Queen goes back there. Another random move.

Now, 8.♘b5, believe it or not, is another random move which threatens ♘×c7+, which Pellegrino playing as black can’t see: it has no the concept of king safety, and it doesn’t see beyond its one-move short nose! That’s why it plays ♝e7, clearly a blunder because black should have defended its c7 pawn.

This time the “engine” is programmed to do a check, so 8.♘c6+ is indeed intentional (the search for check moves comes before the you-can-eat search). And bye bye rook.

Nnbk2nr/pp1pb2p/6p1/3PNpq1/8/4P3/PPP2PPP/R1BQKB1R b KQ - 0 9

(Diagrams are exported from ChessX which, I have to say, does not a great job in this kind of export. In previous posts I’ve used a Python package which produced a nice looking but “huge”, in term of bytes in the HTML, SVG image.)

Then it seems like Pellegrino in black wants to retaliate on the white knight in e5 with 9.… ♝d6??Pellegrino knows how to check and eat undefended pieces, but it has no idea how to defend itself even from direct threat… So it allows first 10.… ♝×e5, then a random move puts the white bishop in d3, a severe blunder, leaving the pawn g2 unguarded for the black Queen to eat. Which in fact she does.

And then again, white moves the Queen instead of saving the rook… but luckly here Pellegrino has two eating moves, and the random choice is for the less dangerous, 12.… ♛×d5. Chess.com marks this as a missed win, no less! More than just a blunder! Of course it should have taken the rook, and check!

But again, white has no clue of the risks, so it doesn’t save the rook and moves the king instead, without reasons. And the black queen strikes again taking the rook, at last. And again white ignores any threats: the pawn in h2 is attacked by two black pieces.

14.♗b5 …

Several next moves are just random, hence mostly silly and pointless, but not always according to chess.com. Random moves can surprise, even if the players haven’t a clue and so they don’t follow the plan.

The move 16.♔d3 is actually good, and also 16.… ♞e8 is considered good by chess.com! Again, random moves which are good.

And what about 18.♔c4? It is excellent, and 18.… ♝f8 is good, because of ♝g7… But of course black will lose this plan along the way…

But then we have 19.♔d3, which is good, after 18.… ♝f8, a random move which allows the black queen to go in c7 and d6. In fact:

19.… ♛d6+

The white king is exposed and black keeps checking it. The white king does the right move — not the best, which is ♔e2, but yet, decent…

Of course 20.… ♛c6+ is a blunder, but Pellegrino isn’t able to see ♗×c6 because when in check, it first tries to move the king2.

20.… ♛c6+??

And wait for it…

21. ♔d3?? …

So black can keep checking the white king, and so it does with the excellent 21.… ♛d6+. And then also with the bishop: 22.… ♝g7+, another excellent move, even if fortuitous. By the way, Pellegrino should be aware of the threefold repetition rule (last feature added, even less untested than the rest!)

The players do some ball, black blunders again with 23.… ♛c6+, but again white is unable to exploit this!, and it moves the king again, and again black checks with 24.… ♛d6+, already seen…

And so on, until the lucky 27.♕h3, the best move white could play there, which gives white a chance to eat a pawn… As said, Pellegrino isn’t aware of direct attacks, so it won’t intentionally defend h7, and nonetheless 27.… ♛e6 is a good move for chess.com, while 28.♕×h7 is a mistake. That of course black won’t take advantage of.

But the luck doesn’t assist the white for very much longer; it wastes time moving the rook between a1 and b1 while luckly black place a bishop nicely in e5 (good move) and advances a pawn (another just good move instead of the best ♜h8).

30.♖a1 …

Black continues doing moves that could be real (30.… d6, just good) while white move the rook a1-b1 again in b1. What a waste!

Then black attacks the white queen in h7 with 31.… ♞f6 (random lucky move which is indeed a blunder), and — at last — white reacts with 32.♕g6 (random lucky defence which is another missed win, because of 32.♕g6#… checkmate).

Now, let’s think about it. Why did Pellegrino miss this opportunity? The problem here is that the square c7 is attacked by one, the black king, and defended by one, the white knight. For poor silly Pellegrino this is a no-win situation, just an exchange. A square should be good if the number of defending pieces is more than the number of attacking pieces. The king is just another piece like others… Pellegrino can’t see that the black piece (the black queen) is safe because the white king can’t eat it: the king counts as regular and so the square isn’t a “weak” spot. Hence the terrible blunder.

After this lost opportunity for white, 32.… ♛d5 is an excellent move for black, which then allows it to take first the white bishop in b5 (random lucky move, lucky because the white doesn’t defend it), and then the pawn in a5, an excellent move; the very same programmed appetite pushes white to take the pawn in g5, thus losing the bishop for the same black appetite — but this is the best move, while 33.♕×g5 is an inaccuracy.

33.… ♛×b5+

The king flies away and the black Queen takes the pawn in a5, as expected (a free meal) — excellent move!

White random king walk (35.♔e2, which is also the best move!) offers another opportunity for a check by the black Queen (35.… ♛a6+, best move for black this time). The king has to move, and 36.♔d1 is an excellent move!

The black keeps being luckier when Pellegrino goes for a random move, and thus advances the b-file pawn (another excellent move!), white retreats its Queen in the back rank (the best move!); another lucky random move for black comes (rook in the open h-file, the best move), white makes its Queen oscillate between g5-g1-g6 (38.♕g6 is a blunder, though, while moving her into g1 was the best move, as said), and another lucky hit missed win comes for the black: 38.… ♜h4, i.e.; the black rook “dominates” a whole rank and a whole file, but 38.… ♜h1+ was the best and a win, according to a variation far far away — see below. Of course Pellegrino is unable to exploit good chances, but anyway… funny 😁

After playing the suggested moves, you can see the variation is this:

38.… Rh1+ 39. Kd2 Qc6 40. Qg8+ Nxg8 41. c4 bxc4 42. Ke2 Qe4 43. b3 Qd3+ 44. Kf3 Bb7#


Another question arises for Pellegrino. Why didn’t it play 38.… ♜h1+? Weren’t the possible checks the first moves to be considered? Nope. First the eating moves, then the non-eating moves which check, don’t allow the piece to be taken back, and don’t cause a threefold repetition.

Thus, you are still asking yourself, why didn’t Pellegrino play 38.… ♜h1+? Because 0 > 0 is false, therefore h1 isn’t considered a “weak” square. Yes, that’s a bug in this simple algorithm, and it’s also kind of asymmetric. We can say that Pellegrino missed two wins intentionally, because it was programmed to do so!

Changes I will do for the next run: first try a check, if safe, then try eating moves, and do not consider the king an attacking piece if there’s at least a defending piece… And if there aren’t attacking pieces nor defending pieces for a square, consider it safe!

Black wins in 44 moves. But Pellegrino is wiser and with a little bit of help from the white itself, who blunders with 39.♔e2, black will win in 41!

Now In fact the chessmate is near. First black does a discovered check with the best possible move ever:

39.… b4+

Now white’s fate can’t be changed, and anyway it keeps doing just a good move instead of the best possible move, so…

It could go like this:

40. Kf3 Bb7+ 41. e4 Bxe4+ 42. Ke3 Bf4+ 43. Kd4 Nc6#

or maybe longer…

40. Kf3 Bb7+ 41. e4 Bxe4+ 42. Ke3 Nd5+ 43. Kd2 Bf4+
44. Ke1 Rh1+ 45. Qg1 Rxg1#

Pellegrino, however, plays just 40.♔d1 (a good move, anyway), and checkmate is there, waiting. For instance:

40. Kd1 Qf1+ 41. Kd2 Ne4#

But Pellegrino plays 40.… ♜h1+. Which isn’t bad is just good: white king can only go in d2, and then:

41.… ♞e4#

White can belate the moment if it sacrifices the Queen in g1, but anyway there’s no hope.

40. Kd1 Rh1+ 41. Qg1 Rxg1+ 42. Kd2 Ne4#

The move ♔d1 isn’t the best to keep the white king alive a little bit more. But from that position only the bad luck of a random move could save the white.

Final note

Even if mostly Pellegrino plays random moves, or moves without “thinking” of the consequences, few times the good luck makes one think that there’s a little bit more inside it than the very simple algorithm described in the note!3 It sometimes played excellent moves, or the best moves, or just good moves… but maybe the evaluation is a little bit skewed by the heap of blunders, missed wins, inaccuracies…


  1. The “algorithm” is this: it generates (almost) all the legal moves, then try first to eat then to check, provided that it can’t be eaten back and there’s no a threefold repetition; if it can’t neither check nor eat safely, then a random move is played. Notice that the concept “it can’t be eaten back” consider also if a piece is defended, but disregards relative or absolute piece values. Basically the only thing that matters is the count of how many pieces attack and defend a square. That’s why 20.… ♛c6+ can be played: attacked by one, defended by three!↩︎

  2. And then, anyway, it considers the square defended (Pellegrino knowns nothing about piece values): for the same reason black considered the check move even if clearly the queen can be eaten by the bishop.↩︎

  3. It’s also because it’s playing against itself and it is unable to exploit its own flaws!↩︎

No comments:

Post a Comment

Be polite and possibly on topic.