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