X-Git-Url: http://winboard.nl/cgi-bin?p=xboard.git;a=blobdiff_plain;f=book.c;h=9828dd24e3d09decce7d4e5e45b1914489de2b94;hp=98dde33bcd80047a58602bfa25fad285a6f77220;hb=HEAD;hpb=74506c0e852b35465c651f331e010ca7e60e7dd3 diff --git a/book.c b/book.c index 98dde33..9828dd2 100644 --- a/book.c +++ b/book.c @@ -2,7 +2,7 @@ * book.c -- code for probing Polyglot opening books * * This code was first released in the public domain by Michel Van den Bergh. - * The array Random64 is taken from the Polyglot source code. + * The array Random64 is taken from the Polyglot source code. * I am pretty sure that a table of random numbers is never protected * by copyright. * @@ -28,6 +28,8 @@ * ------------------------------------------------------------------------ */ +#include "config.h" + #include #include #include @@ -65,7 +67,7 @@ typedef unsigned short uint16; typedef unsigned int uint32; typedef struct { - uint64 key; + uint64 key; uint16 move; uint16 weight; uint16 learnPoints; @@ -311,8 +313,9 @@ hash (int moveNr) ChessSquare p = boards[moveNr][r][f]; if(f == BOARD_LEFT-1 || f == BOARD_RGHT) continue; // between board and holdings if(p != EmptySquare){ - int j = (int)p; + int j = (int)p, promoted = 0; j -= (j >= (int)BlackPawn) ? (int)BlackPawn :(int)WhitePawn; + if(j >= WhitePBishop && j != WhiteKing) promoted++, j -= WhiteTokin; if(j > (int)WhiteQueen) j++; // make space for King if(j > (int) WhiteKing) j = (int)WhiteQueen + 1; p_enc = 2*j + ((int)p < (int)BlackPawn); @@ -326,7 +329,8 @@ hash (int moveNr) pieceGroup = p_enc / 12; p_enc = p_enc % 12; Zobrist = RandomPiece[64*p_enc + (squareNr & 63)]; - switch(pieceGroup) { + if(pieceGroup & 4) Zobrist *= 987654321; + switch(pieceGroup & 3) { case 1: // pieces 5-10 (FEACWM) Zobrist = (Zobrist << 16) ^ (Zobrist >> 48); break; @@ -337,7 +341,9 @@ hash (int moveNr) Zobrist = (Zobrist << 48) ^ (Zobrist >> 16); break; } - if(squareNr >= 64) Zobrist = (Zobrist << 8) ^ (Zobrist >> 56); + if(promoted) Zobrist ^= 123456789*RandomPiece[squareNr & 63]; + if(squareNr & 64) Zobrist = (Zobrist << 8) ^ (Zobrist >> 56); + if(squareNr & 128) Zobrist = (Zobrist << 4) ^ (Zobrist >> 60); // holdings have separate (additive) key, to encode presence of multiple pieces on same square if(f == BOARD_LEFT-2) holdingsKey += Zobrist * boards[moveNr][r][f+1]; else if(f == BOARD_RGHT+1) holdingsKey += Zobrist * boards[moveNr][r][f-1]; else @@ -358,7 +364,7 @@ hash (int moveNr) f = boards[moveNr][EP_STATUS]; if(f >= 0 && f < 8){ if(!WhiteOnMove(moveNr)){ - // the test for neighboring Pawns might not be needed, + // the test for neighboring Pawns might not be needed, // as epStatus already kept track of it, but better safe than sorry. if((f>0 && boards[moveNr][3][f-1]==BlackPawn)|| (f<7 && boards[moveNr][3][f+1]==BlackPawn)){ @@ -478,8 +484,11 @@ find_key (FILE *f, uint64 key, entry_t *entry) } } +static int xStep[] = { 0, 1, 1, 1, 0,-1,-1,-1 }; +static int yStep[] = { 1, 1, 0,-1,-1,-1, 0, 1 }; + void -move_to_string (char move_s[6], uint16 move) +move_to_string (char move_s[20], uint16 move) { int f,fr,ff,t,tr,tf,p; int width = BOARD_RGHT - BOARD_LEFT, size; // allow for alternative board formats @@ -493,29 +502,38 @@ move_to_string (char move_s[6], uint16 move) t = move % size; tr = t / width; tf = t % width; - move_s[0] = ff + 'a'; - move_s[1] = fr + '1' - (BOARD_HEIGHT > 9); - move_s[2] = tf + 'a'; - move_s[3] = tr + '1' - (BOARD_HEIGHT > 9); + snprintf(move_s, 9, "%c%d%c%d", ff + 'a', fr + 1 - (BOARD_HEIGHT == 10), tf + 'a', tr + 1 - (BOARD_HEIGHT == 10)); + + if(IS_SHOGI(gameInfo.variant) && p) { + if(p == 2) p = 10; // Lion moves, for boards so big that 10 is out of range + else if(p != 7) p = 8; // use '+' for all others that do not explicitly defer + } // kludge: encode drops as special promotion code if(gameInfo.holdingsSize && p == 9) { move_s[0] = f + '@'; // from square encodes piece type move_s[1] = '@'; // drop symbol p = 0; + } else if(p == 10) { // decode Lion move + int i = t & 7, j = t >> 3 & 7; + tf = ff + xStep[i] + xStep[j]; tr = fr + yStep[i] + yStep[j]; // calculate true to-square + snprintf(move_s, 20, "%c%d%c%d,%c%d%c%d", ff + 'a', fr + 1 - (BOARD_HEIGHT == 10), + ff + xStep[i] + 'a', fr + yStep[i] + 1 - (BOARD_HEIGHT == 10), + ff + xStep[i] + 'a', fr + yStep[i] + 1 - (BOARD_HEIGHT == 10), + tf + 'a', tr + 1 - (BOARD_HEIGHT == 10) ); + p = 0; } // add promotion piece, if any if(p){ - move_s[4] = promote_pieces[p]; - move_s[5] = '\0'; - }else{ - move_s[4] = '\0'; + int len = strlen(move_s); + move_s[len] = promote_pieces[p]; + move_s[len+1] = '\0'; } if(gameInfo.variant != VariantNormal) return; - // correct FRC-style castlings in variant normal. + // correct FRC-style castlings in variant normal. // [HGM] This is buggy code! e1h1 could very well be a normal R or Q move. if(!strcmp(move_s,"e1h1")){ safeStrCpy(move_s,"e1g1", 6); @@ -561,20 +579,23 @@ GetBookMoves (FILE *f, int moveNr, entry_t entries[], int max) return count; } +static int dirty; + int ReadFromBookFile (int moveNr, char *book, entry_t entries[]) { // retrieve all entries for given position from book in 'entries', return number. static FILE *f = NULL; static char curBook[MSG_SIZ]; - if(book == NULL) return -1; + if(book == NULL) return -1; + if(dirty) { if(f) fclose(f); dirty = 0; f = NULL; } if(!f || strcmp(book, curBook)){ // keep book file open until book changed strncpy(curBook, book, MSG_SIZ); if(f) fclose(f); f = fopen(book,"rb"); } if(!f){ - DisplayError("Polyglot book not valid", 0); + DisplayError(_("Polyglot book not valid"), 0); appData.usePolyglotBook = FALSE; return -1; } @@ -626,7 +647,7 @@ InitMemBook () } char * -MCprobe (moveNr) +MCprobe (int moveNr) { int count, count2, games, i, choice=0; entry_t entries[MOVE_BUF]; @@ -665,14 +686,14 @@ MCprobe (moveNr) char *ProbeBook (int moveNr, char *book) -{ // +{ // entry_t entries[MOVE_BUF]; int count; int i, j; static char move_s[6]; int total_weight; - if(moveNr >= 2*appData.bookDepth) return NULL; + if(moveNr >= 2*appData.bookDepth) return NULL; if(mcMode) return MCprobe(moveNr); if((count = ReadFromBookFile(moveNr, book, entries)) <= 0) return NULL; // no book, or no hit @@ -712,13 +733,18 @@ char * MovesToText(int count, entry_t *entries) { int i, totalWeight = 0; - char algMove[6]; + char algMove[12]; char *p = (char*) malloc(40*count+1); for(i=0; i= 4) { + CoordsToAlgebraic(boards[currentMove], PosFlags(currentMove), i1-ONE+'0', c1-AAA, i2-ONE+'0', c2-AAA, c3, algMove); + } buf[0] = NULLCHAR; if(entries[i].learnCount || entries[i].learnPoints) snprintf(buf, MSG_SIZ, " {%d/%d}", entries[i].learnPoints, entries[i].learnCount); @@ -737,7 +763,20 @@ CoordsToMove (int fromX, int fromY, int toX, int toY, char promoChar) int from = fromX - BOARD_LEFT + fromY * width; for(i=0; promote_pieces[i]; i++) if(promote_pieces[i] == promoChar) break; if(!promote_pieces[i]) i = 0; + else if(i == 9 && gameInfo.variant == VariantChu) i = 1; // on 12x12 only 3 promotion codes available, so use 1 to indicate promotion if(fromY == DROP_RANK) i = 9, from = ToUpper(PieceToChar(fromX)) - '@'; + if(killX >= 0) { // multi-leg move + int dx = killX - fromX, dy = killY - fromY; + for(i=0; i<8; i++) if(dx == xStep[i] && dy == yStep[i]) { + int j; + dx = toX - killX; dy = toY - killY; + for(j=0; j<8; j++) if(dx == xStep[j] && dy == yStep[j]) { + // special encoding in to-square, with promoType = 2. Assumes board >= 64 squares! + return i + 8*j + (2 * width * BOARD_HEIGHT + from) * width * BOARD_HEIGHT; + } + } + i = 0; // if not a valid Lion move, ignore kill-square and promoChar + } return to + (i * width * BOARD_HEIGHT + from) * width * BOARD_HEIGHT; } @@ -757,14 +796,20 @@ TextToMoves (char *text, int moveNum, entry_t *entries) if(w == 1) text = strstr(text, "1 ") + 2; // skip weight that could be recognized as move number one valid = ParseOneMove(text, moveNum, &moveType, &fromX, &fromY, &toX, &toY, &promoChar); text = strstr(text, yy_textstr) + strlen(yy_textstr); // skip what we parsed - if(!valid || moveType != NormalMove) continue; + if(!valid || moveType != NormalMove && moveType != WhiteDrop && moveType != BlackDrop + && moveType != FirstLeg + && moveType != WhitePromotion && moveType != BlackPromotion + && moveType != WhiteCapturesEnPassant && moveType != BlackCapturesEnPassant + && moveType != WhiteKingSideCastle && moveType != BlackKingSideCastle + && moveType != WhiteQueenSideCastle && moveType != BlackQueenSideCastle + && moveType != WhiteNonPromotion && moveType != BlackNonPromotion) continue; if(*text == ' ' && sscanf(text+1, "{%hd/%hd}", &entries[count].learnPoints, &entries[count].learnCount) == 2) { text = strchr(text+1, '}') + 1; } else { entries[count].learnPoints = 0; entries[count].learnCount = 0; } - entries[count].move = CoordsToMove(fromX, fromY, toX, toY, promoChar); + entries[count].move = CoordsToMove(fromX, fromY, toX, toY, promoChar); killX = killY = -1; entries[count].key = hashKey; entries[count].weight = w; count++; @@ -787,6 +832,7 @@ DisplayBook (int moveNr) p = MovesToText(count, entries); EditTagsPopUp(p, NULL); free(p); + addToBookFlag = FALSE; return TRUE; } @@ -852,6 +898,7 @@ SaveToBook (char *text) writepos += len2; } while(len1); } + dirty = 1; fclose(f); } @@ -973,12 +1020,21 @@ AddGameToBook (int always) } if(appData.debugMode) fprintf(debugFP, "add game to book (%d-%d)\n", backwardMostMove, forwardMostMove); - for(i=backwardMostMove; i text && start[-1] != ' ' && start[-1] != '\t') start--; + while(*end && *++end != ' ' && *end != '\n') + ; *end = NULLCHAR; // find clicked word + if(start != end) TypeInDoneEvent(start); // fake it was typed in move type-in +} + +void FlushBook () { FILE *f; @@ -995,5 +1051,5 @@ FlushBook () // entry.learnCount = 0; entry_to_file(f, &entry); } - } else DisplayError("Could not create book", 0); + } else DisplayError(_("Could not create book"), 0); }