CookieCat's pawn structure code

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

CookieCat's pawn structure code

Post by sje »

CookieCat currently recognizes seven pawn structure attributes. A sample:
[d]2qrr1n1/3b1kp1/2pBpn1p/1p2PP2/p2P4/1BP5/P3Q1PP/4RRK1 w - - 0 1[/d]

Code: Select all

[] sfen 2qrr1n1/3b1kp1/2pBpn1p/1p2PP2/p2P4/1BP5/P3Q1PP/4RRK1 w - - 0 1
[] dps 
Backward  (white): [c3]
Backward  (black): [c6 e6 g7]
Connected (white): [g2 h2 c3 d4 e5 f5]
Connected (black): [a4 b5 c6 h6 g7]
Isolated  (white): [a2]
Isolated  (black): [e6]
Location  (white): [a2 g2 h2 c3 d4 e5 f5]
Location  (black): [a4 b5 c6 e6 h6 g7]
Majority  (white): [g2 d4 e5 f5]
Majority  (black): [a4 b5]
Multiple  (white): []
Multiple  (black): []
Passed    (white): []
Passed    (black): []
At present, only the location attribute is scored. Its values come from [color, sq] table look-ups.

Attribute recognition:

Code: Select all

    { Bitboard }

    bbtype =
      record
        case Boolean of
          False: (wvec: array [bbwtype] of bbwspantype); { Array of bitboard words }
          True:  (bv64: ui64type)                        { Unsigned 64 bit value }
      end;

    { Bitboard color indexed vector }

    bbcivtype = array [colorrtype] of bbtype;

    { Pawn structure }

    pawnstructtype =
      record
        backward:  bbcivtype; { Backward pawns by color }
        connected: bbcivtype; { Connected pawns by color }
        isolated:  bbcivtype; { Isolated pawns by color }
        location:  bbcivtype; { Locus of pawns by color }
        majority:  bbcivtype; { Three file majority pawns by color }
        multiple:  bbcivtype; { Doubled (and worse) multiple pawns by color }
        passed:    bbcivtype  { Passed pawns by color }
      end;

  procedure PawnStructReset(var pawnstruct: pawnstructtype);
    var
      color: colorrtype;
  begin
    with pawnstruct do
      for color := colorrmin to colorrmax do
        begin
          BbReset(backward[color]);
          BbReset(connected[color]);
          BbReset(isolated[color]);
          BbReset(location[color]);
          BbReset(majority[color]);
          BbReset(multiple[color]);
          BbReset(passed[color])
        end
  end; { PawnStructReset }

  procedure PawnStructLoadFromPos(var pawnstruct: pawnstructtype; var pos: postype);
    var
      color: colorrtype;
      c0bb, c1bb: bbtype;
      m0bb, m1bb: bbtype;
      bb: bbtype;
      sq: sqxtype;
      advdir: dirtype;
      advsq: sqxtype;
      countbb: bbtype;
  begin
    with pawnstruct, pos, bbdb do
      begin
        PawnStructReset(pawnstruct);
        for color := colorrmin to colorrmax do
          begin

            { Setup }

            c0bb := locbm[synthpawn[color]];
            c1bb := locbm[synthpawn[othercolor[color]]];
            advdir := pawnadvdir[color];

            { Scan }

            bb := c0bb;
            repeat
              sq := BbNextSq(bb);
              if sq <> sqnil then
                begin

                  &#123; Backward &#125;
                  
                  if BbNI2&#40;c0bb, guardedbbvec&#91;color, sq&#93;) then
                    begin
                      advsq &#58;= advance&#91;sq, advdir&#93;;
                      if advsq <> sqnil then
                        if not BbNI2&#40;c1bb, pawnatkbbvec&#91;color, advsq&#93;) then
                          BbSetSq&#40;backward&#91;color&#93;, sq&#41;
                    end;

                  &#123; Connected &#125;

                  if not BbNI2&#40;c0bb, connectbbvec&#91;sq&#93;) then
                    BbSetSq&#40;connected&#91;color&#93;, sq&#41;;

                  &#123; Isolated &#125;

                  if BbNI2&#40;c0bb, adjfilebbvec&#91;sq&#93;) then
                    BbSetSq&#40;isolated&#91;color&#93;, sq&#41;;

                  &#123; Location &#125;

                  location&#91;color&#93; &#58;= c0bb;

                  &#123; Majority &#125;

                  BbAnd2&#40;m0bb, c0bb, majfilebbvec&#91;sq&#93;);
                  BbAnd2&#40;m1bb, c1bb, majfilebbvec&#91;sq&#93;);
                  if BbCount&#40;m0bb&#41; > BbCount&#40;m1bb&#41; then
                    BbSetSq&#40;majority&#91;color&#93;, sq&#41;;

                  &#123; Multiple &#125;

                  BbAnd2&#40;countbb, c0bb, bfilebbvec&#91;MapSqToBfile&#40;sq&#41;&#93;);
                  if BbCount&#40;countbb&#41; > 1 then
                    BbSetSq&#40;multiple&#91;color&#93;, sq&#41;;

                  &#123; Passed &#125;

                  if BbNI2&#40;c1bb, passerbbvec&#91;color, sq&#93;) then
                    BbSetSq&#40;passed&#91;color&#93;, sq&#41;

                end
            until sq = sqnil;
          end
      end
  end; &#123; PawnStructLoadFromPos &#125;
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

CookieCat's pawn transposition table

Post by sje »

CookieCat also has a pawn structure transposition table. Each entry contains a 64 bit pawn structure hash, a copy of the pawn structure bitboards, a score, and some flag data.

Storing all the pawn structure bitboards makes for a jumbo size table entry, but this is necessary to avoid recalculation of the structure when the structure data is needed for pawn/non-pawn score factor calculation. Fortunately, the hit rate for a pawn transposition table is very high, even for a modestly size table.

Note that the pawn location bitboard pair, a part of the pawn structure, is also stored in the transposition table. This appears to be slightly redundant, but these bitboards are checked at probe time to completely eliminate any possibility of a false positive match.

Code: Select all

    &#123; Pawn transposition table entry&#58; flag data &#125;

    &#123; Bits 0 - 0&#58; 0/Free, 1/In use &#125;
    &#123; Bits 1 - 1&#58; 0/WTM, 1/BTM &#125;
    &#123; Bits 7 - 2&#58; Unused &#125;

    &#123; Pawn transposition table items &#125;

    ttpawnentrytype =
      record
        hash&#58;       hashtype;       &#123; Entry signature &#40;from position pshc hash&#41; &#125;
        pawnstruct&#58; pawnstructtype; &#123; Pawn structure &#125;
        score&#58;      svtype;         &#123; Associated score &#125;
        flagdata&#58;   ui8type         &#123; Packed flag data &#125;
      end;

    ttpawnindextype = 0..ttpawnmask;                               &#123; Pawn TT storage index &#125;
    ttpawnptrtype   = ^ttpawntype;                                 &#123; Pointer to pawn TT storage &#125;
    ttpawntype      = array &#91;ttpawnindextype&#93; of ttpawnentrytype;  &#123; Pawn TT storage &#125;

  &#123; ***** Pawn transposition table routines ***** &#125;

  procedure TTPawnReset&#40;var ttpawn&#58; ttpawntype&#41;;
    var
      ttpawnindex&#58; ttpawnindextype;
  begin
    for ttpawnindex &#58;= 0 to ttpawnmask do
      with ttpawn&#91;ttpawnindex&#93; do
        begin
          HashReset&#40;hash&#41;;
          PawnStructReset&#40;pawnstruct&#41;;
          score &#58;= svbroken;
          flagdata &#58;= 0
        end
  end; &#123; TTPawnReset &#125;

  function TTPawnNew&#58; ttpawnptrtype;
    var
      myresult&#58; ttpawnptrtype;
  begin
    New&#40;myresult&#41;;
    TTPawnReset&#40;myresult^);
    TTPawnNew &#58;= myresult
  end; &#123; TTPawnNew &#125;

  procedure TTPawnDispose&#40;ttpawnptr&#58; ttpawnptrtype&#41;;
  begin
    Dispose&#40;ttpawnptr&#41;
  end; &#123; TTPawnDispose &#125;

  procedure TTPawnFetchEntry&#40;
      var ttpawn&#58; ttpawntype; var pos&#58; postype; var sv&#58; svtype; var mypawnstruct&#58; pawnstructtype&#41;;
    var
      ttpawnindex&#58; ttpawnindextype;
  begin
    ttpawnindex &#58;= pos.pshc.bits and ttpawnmask;
    with ttpawn&#91;ttpawnindex&#93; do
      if &#40;hash.bits = pos.pshc.bits&#41; and
          BbEqual&#40;pawnstruct.location&#91;colorw&#93;, pos.bbdb.locbm&#91;manwp&#93;) and
          BbEqual&#40;pawnstruct.location&#91;colorb&#93;, pos.bbdb.locbm&#91;manbp&#93;) and
          Odd&#40;flagdata&#41; and ((&#40;flagdata shr 1&#41; and 1&#41; = pos.good&#41; then
        begin
          sv &#58;= score;
          mypawnstruct &#58;= pawnstruct
        end
      else
        sv &#58;= svbroken
  end; &#123; TTPawnFetchEntry &#125;

  procedure TTPawnStashEntry&#40;
      var ttpawn&#58; ttpawntype; var pos&#58; postype; sv&#58; svtype; var mypawnstruct&#58; pawnstructtype&#41;;
    var
      ttpawnindex&#58; ttpawnindextype;
  begin
    ttpawnindex &#58;= pos.pshc.bits and ttpawnmask;
    with ttpawn&#91;ttpawnindex&#93; do
      begin
        hash &#58;= pos.pshc;
        pawnstruct &#58;= mypawnstruct;
        score &#58;= sv;
        flagdata &#58;= 1 or &#40;pos.good shl 1&#41;
      end
  end; &#123; TTPawnStashEntry &#125;