Announcement: The Bozochess Project

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Move generation routine hierarchy

Post by sje »

Bozo's move generation routine hierarchy starts with the PosGenerate routine that generates all legal moves in no particular order with no markings and no scores. From that, there are a series of meta-generation routines:

Code: Select all

  procedure PosMetaGenNotated(var pos: postype; var gms: gmstype);
  begin
    PosGenerate(pos, gms);
    PosMarkNotation(pos, gms)
  end; { PosMetaGenNotated }

  procedure PosMetaGenCanonical(var pos: postype; var gms: gmstype);
  begin
    PosMetaGenNotated(pos, gms);
    GmsSortBySan(gms)
  end; { PosMetaGenCanonical }

  procedure PosMetaGenDeluxe(var pos: postype; var gms: gmstype);
  begin
    PosMetaGenCanonical(pos, gms);
    PosMarkDraws(pos, gms)
  end; { PosMetaGenDeluxe }

  procedure PosMetaGenSuperDeluxe(var pos: postype; var gms: gmstype);
  begin
    PosMetaGenDeluxe(pos, gms);
    PosMarkLoseIn1(pos, gms);
    PosMarkMateIn2(pos, gms)
  end; { PosMetaGenSuperDeluxe }

  procedure PosMetaGenHyperDeluxe(var pos: postype; var gms: gmstype);
  begin
    PosMetaGenSuperDeluxe(pos, gms);
    PosMarkLoseIn2(pos, gms);
    PosMarkMateIn3(pos, gms)
  end; { PosMetaGenHyperDeluxe }
The last routine PosMetaGenHyperDeluxe is called only for a full search and it ensures that the program will never miss a mate in three.
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Six mate/lose predicate functions

Post by sje »

Used mostly only near the root of a search tree, here are six mate/lose predicate functions:

Code: Select all

  function PosIsMateIn1(var pos: postype): Boolean;
    var
      myresult: Boolean;
      gms: gmstype;
      index: gctype;
  begin
    with pos, gms do
      begin
        myresult := False;
        PosGenOnlyChecks(pos, gms);
        index := 0;
        while &#40;not myresult&#41; and &#40;index < movecount&#41; do
          begin
            PosExecute&#40;pos, moves&#91;index&#93;);
            if PosIsCheckmate&#40;pos&#41; then
              myresult &#58;= True;
            PosRetract&#40;pos&#41;;
            Inc&#40;index&#41;
          end
      end;
    PosIsMateIn1 &#58;= myresult
  end; &#123; PosIsMateIn1 &#125;

  function PosIsLoseIn1&#40;var pos&#58; postype&#41;&#58; Boolean;
    var
      myresult&#58; Boolean;
      gms&#58; gmstype;
      index&#58; gctype;
  begin
    with pos, gms do
      begin
        PosGenerate&#40;pos, gms&#41;;
        if movecount = 0 then
          myresult &#58;= inch
        else
          begin
            myresult &#58;= True;
            index &#58;= 0;
            while myresult and &#40;index < movecount&#41; do
              begin
                PosExecute&#40;pos, moves&#91;index&#93;);
                if not PosIsMateIn1&#40;pos&#41; then
                  myresult &#58;= False;
                PosRetract&#40;pos&#41;;
                Inc&#40;index&#41;
              end
          end
      end;
    PosIsLoseIn1 &#58;= myresult
  end; &#123; PosIsLoseIn1 &#125;

  function PosIsMateIn2&#40;var pos&#58; postype&#41;&#58; Boolean;
    var
      myresult&#58; Boolean;
      gms&#58; gmstype;
      index&#58; gctype;
  begin
    with pos, gms do
      begin
        myresult &#58;= False;
        index &#58;= 0;
        PosGenerate&#40;pos, gms&#41;;
        PosMarkChecks&#40;pos, gms&#41;;
        GmsMoveChecksToFront&#40;gms&#41;;
        while &#40;not myresult&#41; and &#40;index < movecount&#41; do
          begin
            PosExecute&#40;pos, moves&#91;index&#93;);
            if PosIsLoseIn1&#40;pos&#41; then
              myresult &#58;= True;
            PosRetract&#40;pos&#41;;
            Inc&#40;index&#41;
          end
      end;
    PosIsMateIn2 &#58;= myresult
  end; &#123; PosIsMateIn2 &#125;

  function PosIsLoseIn2&#40;var pos&#58; postype&#41;&#58; Boolean;
    var
      myresult&#58; Boolean;
      gms&#58; gmstype;
      index&#58; gctype;
  begin
    with pos, gms do
      begin
        PosGenerate&#40;pos, gms&#41;;
        if movecount = 0 then
          myresult &#58;= inch
        else
          begin
            myresult &#58;= True;
            index &#58;= 0;
            while myresult and &#40;index < movecount&#41; do
              begin
                PosExecute&#40;pos, moves&#91;index&#93;);
                if not PosIsMateIn2&#40;pos&#41; then
                  myresult &#58;= False;
                PosRetract&#40;pos&#41;;
                Inc&#40;index&#41;
              end
          end
      end;
    PosIsLoseIn2 &#58;= myresult
  end; &#123; PosIsLoseIn2 &#125;

  function PosIsMateIn3&#40;var pos&#58; postype&#41;&#58; Boolean;
    var
      myresult&#58; Boolean;
      gms&#58; gmstype;
      index&#58; gctype;
  begin
    with pos, gms do
      begin
        myresult &#58;= False;
        index &#58;= 0;
        PosGenerate&#40;pos, gms&#41;;
        PosMarkChecks&#40;pos, gms&#41;;
        GmsMoveChecksToFront&#40;gms&#41;;
        while &#40;not myresult&#41; and &#40;index < movecount&#41; do
          begin
            PosExecute&#40;pos, moves&#91;index&#93;);
            if PosIsLoseIn2&#40;pos&#41; then
              myresult &#58;= True;
            PosRetract&#40;pos&#41;;
            Inc&#40;index&#41;
          end
      end;
    PosIsMateIn3 &#58;= myresult
  end; &#123; PosIsMateIn3 &#125;
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

EPD output

Post by sje »

EPD output is now working. Here are some samples from the checkmate search:

Code: Select all

&#91;&#93; sfen 1B1bk3/7R/1r5p/1Pp1p3/2NP1N2/1RP2Pp1/2QK4/8 w - - 2 52 
&#91;&#93; mate 4
Found mate in 4
PV&#58; 52 Rh8+ Ke7 53 Qh7+ Kf6 54 Qg6+ Ke7 55 Qg7#
Count&#58; 5361   Time&#58; 000.00&#58;00&#58;00.092   Frequency&#58; 58271
1B1bk3/7R/1r5p/1Pp1p3/2NP1N2/1RP2Pp1/2QK4/8 w - - 2 52 nc 5361; etime 000.00&#58;00&#58;00.092; ps MateIn4; pv Rh8+ Ke7 Qh7+ Kf6 Qg6+ Ke7 Qg7#; dm 4;
&#91;&#93; sfen 1B6/2r5/8/p1bQ4/2p1P1Pp/P2P3P/1P1k2BK/R2b1R2 w - - 5 49 
&#91;&#93; mate 4
Found mate in 4
PV&#58; 49 Raxd1+ Ke2 50 Bf3+ Ke3 51 Rde1+ Kd2 52 Re2#
Count&#58; 2570   Time&#58; 000.00&#58;00&#58;00.036   Frequency&#58; 71388
1B6/2r5/8/p1bQ4/2p1P1Pp/P2P3P/1P1k2BK/R2b1R2 w - - 5 49 nc 2570; etime 000.00&#58;00&#58;00.036; ps MateIn4; pv Raxd1+ Ke2 Bf3+ Ke3 Rde1+ Kd2 Re2#; dm 4;
&#91;&#93; sfen 1B6/6k1/8/4pB2/7Q/3r4/2K5/3Q2q1 b - - 3 99 
&#91;&#93; mate 4
Found mate in 4
PV&#58; 99... Qxd1+ 100 Kb2 Qb3+ 101 Ka1 Rd1+ 102 Bb1 Rxb1#
Count&#58; 169   Time&#58; 000.00&#58;00&#58;00.007   Frequency&#58; 24142
1B6/6k1/8/4pB2/7Q/3r4/2K5/3Q2q1 b - - 3 99 nc 169; etime 000.00&#58;00&#58;00.007; ps MateIn4; pv Qxd1+ Kb2 Qb3+ Ka1 Rd1+ Bb1 Rxb1#; dm 4;
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Non-recursion

Post by sje »

As mentioned in another thread, I've converted Bozo's checkmate search from a recursive scheme to an iterative, state driven scheme. I'm using the new checkmate search as a model for a general move search that is now being coded. I hope to have this ready soon.

The parsers for EPD and for PGN are also under development.

How big is the Pascal source?

Code: Select all

gail&#58;bozochess sje$ wc bozochess.pas
   11804   34794  343865 bozochess.pas
gail&#58;bozochess sje$ grep \; *.pas | wc -l 
    4978
gail&#58;bozochess sje$ grep procedure *.pas | wc -l
     334
gail&#58;bozochess sje$ grep function *.pas | wc -l 
     185
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

FEN file reader + mate finder

Post by sje »

I connected the FEN file reader code to the program's mate finder and got the ffmate command which reads a file of FEN records and runs the mate finder to fixed depth on each one.

The main goals are verification and performance testing of the mate finder code. I have a set of four FEN files each with 100,000 records for mate in 1 up to 4 moves. The program solves a mate in 3 with a mean of 5 milliseconds, and a mate in 4 is solved with a mean of 43 milliseconds. The mate in 1 and mate in 2 problems are solved too quickly under millisecond resolution to get accurate timing results.
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Bozo's first game

Post by sje »

Bozo's first game was played with a full width depth limit of only one ply with a very simple evaluation function and a simple quiescence search. The code is non-recursive, like the program's mate finder. The astonishing fact is that the search code, on its very first run, did not hang.

Code: Select all

&#91;Event "Unknown event"&#93;
&#91;Site "Unknown site"&#93;
&#91;Date "2011.11.27"&#93;
&#91;Round "-"&#93;
&#91;White "Unknown player"&#93;
&#91;Black "Unknown player"&#93;
&#91;Result "0-1"&#93;

1 e3 e6 2 Qh5 g5 3 Nc3 Nc6 4 Nf3 h6 5 Bd3 Nf6 6 Qh3 g4 7 Qg3 gxf3 8 gxf3 e5 9 Rb1 d5 10 O-O Rg8 11
Bg6 fxg6 12 a3 g5 13 b4 d4 14 Nb5 Be6 15 Rb2 Bc4 16 exd4 Bxb5 17 dxe5 Bxf1 18 Kxf1 Nh5 19 Qg4 Nf4
20 Qf5 Qd5 21 Qf6 Qxf3 22 d3 Qd1# 0-1
Also, the second game, played with a depth limit of two ply:

Code: Select all

&#91;Event "Unknown event"&#93;
&#91;Site "Unknown site"&#93;
&#91;Date "2011.11.27"&#93;
&#91;Round "-"&#93;
&#91;White "Unknown player"&#93;
&#91;Black "Unknown player"&#93;
&#91;Result "0-1"&#93;

1 e3 d5 2 Qh5 Qd6 3 Nc3 Nf6 4 Bb5+ c6 5 Qg5 h6 6 Qf4 cxb5 7 Nxb5 Qxf4 8 exf4 Na6 9 Nf3 Bg4 10 Ne5
Bc8 11 d3 Ng4 12 a4 Nxe5 13 fxe5 g5 14 Be3 b6 15 Kd2 Bg7 16 f4 f6 17 fxg5 hxg5 18 a5 d4 19 Nxd4
fxe5 20 Nc6 Kd7 21 Nxa7 Rxa7 22 axb6 Ra8 23 Bxg5 Bb7 24 Rag1 Nc5 25 b4 Ne6 26 Be3 Nf4 27 Bxf4 exf4
28 h4 Bd4 29 Re1 Be3+ 30 Kc3 Bxg2 31 Rh2 Ra3+ 32 Kb2 Ra4 33 Rxg2 Rxb4+ 34 Ka3 Rxb6 35 Rg5 Ra8+ 36
Ra5 Rxa5# 0-1
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Games three and four

Post by sje »

Three ply search limit:

Code: Select all

&#91;Event "Unknown event"&#93;
&#91;Site "Unknown site"&#93;
&#91;Date "2011.11.27"&#93;
&#91;Round "-"&#93;
&#91;White "Unknown player"&#93;
&#91;Black "Unknown player"&#93;
&#91;Result "0-1"&#93;

1 e3 d5 2 Qh5 Nc6 3 Nc3 Nf6 4 Qg5 h6 5 Qg3 e5 6 Bd3 e4 7 Nb5 Kd7 8 Be2 a6 9 Nd4 Nxd4 10 exd4 Qe8 11
Kd1 Kd8 12 c3 g5 13 b4 Bd6 14 f4 Bxf4 15 Qf2 Ng4 16 Bxg4 Bxg4+ 17 Ke1 f5 18 Nh3 Bd6 19 Qf1 a5 20 b5
a4 21 Nf2 Bh5 22 h4 gxh4 23 Rxh4 Rg8 24 Bb2 a3 25 Bc1 Qf7 26 d3 exd3 27 Kd2 Be2 28 Qe1 Bg3 29 Rh3
Bf4+ 30 Re3 Qe8 31 Nd1 Bxe3+ 32 Nxe3 Qe4 33 Qh1 h5 34 Qh2 h4 35 Qe5 Qxe5 36 dxe5 Ra4 37 Nxd5 Rxg2
38 Ne3 Rg5 39 Ke1 f4 40 Nd5 Bf3 41 Nxf4 d2+ 42 Bxd2 Rg1+ 43 Kf2 Rxa1 44 Kxf3 Rxa2 45 Ne6+ Ke7 46
Nc5 Rc4 47 Bg5+ Kf7 48 Nxb7 Rxc3+ 49 Be3 Ke6 50 Ke4 Rc4+ 51 Bd4 Rb2 52 Nc5+ Kf7 53 Kd3 Rbc2 54 Ne4
a2 55 Ba1 Rc1 56 Ng5+ Kg6 57 Ne6 Rxa1 58 Nf8+ Kf5 59 b6 cxb6 60 Kxc4 Rc1+ 61 Kb3 a1=Q 62 Kb4 Qb2+
63 Ka4 Ra1# 0-1
Four ply search limit:

Code: Select all

&#91;Event "Unknown event"&#93;
&#91;Site "Unknown site"&#93;
&#91;Date "2011.11.27"&#93;
&#91;Round "-"&#93;
&#91;White "Unknown player"&#93;
&#91;Black "Unknown player"&#93;
&#91;Result "1-0"&#93;

1 e3 d5 2 Qh5 Nc6 3 Nc3 e5 4 Bb5 g5 5 Nf3 a6 6 Nxe5 Qf6 7 Ng4 Qf5 8 Be2 Nb4 9 Bd1 Bg7 10 d4 Ne7 11
Kd2 Qg6 12 Ne5 Qxh5 13 Bxh5 Ng6 14 a3 Nxe5 15 dxe5 Nc6 16 f4 gxf4 17 exf4 Be6 18 Na4 d4 19 Bf3 Bf8
20 b4 Bh6 21 Kd3 Bf5+ 22 Be4 Bxe4+ 23 Kxe4 Rg8 24 g3 O-O-O 25 Nc5 Kb8 26 Bb2 Rg4 27 Rad1 Bg7 28
Bxd4 Nxd4 29 Rxd4 f5+ 30 Kd3 Rxd4+ 31 Kxd4 Rg6 32 Kd3 b5 33 Ra1 Rh6 34 h4 Rg6 35 Rg1 Rh6 36 Ra1 Rg6
37 Rg1 Rh6 38 c3 Kc8 39 Ra1 Rg6 40 Rg1 Rh6 41 Kc2 Bf8 42 Nb3 Rg6 43 Nd4 c6 44 Nxf5 c5 45 Rd1 cxb4
46 axb4 h5 47 Kb2 Rc6 48 Rd3 Kc7 49 Kb3 a5 50 Rd1 axb4 51 cxb4 Rg6 52 Rd5 Kb6 53 Rd7 Rc6 54 Rd8 Bh6
55 Rh8 Bxf4 56 gxf4 Rc4 57 Ne3 Rd4 58 Kc3 Rd7 59 Rxh5 Rg7 60 Kb2 Kc7 61 Rg5 Rd7 62 Kc2 Kb6 63 Rg8
Rc7+ 64 Kb2 Rd7 65 Kc2 Rc7+ 66 Kb2 Rd7 67 e6 Rd3 68 Nc2 Rd2 69 e7 Re2 70 e8=Q Rxe8 71 Rxe8 Kc7 72
Na3 Kc6 73 f5 Kd6 74 f6 Kd5 75 f7 Kd6 76 Nxb5+ Kd5 77 Nc3+ Kc6 78 Re7 Kb6 79 f8=Q Ka6 80 Qf6# 1-0
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Six ply search

Post by sje »

Here's a game Bozo played against itself using a six ply search:

Code: Select all

&#91;Event "Unknown event"&#93;
&#91;Site "Unknown site"&#93;
&#91;Date "2011.11.28"&#93;
&#91;Round "-"&#93;
&#91;White "Unknown player"&#93;
&#91;Black "Unknown player"&#93;
&#91;Result "1-0"&#93;

1 Nc3 e6 2 d4 Nc6 3 d5 exd5 4 Qxd5 Nb4 5 Qd1 Qf6 6 a3 Na6 7 Nf3 h6 8 Qd5 c6 9 Qd2 Nc5 10 Rb1 d5 11
b4 Ne4 12 Nxe4 dxe4 13 Bb2 Qf5 14 Rd1 Be7 15 g4 Qg6 16 Ne5 Qg5 17 Bg2 Nf6 18 h3 Qxd2+ 19 Rxd2 Be6
20 f4 a5 21 c3 O-O 22 Kf2 Rfd8 23 Rxd8+ Bxd8 24 e3 axb4 25 cxb4 Bd5 26 Ra1 Bb3 27 Bd4 Be7 28 g5
hxg5 29 fxg5 Nd5 30 Bxe4 Bxg5 31 Kf3 Bf6 32 Bb2 Nb6 33 Nd3 Bxb2 34 Nxb2 Be6 35 h4 Nd5 36 Bxd5 cxd5
37 Nd3 Bf5 38 Nf4 Be4+ 39 Kg3 Kh7 40 a4 Kh6 41 a5 f6 42 Rd1 Rd8 43 Nd3 Bf5 44 Nc5 Bc8 45 Rh1 Kh5 46
Rd1 Kg6 47 Nd3 Kf5 48 Nc5 Ke5 49 Rc1 Rh8 50 Rf1 Rh7 51 Rc1 Bf5 52 e4 dxe4 53 Nxb7 g6 54 Rc5+ Kd4 55
Nd6 Be6 56 Rc1 Rh8 57 Nb5+ Ke3 58 Rc3+ Ke2 59 Nd4+ Kd2 60 Rc6 Bd5 61 Rd6 Rh5 62 Nb5 e3 63 Nd4 e2 64
Nxe2 Kxe2 65 Rxf6 g5 66 hxg5 Rxg5+ 67 Kf4 Rh5 68 Rd6 Bc4 69 a6 Rh7 70 Rc6 Kd3 71 Rd6+ Kc2 72 Rb6
Kb3 73 Rb7 Rh4+ 74 Kg3 Rh8 75 a7 Ra8 76 b5 Bd3 77 b6 Rg8+ 78 Kf4 Rc8 79 Rb8 Rc4+ 80 Ke3 Be4 81 b7
Ra4 82 a8=Q Rb4 83 Qa1 Bc6 84 Kd2 Bxb7 85 Rxb7 Rxb7 86 Qb1+ Kc4 87 Qxb7 Kd4 88 Qb5 Ke4 89 Kc2 Ke3
90 Kb2 Kd2 91 Qe5 Kd3 92 Kc1 Kc4 93 Kd2 Kb4 94 Qd5 Ka3 95 Kc3 Ka4 96 Qe5 Ka3 97 Qa5# 1-0
Not too bad considering that the evaluation function is only two lines long (material plus attacked square count).
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Mate in four speed

Post by sje »

I recently ran Bozo on my 100,000 position matein4.fen file. The mean time per position, including all overhead, was 37.3 milliseconds. The position requiring the most search nodes (578,950) was:
[d]1rb5/2pk3p/1p3Qpn/pP1pp1N1/3B4/1P1B4/3bK1PP/2R3NR w - - 8 42[/d]
The solution for the above is: 42 Ne6 Bxc1 43 Ng7 exd4 44 Qe6+ Kd8 45 Qe8#
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

The current command set

Post by sje »

The current command set now includes option manipulation. An option is a boolean value with a handy four character name mich is used to contral program operation.

Not all commands are implemented at this time.

Most of the current effort is on move ordering issues.

Code: Select all

&#91;&#93; help
Enter a command, or a sequence of one or more SAN chess moves 

  Commands&#58;
    bench      Run the benchmark
    d          Display everything
    dao        Display active options
    db         Display board &#40;ANSI color&#41;
    dbbdb      Display bitboard database
    dbmono     Display board &#40;monochrome&#41;
    dfen       Display FEN
    dm         Display moves
    dp         Display position
    dpgn       Display PGN
    dpi        Display program identification
    echo       Echo parameters
    efnormal   Normalize from an EPD <input-file> to an EPD <output-file>
    exit       Exit program
    ffmate     Scan FEN <input-file> data, find mate in <number> full moves
    ffnormal   Normalize from a FEN <input-file> to a FEN <output-file>
    ffperft    Summing over a FEN <input-file> data, run perft to <depth>
    g          Search for a move and then play it
    gg         Play both sides until the end of the game
    help       Show help
    loadfen    Load FEN from an <input-file>
    loadpgn    Load PGN from an <input-file>
    mate       Search for a checkmate in <number> full moves
    new        New game
    noop       No operation
    optreset   Reset <option> &#91;<option>&#93;*
    optset     Set <option> &#91;<option>&#93;*
    perftbulk  Run perft to <depth> with bulk counting
    perftfull  Run perft to <depth> with each node visited
    perfttran  Run perft to <depth> with transposition help
    pfnormal   Normalize from a PGN <input-file> to a PGN <output-file>
    rg         Generate and display a single random game
    rgdump     Dump to a PGN <output-file> <number> random games
    rgstat     Generate a report for <number> random game&#40;s&#41;
    rm         Retract move
    rmp        Retract move pair
    s          Search for a move but do not play it
    savefen    Save FEN to an <output-file>
    savepgn    Save PGN to an <output-file>
    selftest   Run the self test
    sfen       Set FEN <mpd> <good> <cavs> <epsq> <hmvc> <fmvn>
    stag       Set PGN <tagname> to <tagvalue>
    test       Run developer test

  Options&#58;
    adcc       Auto display&#58; chess clock
    adcp       Auto display&#58; chess position
    trcv       Trace&#58; current variation
    trea       Trace&#58; EPD analysis
    trfd       Trace&#58; First time node at depth
    trit       Trace&#58; iteration start/finish
    trpv       Trace&#58; predicted variation
    trts       Trace&#58; timing statistics