Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
112 | pmbaty | 1 | /* |
2 | Protector -- a UCI chess engine |
||
3 | |||
4 | Copyright (C) 2009-2010 Raimund Heid (Raimund_Heid@yahoo.com) |
||
5 | |||
6 | This program is free software: you can redistribute it and/or modify |
||
7 | it under the terms of the GNU General Public License as published by |
||
8 | the Free Software Foundation, either version 3 of the License, or |
||
9 | (at your option) any later version. |
||
10 | |||
11 | This program is distributed in the hope that it will be useful, |
||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
14 | GNU General Public License for more details. |
||
15 | |||
16 | You should have received a copy of the GNU General Public License |
||
17 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
18 | |||
19 | */ |
||
20 | |||
21 | #include "tablebase.h" |
||
22 | #include "protector.h" |
||
23 | #include "io.h" |
||
24 | #include <assert.h> |
||
25 | |||
26 | #ifdef INCLUDE_TABLEBASE_ACCESS |
||
27 | |||
28 | #ifndef _MSC_VER |
||
29 | #include <pthread.h> |
||
30 | pthread_spinlock_t lock; |
||
31 | #else // _MSC_VER |
||
32 | bool lock = 0; // Pierre-Marie Baty -- Win32 thread locking |
||
33 | __declspec(dllimport) void __stdcall Sleep (unsigned long Timeout); // Pierre-Marie Baty -- for Sleep() |
||
34 | #endif // !_MSC_VER |
||
35 | volatile int tbAccessCount = 0; |
||
36 | |||
37 | #define MAX_PIECES_PER_SIDE 3 |
||
38 | #define NO_EP 127 |
||
39 | |||
40 | bool tbAvailable = FALSE; |
||
41 | typedef unsigned long long INDEX; |
||
42 | typedef unsigned int squaret; |
||
43 | |||
44 | char *cache = 0; |
||
45 | |||
46 | #define TB_FASTCALL /* __fastcall */ |
||
47 | |||
48 | typedef INDEX(*PfnCalcIndex) (squaret *, squaret *, squaret, int fInverse); |
||
49 | |||
50 | extern int IInitializeTb(char *pszPath); |
||
51 | extern int FTbSetCacheSize(void *pv, unsigned long cbSize); |
||
52 | extern void VTbCloseFiles(void); |
||
53 | extern int IDescFindFromCounters(int *piCount); |
||
54 | extern int FRegisteredFun(int iTb, int side); |
||
55 | extern PfnCalcIndex PfnIndCalcFun(int iTb, int side); |
||
56 | extern int TB_FASTCALL L_TbtProbeTable(int iTb, int side, INDEX indOffset); |
||
57 | |||
58 | #define pageL 65536 |
||
59 | #define tbbe_ssL ((pageL-4)/2) |
||
60 | #define bev_broken (tbbe_ssL+1) /* illegal or busted */ |
||
61 | #define bev_mi1 tbbe_ssL /* mate in 1 move */ |
||
62 | #define bev_mimin 1 /* mate in max moves */ |
||
63 | #define bev_draw 0 /* draw */ |
||
64 | #define bev_limax (-1) /* mated in max moves */ |
||
65 | #define bev_li0 (-tbbe_ssL) /* mated in 0 moves */ |
||
66 | |||
67 | #define PfnIndCalc PfnIndCalcFun |
||
68 | |||
69 | int setTablebaseCacheSize(unsigned int size) |
||
70 | { |
||
71 | unsigned long numBytes = (unsigned long) size * 1024 * 1024; |
||
72 | |||
73 | if (cache != 0) |
||
74 | { |
||
75 | free(cache); |
||
76 | } |
||
77 | |||
78 | cache = malloc(numBytes); |
||
79 | |||
80 | if (cache == 0) |
||
81 | { |
||
82 | logDebug("### Could not allocate tablebase cache (%lu bytes). ###\n", |
||
83 | numBytes); |
||
84 | |||
85 | return -1; |
||
86 | } |
||
87 | |||
88 | if (FTbSetCacheSize(cache, numBytes) == 0) |
||
89 | { |
||
90 | logDebug("### Could not set tablebase cache size (%lu bytes). ###\n", |
||
91 | numBytes); |
||
92 | |||
93 | free(cache); |
||
94 | cache = 0; |
||
95 | |||
96 | return -2; |
||
97 | } |
||
98 | |||
99 | /* logDebug("table base cache size set to %lu\n", numBytes); */ |
||
100 | |||
101 | return 0; |
||
102 | } |
||
103 | |||
104 | int initializeTablebase(const char *path) |
||
105 | { |
||
106 | int result = IInitializeTb((char *) path); |
||
107 | |||
108 | if (result > 0) |
||
109 | { |
||
110 | if (setTablebaseCacheSize(4) != 0) |
||
111 | { |
||
112 | closeTablebaseFiles(); |
||
113 | |||
114 | return -1; |
||
115 | } |
||
116 | |||
117 | /* logDebug("Tablebases found at %s\n", path); */ |
||
118 | } |
||
119 | else |
||
120 | { |
||
121 | logDebug("### Error while looking for tablebases in %s ###\n", path); |
||
122 | } |
||
123 | |||
124 | tbAvailable = (bool) (result > 0); |
||
125 | |||
126 | return (result > 0 ? 0 : -1); |
||
127 | } |
||
128 | |||
129 | void closeTablebaseFiles() |
||
130 | { |
||
131 | VTbCloseFiles(); |
||
132 | } |
||
133 | |||
134 | static void initializePieceData(const Bitboard * pieces, int *pieceCount, |
||
135 | unsigned int *pieceLocation) |
||
136 | { |
||
137 | Bitboard tmp = *pieces; |
||
138 | Square square; |
||
139 | |||
140 | *pieceCount = 0; |
||
141 | |||
142 | ITERATE_BITBOARD(&tmp, square) |
||
143 | { |
||
144 | *(pieceLocation++) = square; |
||
145 | (*pieceCount)++; |
||
146 | } |
||
147 | } |
||
148 | |||
149 | static int getMateValue(int fullMoves) |
||
150 | { |
||
151 | if (fullMoves > 0) |
||
152 | { |
||
153 | return 1 - VALUE_MATED - 2 * fullMoves; |
||
154 | } |
||
155 | else |
||
156 | { |
||
157 | return VALUE_MATED - 2 * fullMoves; |
||
158 | } |
||
159 | } |
||
160 | |||
161 | int probeTablebase(const Position * position) |
||
162 | { |
||
163 | int pieceCount[10]; |
||
164 | unsigned int whitePieces[MAX_PIECES_PER_SIDE * 5 + 1]; |
||
165 | unsigned int blackPieces[MAX_PIECES_PER_SIDE * 5 + 1]; |
||
166 | unsigned int *pwhite, *pblack; |
||
167 | int tableNr, fInvert, tableValue, fullMoves; |
||
168 | Color color; |
||
169 | INDEX index; |
||
170 | Square enPassantSquare = (Square) NO_EP; |
||
171 | |||
172 | initializePieceData(&position->piecesOfType[WHITE_PAWN], &pieceCount[0], |
||
173 | &whitePieces[0 * MAX_PIECES_PER_SIDE]); |
||
174 | initializePieceData(&position->piecesOfType[WHITE_KNIGHT], &pieceCount[1], |
||
175 | &whitePieces[1 * MAX_PIECES_PER_SIDE]); |
||
176 | initializePieceData(&position->piecesOfType[WHITE_BISHOP], &pieceCount[2], |
||
177 | &whitePieces[2 * MAX_PIECES_PER_SIDE]); |
||
178 | initializePieceData(&position->piecesOfType[WHITE_ROOK], &pieceCount[3], |
||
179 | &whitePieces[3 * MAX_PIECES_PER_SIDE]); |
||
180 | initializePieceData(&position->piecesOfType[WHITE_QUEEN], &pieceCount[4], |
||
181 | &whitePieces[4 * MAX_PIECES_PER_SIDE]); |
||
182 | |||
183 | initializePieceData(&position->piecesOfType[BLACK_PAWN], &pieceCount[5], |
||
184 | &blackPieces[0 * MAX_PIECES_PER_SIDE]); |
||
185 | initializePieceData(&position->piecesOfType[BLACK_KNIGHT], &pieceCount[6], |
||
186 | &blackPieces[1 * MAX_PIECES_PER_SIDE]); |
||
187 | initializePieceData(&position->piecesOfType[BLACK_BISHOP], &pieceCount[7], |
||
188 | &blackPieces[2 * MAX_PIECES_PER_SIDE]); |
||
189 | initializePieceData(&position->piecesOfType[BLACK_ROOK], &pieceCount[8], |
||
190 | &blackPieces[3 * MAX_PIECES_PER_SIDE]); |
||
191 | initializePieceData(&position->piecesOfType[BLACK_QUEEN], &pieceCount[9], |
||
192 | &blackPieces[4 * MAX_PIECES_PER_SIDE]); |
||
193 | |||
194 | tableNr = IDescFindFromCounters(pieceCount); |
||
195 | |||
196 | if (tableNr == 0) |
||
197 | { |
||
198 | return TABLEBASE_ERROR; |
||
199 | } |
||
200 | |||
201 | whitePieces[5 * MAX_PIECES_PER_SIDE] = position->king[WHITE]; |
||
202 | blackPieces[5 * MAX_PIECES_PER_SIDE] = position->king[BLACK]; |
||
203 | |||
204 | if (tableNr > 0) |
||
205 | { |
||
206 | color = position->activeColor; |
||
207 | fInvert = 0; |
||
208 | pwhite = whitePieces; |
||
209 | pblack = blackPieces; |
||
210 | } |
||
211 | else |
||
212 | { |
||
213 | color = opponent(position->activeColor); |
||
214 | fInvert = 1; |
||
215 | pwhite = blackPieces; |
||
216 | pblack = whitePieces; |
||
217 | tableNr = -tableNr; |
||
218 | } |
||
219 | |||
220 | #if defined __APPLE__ |
||
221 | pthread_mutex_lock((pthread_mutex_t *) & lock); |
||
222 | #elif defined _MSC_VER |
||
223 | while (lock) |
||
224 | Sleep (1); // allow context switching |
||
225 | lock = 1; // Pierre-Marie Baty -- Win32 thread locking |
||
226 | #else |
||
227 | pthread_spin_lock(&lock); |
||
228 | #endif |
||
229 | |||
230 | if (FRegisteredFun(tableNr, color) == FALSE) |
||
231 | { |
||
232 | #if defined __APPLE__ |
||
233 | pthread_mutex_unlock((pthread_mutex_t *) & lock); |
||
234 | #elif defined _MSC_VER |
||
235 | lock = 0; // Pierre-Marie Baty -- Win32 thread locking |
||
236 | #else |
||
237 | pthread_spin_unlock(&lock); |
||
238 | #endif |
||
239 | |||
240 | return TABLEBASE_ERROR; |
||
241 | } |
||
242 | |||
243 | if (position->enPassantSquare != NO_SQUARE) |
||
244 | { |
||
245 | const Bitboard attackers = |
||
246 | position->piecesOfType[PAWN | position->activeColor] & |
||
247 | generalMoves[PAWN | opponent(position->activeColor)] |
||
248 | [position->enPassantSquare]; |
||
249 | |||
250 | if (attackers != EMPTY_BITBOARD) |
||
251 | { |
||
252 | /* |
||
253 | dumpSquare(position->enPassantSquare); |
||
254 | dumpPosition(position); |
||
255 | */ |
||
256 | |||
257 | enPassantSquare = position->enPassantSquare; |
||
258 | } |
||
259 | } |
||
260 | |||
261 | index = PfnIndCalcFun(tableNr, color) |
||
262 | (pwhite, pblack, enPassantSquare, fInvert); |
||
263 | |||
264 | tableValue = L_TbtProbeTable(tableNr, color, index); |
||
265 | |||
266 | #if defined __APPLE__ |
||
267 | pthread_mutex_unlock((pthread_mutex_t *) & lock); |
||
268 | #elif defined _MSC_VER |
||
269 | lock = 0; // Pierre-Marie Baty -- Win32 thread locking |
||
270 | #else |
||
271 | pthread_spin_unlock(&lock); |
||
272 | #endif |
||
273 | |||
274 | if (tableValue == bev_broken) |
||
275 | { |
||
276 | return TABLEBASE_ERROR; |
||
277 | } |
||
278 | |||
279 | if (tableValue == 0) |
||
280 | { |
||
281 | return 0; |
||
282 | } |
||
283 | |||
284 | fullMoves = (tableValue > 0 ? |
||
285 | 1 + tbbe_ssL - tableValue : bev_li0 - tableValue); |
||
286 | |||
287 | return getMateValue(fullMoves); |
||
288 | } |
||
289 | |||
290 | int initializeModuleTablebase() |
||
291 | { |
||
292 | #if defined __APPLE__ |
||
293 | pthread_mutex_init((pthread_mutex_t *) & lock, tbAccessCount); |
||
294 | #elif defined _MSC_VER |
||
295 | lock = 0; // Pierre-Marie Baty -- Win32 thread locking |
||
296 | #else |
||
297 | pthread_spin_init(&lock, tbAccessCount); |
||
298 | #endif |
||
299 | |||
300 | if (commandlineOptions.tablebasePath != 0) |
||
301 | { |
||
302 | return initializeTablebase(commandlineOptions.tablebasePath); |
||
303 | } |
||
304 | else |
||
305 | { |
||
306 | return 0; |
||
307 | } |
||
308 | } |
||
309 | |||
310 | static int testTableFinder() |
||
311 | { |
||
312 | #ifndef NDEBUG |
||
313 | Variation variation; |
||
314 | int tableValue; |
||
315 | |||
316 | initializeVariation(&variation, "B6k/8/8/8/8/8/8/K6N w - - 0 1"); |
||
317 | tableValue = probeTablebase(&variation.singlePosition); |
||
318 | assert(tableValue == 29941); |
||
319 | |||
320 | initializeVariation(&variation, "B6k/8/8/8/8/8/8/K6N b - - 0 1"); |
||
321 | tableValue = probeTablebase(&variation.singlePosition); |
||
322 | assert(tableValue == -29940); |
||
323 | #endif |
||
324 | |||
325 | return 0; |
||
326 | } |
||
327 | |||
328 | static int testMateValues() |
||
329 | { |
||
330 | #ifndef NDEBUG |
||
331 | Variation variation; |
||
332 | int tableValue; |
||
333 | |||
334 | initializeVariation(&variation, "R6k/8/6K1/8/8/8/8/8 b - - 0 1"); |
||
335 | tableValue = probeTablebase(&variation.singlePosition); |
||
336 | assert(tableValue == VALUE_MATED); |
||
337 | |||
338 | initializeVariation(&variation, "7k/8/6K1/8/8/8/8/R7 w - - 0 1"); |
||
339 | tableValue = probeTablebase(&variation.singlePosition); |
||
340 | assert(tableValue == -VALUE_MATED - 1); |
||
341 | #endif |
||
342 | |||
343 | return 0; |
||
344 | } |
||
345 | |||
346 | int testModuleTablebase() |
||
347 | { |
||
348 | int result; |
||
349 | |||
350 | if (tbAvailable == FALSE) |
||
351 | { |
||
352 | return 0; |
||
353 | } |
||
354 | |||
355 | if (commandlineOptions.tablebasePath == 0) |
||
356 | { |
||
357 | return 0; |
||
358 | } |
||
359 | |||
360 | if ((result = testTableFinder()) != 0) |
||
361 | { |
||
362 | return result; |
||
363 | } |
||
364 | |||
365 | if ((result = testMateValues()) != 0) |
||
366 | { |
||
367 | return result; |
||
368 | } |
||
369 | |||
370 | return 0; |
||
371 | } |
||
372 | #endif |