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 |