LCOV - code coverage report
Current view: top level - src - matsig.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 13 13 100.0 %
Date: 2019-01-29 11:06:41 Functions: 1 1 100.0 %

          Line data    Source code
       1             : //////////////////////////////////////////////////////////////////////
       2             : //
       3             : //  FILE:       matsig.h
       4             : //              Material signatures and home-pawn signatures.
       5             : //
       6             : //  Part of:    Scid (Shane's Chess Information Database)
       7             : //  Version:    1.9
       8             : //
       9             : //  Notice:     Copyright (c) 2000  Shane Hudson.  All rights reserved.
      10             : //
      11             : //  Author:     Shane Hudson (sgh@users.sourceforge.net)
      12             : //
      13             : //////////////////////////////////////////////////////////////////////
      14             : 
      15             : 
      16             : #ifndef SCID_MATSIG_H
      17             : #define SCID_MATSIG_H
      18             : 
      19             : #include "common.h"
      20             : #include <algorithm>
      21             : #include <string>
      22             : 
      23             : // Matsigs are 32-bit unsigned ints.  We only use 24 bits of this.
      24             : 
      25             : typedef uint32_t matSigT;
      26             : 
      27             : // From most significant bits down to least, the matsig layout is:
      28             : // Bits 22-33:  WQ    Bits 10-11:  BQ
      29             : // Bits 20-21:  WN    Bits 08-09:  BR
      30             : // Bits 18-19:  WB    Bits 06-07:  BB
      31             : // Bits 16-17:  WN    Bits 04-05:  BN
      32             : // Bits 12-15:  WP    Bits 00-03:  BP
      33             : 
      34             : // This means that pawn counts from 0 to 8 are possible, but for other
      35             : // pieces only counts up to 3 are possible.
      36             : 
      37             : 
      38             : // Shifts:
      39             : 
      40             : #define SHIFT_BP 0
      41             : #define SHIFT_BN 4
      42             : #define SHIFT_BB 6
      43             : #define SHIFT_BR 8
      44             : #define SHIFT_BQ 10
      45             : #define SHIFT_WP 12
      46             : #define SHIFT_WN 16
      47             : #define SHIFT_WB 18
      48             : #define SHIFT_WR 20
      49             : #define SHIFT_WQ 22
      50             : 
      51             : 
      52             : // Masks:
      53             :                             //         28   24   20   16   12    8    4    0
      54             : #define MASK_BP 0x0000000F  // 0- 3: .... .... .... .... .... .... .... 1111
      55             : #define MASK_BN 0x00000030  // 4- 5: .... .... .... .... .... .... ..11 ....
      56             : #define MASK_BB 0x000000C0  // 6- 7: .... .... .... .... .... .... 11.. ....
      57             : #define MASK_BR 0x00000300  // 8- 9: .... .... .... .... .... ..11 .... ....
      58             : #define MASK_BQ 0x00000C00  //10-11: .... .... .... .... .... 11.. .... ....
      59             : #define MASK_WP 0x0000F000  //12-15: .... .... .... .... 1111 .... .... ....
      60             : #define MASK_WN 0x00030000  //16-17: .... .... .... ..11 .... .... .... ....
      61             : #define MASK_WB 0x000C0000  //18-19: .... .... .... 11.. .... .... .... ....
      62             : #define MASK_WR 0x00300000  //20-21: .... .... ..11 .... .... .... .... ....
      63             : #define MASK_WQ 0x00C00000  //29-31: .... .... 11.. .... .... .... .... ....
      64             : 
      65             : 
      66             : // The arrays MASK_BY_PIECE and SHIFT_BY_PIECE are useful for setting
      67             : // matsigs by piece type:
      68             : 
      69             : const matSigT
      70             : MASK_BY_PIECE [16] = {
      71             :     0,        //  0: Empty
      72             :     0,        //  1: WK
      73             :     MASK_WQ,  //  2: WQ
      74             :     MASK_WR,  //  3: WR
      75             :     MASK_WB,  //  4: WB
      76             :     MASK_WN,  //  5: WN
      77             :     MASK_WP,  //  6: WP
      78             :     0, 0,     //  7, 8: Invalid pieces
      79             :     0,        //  9: BK
      80             :     MASK_BQ,  // 10: BQ
      81             :     MASK_BR,  // 11: BR
      82             :     MASK_BB,  // 12: BB
      83             :     MASK_BN,  // 13: BN
      84             :     MASK_BP,  // 14: BP
      85             :     0         // 15: Invalid piece
      86             : };
      87             : 
      88             : const uint
      89             : SHIFT_BY_PIECE[16] = {
      90             :     0, 0,      //  0: Empty,  1: WK
      91             :     SHIFT_WQ,  //  2: WQ
      92             :     SHIFT_WR,  //  3: WR
      93             :     SHIFT_WB,  //  4: WB
      94             :     SHIFT_WN,  //  5: WN
      95             :     SHIFT_WP,  //  6: WP
      96             :     0, 0, 0,   //  7, 8: Invalid pieces,  9: BK
      97             :     SHIFT_BQ,  // 10: BQ
      98             :     SHIFT_BR,  // 11: BR
      99             :     SHIFT_BB,  // 12: BB
     100             :     SHIFT_BN,  // 13: BN
     101             :     SHIFT_BP,  // 14: BP
     102             :     0          // 15: Invalid piece
     103             : };
     104             : 
     105             : 
     106             : // Quick way to flip colors: just switch the upper/lower 12 bits
     107             : 
     108             : #define MATSIG_FlipColor(x) ((x) >> 12) | (((x) & 0x00000FFF) << 12)
     109             : 
     110             : 
     111             : // Quick tests for non-zero counts of a piece type:
     112             : 
     113             : #define MATSIG_Has_WQ(x)  ((x) & MASK_WQ)
     114             : #define MATSIG_Has_BQ(x)  ((x) & MASK_BQ)
     115             : #define MATSIG_Has_WR(x)  ((x) & MASK_WR)
     116             : #define MATSIG_Has_BR(x)  ((x) & MASK_BR)
     117             : #define MATSIG_Has_WB(x)  ((x) & MASK_WB)
     118             : #define MATSIG_Has_BB(x)  ((x) & MASK_BB)
     119             : #define MATSIG_Has_WN(x)  ((x) & MASK_WN)
     120             : #define MATSIG_Has_BN(x)  ((x) & MASK_BN)
     121             : #define MATSIG_Has_WP(x)  ((x) & MASK_WP)
     122             : #define MATSIG_Has_BP(x)  ((x) & MASK_BP)
     123             : 
     124             : #define MATSIG_HasQueens(x)   ((x) & (MASK_WQ | MASK_BQ))
     125             : #define MATSIG_HasRooks(x)    ((x) & (MASK_WR | MASK_BR))
     126             : #define MATSIG_HasBishops(x)  ((x) & (MASK_WB | MASK_BB))
     127             : #define MATSIG_HasKnights(x)  ((x) & (MASK_WN | MASK_BN))
     128             : #define MATSIG_HasPawns(x)    ((x) & (MASK_WP | MASK_BP))
     129             : 
     130             : 
     131             : // Macros to extract a particular count:
     132             : 
     133             : #define MATSIG_Count_WQ(x)  (((x) & MASK_WQ) >> SHIFT_WQ)
     134             : #define MATSIG_Count_BQ(x)  (((x) & MASK_BQ) >> SHIFT_BQ)
     135             : #define MATSIG_Count_WR(x)  (((x) & MASK_WR) >> SHIFT_WR)
     136             : #define MATSIG_Count_BR(x)  (((x) & MASK_BR) >> SHIFT_BR)
     137             : #define MATSIG_Count_WB(x)  (((x) & MASK_WB) >> SHIFT_WB)
     138             : #define MATSIG_Count_BB(x)  (((x) & MASK_BB) >> SHIFT_BB)
     139             : #define MATSIG_Count_WN(x)  (((x) & MASK_WN) >> SHIFT_WN)
     140             : #define MATSIG_Count_BN(x)  (((x) & MASK_BN) >> SHIFT_BN)
     141             : #define MATSIG_Count_WP(x)  (((x) & MASK_WP) >> SHIFT_WP)
     142             : #define MATSIG_Count_BP(x)  (((x) & MASK_BP) >> SHIFT_BP)
     143             : 
     144             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     145             : // matsig_getCount():
     146             : //      Inline routine to extract a count of a certain piece type.
     147             : //
     148             : inline uint
     149             : matsig_getCount (matSigT m, pieceT p)
     150             : {
     151             :     return (m & MASK_BY_PIECE[p]) >> SHIFT_BY_PIECE[p];
     152             : }
     153             : 
     154             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     155             : // matsig_setCount():
     156             : //      Inline routine to set a particular count.
     157             : //
     158             : inline matSigT
     159             : matsig_setCount (matSigT m, pieceT p, uint count)
     160             : {
     161             :     // First we clear the old mask for this piece:
     162             :     m &= ~(MASK_BY_PIECE[p]);
     163             : 
     164             :          // Avoid overflow.
     165             :          if (p != PAWN && count > 3)
     166             :                  count = 3;
     167             : 
     168             :     // Now we OR to add the new value in:
     169             :     m |= ((uint) count) << SHIFT_BY_PIECE[p];
     170             :     return m;
     171             : }
     172             : 
     173             : 
     174             : // Common constant matsigs:
     175             : 
     176             : const matSigT MATSIG_Empty = 0;
     177             : 
     178             : const matSigT MATSIG_StdStart =
     179             :    ((1 << SHIFT_WQ) | (1 << SHIFT_BQ) | (2 << SHIFT_WR) | (2 << SHIFT_BR) |
     180             :     (2 << SHIFT_WB) | (2 << SHIFT_BB) | (2 << SHIFT_WN) | (2 << SHIFT_BN) |
     181             :     (8 << SHIFT_WP) | (8 << SHIFT_BP));
     182             : 
     183             : 
     184             : //
     185             : // Public functions found in matsig.cpp:
     186             : //
     187             : 
     188             : 
     189             : // matsig_makeString: sets s to be a string representation of the sig,
     190             : std::string
     191             : matsig_makeString (matSigT matsig);
     192             : 
     193             : 
     194             : // matsig_isReachable: returns true if a game currently
     195             : //     at a position with the signature <start>, could possibly reach
     196             : //     the signature <target>. This is useful for quick tests for material
     197             : //     searches. For example, if we store the final matsig of every game,
     198             : //     we can speedup a material search by ONLY searching the games that
     199             : //     have matsig_isReachable(searchsig, finalsig) = 1, or have promotions.
     200             : //     Example: if searchsig requires neither side to have queens, but
     201             : //     finalsig for a game shows a WQ (and no promotions), the game could
     202             : //     not possibly match.
     203             : //     If promos is true, only the pawn counts are checked, since other
     204             : //     material could reappear on the board due to a promotion.
     205             : //     If upromo is true, there are underpromotions (to R, B or N) but
     206             : //     if only promos is true, all promotions are to Queens only.
     207             : bool
     208             : matsig_isReachable (matSigT mStart, matSigT mTarget, bool promos, bool upromo);
     209             : 
     210             : // matsig_isReachablePawns:
     211             : //    like matsig_isReachable, but considering pawns only.
     212             : inline bool
     213             : matsig_isReachablePawns (matSigT mStart, matSigT mTarget)
     214             : {
     215             :     if (MATSIG_Count_WP(mStart) < MATSIG_Count_WP(mTarget)) { return false; }
     216             :     if (MATSIG_Count_BP(mStart) < MATSIG_Count_BP(mTarget)) { return false; }
     217             :     return true;
     218             : }
     219             : 
     220             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     221             : // matsig_Make():
     222             : //      Make a material sig, given an array of material counts as
     223             : //      stored in a Position.
     224             : //
     225        9016 : inline matSigT matsig_Make(const byte* materialCounts) {
     226        9016 :     matSigT m = 0;
     227        9016 :     m |= std::min<matSigT>(3, materialCounts[WQ]) << SHIFT_WQ;
     228        9016 :     m |= std::min<matSigT>(3, materialCounts[WR]) << SHIFT_WR;
     229        9016 :     m |= std::min<matSigT>(3, materialCounts[WB]) << SHIFT_WB;
     230        9016 :     m |= std::min<matSigT>(3, materialCounts[WN]) << SHIFT_WN;
     231        9016 :     m |= matSigT(materialCounts[WP]) << SHIFT_WP;
     232        9016 :     m |= std::min<matSigT>(3, materialCounts[BQ]) << SHIFT_BQ;
     233        9016 :     m |= std::min<matSigT>(3, materialCounts[BR]) << SHIFT_BR;
     234        9016 :     m |= std::min<matSigT>(3, materialCounts[BB]) << SHIFT_BB;
     235        9016 :     m |= std::min<matSigT>(3, materialCounts[BN]) << SHIFT_BN;
     236        9016 :     m |= matSigT(materialCounts[BP]) << SHIFT_BP;
     237        9016 :     return m;
     238             : }
     239             : 
     240             : 
     241             : // Common HPSigs:
     242             : // 0 => no pawns still on their original 2nd/7th rank squares.
     243             : // 0xFFFF => all 16 pawns still on their original 2nd/7th rank squares.
     244             : 
     245             : const uint
     246             : HPSIG_Empty = 0x0;
     247             : 
     248             : const uint
     249             : HPSIG_StdStart = 0xFFFF;
     250             : 
     251             : 
     252             : bool
     253             : hpSig_PossibleMatch (uint hpSig, const byte * changeList);
     254             : 
     255             : bool
     256             : hpSig_Prefix (const byte * changeListA, const byte * changeListB);
     257             : 
     258             : uint
     259             : hpSig_Final (const byte * changeList);
     260             : 
     261             : // hpSig_bitMask[]: used to add or clear bits in an hpSig.
     262             : //
     263             : static const uint hpSig_bitMask [16] = {
     264             :     // a2 to h2:
     265             :     0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100,
     266             :     // a7 to h7:
     267             :     0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
     268             : };
     269             : 
     270             : inline uint
     271             : hpSig_AddPawn (uint hpSig, colorT color, fyleT fyle)
     272             : {
     273             :     ASSERT (color == WHITE  ||  color == BLACK);
     274             :     ASSERT (fyle <= H_FYLE);
     275             : 
     276             :     uint val = (uint) fyle;
     277             :     if (color == BLACK) val += 8;
     278             :     return hpSig | hpSig_bitMask [val];
     279             : }
     280             : 
     281             : inline uint
     282             : hpSig_ClearPawn (uint hpSig, colorT color, fyleT fyle)
     283             : {
     284             :     ASSERT (color == WHITE  ||  color == BLACK);
     285             :     ASSERT (fyle <= H_FYLE);
     286             : 
     287             :     uint val = (uint) fyle;
     288             :     if (color == BLACK) val += 8;
     289             :     return hpSig & ~(hpSig_bitMask [val]);
     290             : }
     291             : 
     292             : /**
     293             :  * Creates a 16-bits bitmap of the missing pawns in the home ranks.
     294             :  *
     295             :  * Used to speed up the searches of positions with the same pawn structure.
     296             :  * @returns a std::pair containing the bitmap and the number of moved pawns.
     297             :  */
     298             : inline std::pair<uint16_t, uint16_t> hpSig_make(const pieceT* board) {
     299             :         int hpSig = 0;
     300             :         int nMoved = 0;
     301             :         const pieceT* b = board + A2;
     302             :         // clang-format off
     303             :         if (*b != WP) { hpSig |= 0x8000; ++nMoved; }  b++;  /* a2 */
     304             :         if (*b != WP) { hpSig |= 0x4000; ++nMoved; }  b++;  /* b2 */
     305             :         if (*b != WP) { hpSig |= 0x2000; ++nMoved; }  b++;  /* c2 */
     306             :         if (*b != WP) { hpSig |= 0x1000; ++nMoved; }  b++;  /* d2 */
     307             :         if (*b != WP) { hpSig |= 0x0800; ++nMoved; }  b++;  /* e2 */
     308             :         if (*b != WP) { hpSig |= 0x0400; ++nMoved; }  b++;  /* f2 */
     309             :         if (*b != WP) { hpSig |= 0x0200; ++nMoved; }  b++;  /* g2 */
     310             :         if (*b != WP) { hpSig |= 0x0100; ++nMoved; }        /* h2 */
     311             :         b = board + A7;
     312             :         if (*b != BP) { hpSig |= 0x0080; ++nMoved; }  b++;  /* a7 */
     313             :         if (*b != BP) { hpSig |= 0x0040; ++nMoved; }  b++;  /* b7 */
     314             :         if (*b != BP) { hpSig |= 0x0020; ++nMoved; }  b++;  /* c7 */
     315             :         if (*b != BP) { hpSig |= 0x0010; ++nMoved; }  b++;  /* d7 */
     316             :         if (*b != BP) { hpSig |= 0x0008; ++nMoved; }  b++;  /* e7 */
     317             :         if (*b != BP) { hpSig |= 0x0004; ++nMoved; }  b++;  /* f7 */
     318             :         if (*b != BP) { hpSig |= 0x0002; ++nMoved; }  b++;  /* g7 */
     319             :         if (*b != BP) { hpSig |= 0x0001; ++nMoved; }        /* h7 */
     320             :         // clang-format on
     321             : 
     322             :         return {static_cast<uint16_t>(hpSig), static_cast<uint16_t>(nMoved)};
     323             : }
     324             : 
     325             : inline bool hpSig_match(int hpSig, int nMoved, const byte* changeList) {
     326             :         // The first byte of a changeList is the length (in halfbytes) of the
     327             :         // list, which can be any value from 0 to 16 inclusive.
     328             :         if (*changeList == 16 && nMoved == 16)
     329             :                 return true;
     330             :         if (*changeList++ < nMoved)
     331             :                 return false;
     332             : 
     333             :         int sig = 0;
     334             :         for (int i = 0, n = nMoved / 2; i < n; ++i) {
     335             :                 sig |= 1 << (*changeList >> 4);
     336             :                 sig |= 1 << (*changeList++ & 0x0F);
     337             :         }
     338             :         if (nMoved & 1)
     339             :                 sig |= 1 << (*changeList >> 4);
     340             : 
     341             :         return sig == hpSig;
     342             : }
     343             : 
     344             : #endif
     345             : 
     346             : //////////////////////////////////////////////////////////////////////
     347             : //  EOF: matsig.h
     348             : //////////////////////////////////////////////////////////////////////
     349             : 

Generated by: LCOV version 1.13