- /* 
-     Protector -- a UCI chess engine 
-   
-     Copyright (C) 2009-2010 Raimund Heid (Raimund_Heid@yahoo.com) 
-   
-     This program is free software: you can redistribute it and/or modify 
-     it under the terms of the GNU General Public License as published by 
-     the Free Software Foundation, either version 3 of the License, or 
-     (at your option) any later version. 
-   
-     This program is distributed in the hope that it will be useful, 
-     but WITHOUT ANY WARRANTY; without even the implied warranty of 
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
-     GNU General Public License for more details. 
-   
-     You should have received a copy of the GNU General Public License 
-     along with this program.  If not, see <http://www.gnu.org/licenses/>. 
-   
- */ 
-   
- #include "book.h" 
- #include "io.h" 
- #include "pgn.h" 
- #include <string.h> 
- #include <assert.h> 
- #include <stdlib.h> 
- #include <time.h> 
-   
- static const UINT32 ILLEGAL_OFFSET = 0xFFFFFFFF; 
- Book globalBook; 
-   
- int openBook(Book * book, const char *name) 
- { 
-    char indexfileName[256], movefileName[256]; 
-   
-    strcat(- indexfileName , ".bki");
 
-   
-    book->readonly = FALSE; 
-    book ->- indexFile  = fopen(- indexfileName , "r+");
-    book ->- moveFile  = fopen(- movefileName , "r+");
-   
-    if (book->indexFile == NULL) 
-    { 
-       book ->- indexFile  = fopen(- indexfileName , "w+");
-    } 
-   
-    if (book->moveFile == NULL) 
-    { 
-       book ->- moveFile  = fopen(- movefileName , "w+");
-    } 
-   
-    if (book->indexFile == NULL) 
-    { 
-       book ->- indexFile  = fopen(- indexfileName , "r");
-       book->readonly = TRUE; 
-    } 
-   
-    if (book->moveFile == NULL) 
-    { 
-       book ->- moveFile  = fopen(- movefileName , "r");
-       book->readonly = TRUE; 
-    } 
-   
-    if (book->indexFile != NULL) 
-    { 
-       fseek(- book ->- indexFile , 0,-  SEEK_END );
 
-       book->numberOfPositions = 
-          (ftell(- book ->- indexFile ) + 1) / sizeof(- BookPosition );
 
-    } 
-   
-    if (book->moveFile != NULL) 
-    { 
-       fseek(- book ->- moveFile , 0,-  SEEK_END );
 
-       book ->- numberOfMoves  = (ftell(- book ->- moveFile ) + 1) / sizeof(- BookMove );
-    } 
-   
-    if (book->indexFile != NULL && book->moveFile != NULL) 
-    { 
-       return 0; 
-    } 
-    else 
-    { 
-       if (book->indexFile != NULL) 
-       { 
-          book->indexFile = NULL; 
-       } 
-   
-       if (book->moveFile != NULL) 
-       { 
-          book->moveFile = NULL; 
-       } 
-   
-       return -1; 
-    } 
- } 
-   
- void closeBook(Book * book) 
- { 
-    if (book->indexFile != NULL) 
-    { 
-    } 
-   
-    if (book->moveFile != NULL) 
-    { 
-    } 
- } 
-   
- static BookPosition loadBookposition(const Book * book, const UINT32 offset) 
- { 
-    BookPosition position; 
-   
-    fseek(- book ->- indexFile ,-  offset ,-  SEEK_SET );
 
-    fread(&- position , sizeof(- BookPosition ), 1,-  book ->- indexFile );
 
-   
-    return position; 
- } 
-   
- static void storeBookposition(Book * book, const BookPosition * position, 
-                               const UINT32 offset) 
- { 
-    fseek(- book ->- indexFile ,-  offset ,-  SEEK_SET );
 
-    fwrite(- position , sizeof(- BookPosition ), 1,-  book ->- indexFile );
 
- } 
-   
- static BookMove loadBookmove(const Book * book, const UINT32 offset) 
- { 
-    BookMove move; 
-   
-    fseek(- book ->- moveFile ,-  offset ,-  SEEK_SET );
 
-    fread(&- move , sizeof(- BookMove ), 1,-  book ->- moveFile );
 
-   
-    return move; 
- } 
-   
- static void storeBookmove(Book * book, const BookMove * move, 
-                           const UINT32 offset) 
- { 
-    fseek(- book ->- moveFile ,-  offset ,-  SEEK_SET );
 
-    fwrite(- move , sizeof(- BookMove ), 1,-  book ->- moveFile );
 
- } 
-   
- void createEmptyBook(Book * book) 
- { 
-    BookPosition position; 
-    int i; 
-   
-    position.hashKey = 0; 
-    position.nextPosition = ILLEGAL_OFFSET; 
-    position.firstMove = ILLEGAL_OFFSET; 
-   
-    for (i = 0; i < BOOKINDEX_SIZE; i++) 
-    { 
-       storeBookposition(book, &position, i * sizeof(BookPosition)); 
-    } 
-   
-    book->numberOfPositions = BOOKINDEX_SIZE; 
-    book->numberOfMoves = 0; 
- } 
-   
- static UINT32 getBookpositionOffset(const Book * book, const UINT64 hashKey) 
- { 
-    UINT32 offset = (UINT32) getBookpositionIndexOffset(hashKey); 
-    BookPosition position = loadBookposition(book, offset); 
-   
-    while (position.hashKey != hashKey && 
-           position.nextPosition != ILLEGAL_OFFSET) 
-    { 
-       offset = position.nextPosition; 
-       position = loadBookposition(book, offset); 
-    } 
-   
-    return (position.hashKey == hashKey && 
-            position.firstMove != ILLEGAL_OFFSET ? offset : ILLEGAL_OFFSET); 
- } 
-   
- static void addBookposition(Book * book, const BookPosition * position) 
- { 
-    UINT32 offset = (UINT32) getBookpositionIndexOffset(position->hashKey); 
-    BookPosition currentPosition = loadBookposition(book, offset); 
-   
-    if (currentPosition.firstMove == ILLEGAL_OFFSET) 
-    { 
-       storeBookposition(book, position, offset); 
-    } 
-    else 
-    { 
-       UINT32 newOffset = book->numberOfPositions++ * sizeof(BookPosition); 
-   
-       storeBookposition(book, position, newOffset); 
-   
-       while (currentPosition.nextPosition != ILLEGAL_OFFSET) 
-       { 
-          offset = currentPosition.nextPosition; 
-          currentPosition = loadBookposition(book, offset); 
-       } 
-   
-       currentPosition.nextPosition = newOffset; 
-       storeBookposition(book, ¤tPosition, offset); 
-    } 
- } 
-   
- static UINT32 getBookmoveOffset(const Book * book, const UINT64 hashKey, 
-                                 const UINT16 move) 
- { 
-    UINT32 offset = getBookpositionOffset(book, hashKey); 
-    BookMove currentMove; 
-   
-    if (offset == ILLEGAL_OFFSET) 
-    { 
-       return ILLEGAL_OFFSET; 
-    } 
-    else 
-    { 
-       BookPosition position = loadBookposition(book, offset); 
-   
-       if (position.firstMove == ILLEGAL_OFFSET) 
-       { 
-          return ILLEGAL_OFFSET; 
-       } 
-       else 
-       { 
-          offset = position.firstMove; 
-          currentMove = loadBookmove(book, offset); 
-       } 
-    } 
-   
-    while (currentMove.move != move && 
-           currentMove.nextAlternative != ILLEGAL_OFFSET) 
-    { 
-       offset = currentMove.nextAlternative; 
-       currentMove = loadBookmove(book, offset); 
-    } 
-   
-    return (currentMove.move == move ? offset : ILLEGAL_OFFSET); 
- } 
-   
- static void appendBookmove(Book * book, const UINT64 hashKey, 
-                            const BookMove * move) 
- { 
-    UINT32 moveOffset = book->numberOfMoves++ * sizeof(BookMove); 
-    UINT32 positionOffset = getBookpositionOffset(book, hashKey); 
-    BookPosition position; 
-   
-    storeBookmove(book, move, moveOffset); 
-   
-    if (positionOffset == ILLEGAL_OFFSET) 
-    { 
-       position.hashKey = hashKey; 
-       position.firstMove = moveOffset; 
-       position.nextPosition = ILLEGAL_OFFSET; 
-       addBookposition(book, &position); 
-    } 
-    else 
-    { 
-       position = loadBookposition(book, positionOffset); 
-   
-       if (position.firstMove == ILLEGAL_OFFSET) 
-       { 
-          position.firstMove = moveOffset; 
-          storeBookposition(book, &position, positionOffset); 
-       } 
-       else 
-       { 
-          UINT32 currentMoveOffset = position.firstMove; 
-          BookMove currentMove = loadBookmove(book, currentMoveOffset); 
-   
-          while (currentMove.nextAlternative != ILLEGAL_OFFSET) 
-          { 
-             currentMoveOffset = currentMove.nextAlternative; 
-             currentMove = loadBookmove(book, currentMoveOffset); 
-          } 
-   
-          currentMove.nextAlternative = moveOffset; 
-          storeBookmove(book, ¤tMove, currentMoveOffset); 
-       } 
-    } 
- } 
-   
- static void updateBookmove(BookMove * move, const Color activeColor, 
-                            const GameResult result, const bool personalResult) 
- { 
-    if (personalResult != FALSE) 
-    { 
-       move->numberOfPersonalGames++; 
-   
-       if (result == RESULT_WHITE_WINS) 
-       { 
-          move->personalScore += (activeColor == WHITE ? 1 : -1); 
-       } 
-       else if (result == RESULT_BLACK_WINS) 
-       { 
-          move->personalScore += (activeColor == BLACK ? 1 : -1); 
-       } 
-    } 
-    else 
-    { 
-       move->numberOfGames++; 
-   
-       if (result == RESULT_WHITE_WINS) 
-       { 
-          move->score += (activeColor == WHITE ? 1 : -1); 
-       } 
-       else if (result == RESULT_BLACK_WINS) 
-       { 
-          move->score += (activeColor == BLACK ? 1 : -1); 
-       } 
-    } 
- } 
-   
- void addBookmove(Book * book, const Position * position, 
-                  const Move move, const GameResult result, 
-                  const bool personalResult) 
- { 
-    BookMove bookMove; 
-    UINT32 bookmoveOffset; 
-   
-    bookMove.move = packedMove(move); 
-    bookmoveOffset = getBookmoveOffset(book, position->hashKey, bookMove.move); 
-   
-    if (bookmoveOffset == ILLEGAL_OFFSET) 
-    { 
-       bookMove.numberOfGames = 0; 
-       bookMove.score = 0; 
-       bookMove.numberOfPersonalGames = 0; 
-       bookMove.personalScore = 0; 
-       bookMove.nextAlternative = ILLEGAL_OFFSET; 
-   
-       updateBookmove(&bookMove, position->activeColor, result, 
-                      personalResult); 
-       appendBookmove(book, position->hashKey, &bookMove); 
-    } 
-    else 
-    { 
-       bookMove = loadBookmove(book, bookmoveOffset); 
-   
-       updateBookmove(&bookMove, position->activeColor, result, 
-                      personalResult); 
-       storeBookmove(book, &bookMove, bookmoveOffset); 
-    } 
- } 
-   
- static void appendBookGame(Book * book, const PGNGame * game, 
-                            const int maximumNumberOfPlies) 
- { 
-    Gamemove *currentMove = game->firstMove; 
-    int plycount = 0; 
-    GameResult result = RESULT_UNKNOWN; 
-   
-    if (strcmp(- game ->- result ,-  GAMERESULT_WHITE_WINS ) == 0)
 
-    { 
-       result = RESULT_WHITE_WINS; 
-    } 
-   
-    if (strcmp(- game ->- result ,-  GAMERESULT_DRAW ) == 0)
 
-    { 
-       result = RESULT_DRAW; 
-    } 
-   
-    if (strcmp(- game ->- result ,-  GAMERESULT_BLACK_WINS ) == 0)
 
-    { 
-       result = RESULT_BLACK_WINS; 
-    } 
-   
-    if (- result  ==-  RESULT_UNKNOWN  || strcmp(- game ->- setup , "1") == 0)
 
-    { 
-       logDebug("Skipping book game %s-%s.\n", game->white, game->black); 
-   
-       return; 
-    } 
-   
-    while (plycount++ < maximumNumberOfPlies && currentMove != 0) 
-    { 
-       addBookmove(book, ¤tMove->position, 
-                   gameMove2Move(currentMove), result, FALSE); 
-       currentMove = currentMove->nextMove; 
-    } 
- } 
-   
- void appendBookDatabase(Book * book, const char *filename, 
-                         int maximumNumberOfPlies) 
- { 
-    PGNFile pgnfile; 
-    PGNGame *game; 
-    long i; 
-   
-    if (openPGNFile(&pgnfile, filename) != 0) 
-    { 
-       return; 
-    } 
-   
-    logReport("\nProcessing book file '%s' [%ld game(s)]\n", filename, 
-              pgnfile.numGames); 
-   
-    for (i = 1; i <= pgnfile.numGames; i++) 
-    { 
-       game = getGame(&pgnfile, i); 
-       logReport("Processing book game #%ld.\n", i); 
-       appendBookGame(book, game, maximumNumberOfPlies); 
-       freePgnGame(game); 
-    } 
-   
-    closePGNFile(&pgnfile); 
- } 
-   
- static int getSuccessProbability(UINT16 numGames, INT16 score) 
- { 
-    int result; 
-   
-    if (numGames == 0) 
-    { 
-       return 0; 
-    } 
-   
-    result = (50 * (long) (numGames + score)) / (long) numGames; 
-   
-    assert(- result  >= 0 &&-  result  <= 100);
 
-   
-    return result; 
- } 
-   
- static int getBookmoveValue(const BookMove * move, const UINT32 numberOfGames) 
- { 
-    const int weightGames = 10, weightPersonalGames = 1; 
-    int successProbability, personalSuccessProbability, moveProbability; 
-   
-    successProbability = 
-       getSuccessProbability(move->numberOfGames, move->score); 
-    personalSuccessProbability = 
-       getSuccessProbability(move->numberOfPersonalGames, move->personalScore); 
-    moveProbability = (move->numberOfGames * 100) / numberOfGames; 
-   
-    successProbability = (successProbability * weightGames + 
-                          personalSuccessProbability * weightPersonalGames) / 
-       (weightGames + weightPersonalGames); 
-   
-    return successProbability * moveProbability; 
- } 
-   
- void getBookmoves(const Book * book, const UINT64 hashKey, 
-                   const Movelist * legalMoves, Movelist * bookMoves) 
- { 
-    UINT32 positionOffset = getBookpositionOffset(book, hashKey), moveOffset; 
-    BookPosition position; 
-    BookMove bookMove, bookMoveStore[MAX_MOVES_PER_POSITION]; 
-    UINT32 numberOfGames = 0; 
-    int i; 
-   
-    bookMoves->numberOfMoves = 0; 
-   
-    if (positionOffset == ILLEGAL_OFFSET) 
-    { 
-       return; 
-    } 
-   
-    position = loadBookposition(book, positionOffset); 
-    moveOffset = position.firstMove; 
-   
-    while (moveOffset != ILLEGAL_OFFSET) 
-    { 
-       Move move; 
-   
-       bookMove = loadBookmove(book, moveOffset); 
-       move = (Move) bookMove.move; 
-   
-       if (listContainsMove(legalMoves, move)) 
-       { 
-          numberOfGames += bookMove.numberOfGames; 
-          bookMoveStore[bookMoves->numberOfMoves] = bookMove; 
-          bookMoves->moves[bookMoves->numberOfMoves++] = move; 
-       } 
-   
-       moveOffset = bookMove.nextAlternative; 
-    } 
-   
-    for (i = 0; i < bookMoves->numberOfMoves; i++) 
-    { 
-       const int value = 
-          max(1, getBookmoveValue(&bookMoveStore[i], numberOfGames)); 
-   
-       setMoveValue(&bookMoves->moves[i], value); 
-    } 
- } 
-   
- static Move chooseBookmove(const Movelist * bookMoves) 
- { 
-    int i; 
-    UINT32 randomNumber, sum = 0; 
-   
-    for (i = 0; i < bookMoves->numberOfMoves; i++) 
-    { 
-       sum += getMoveValue(bookMoves->moves[i]); 
-    } 
-   
-    srand((unsigned int) (- getTimestamp () + time(0)));
 
-    randomNumber  = ((- UINT32 ) rand() * (- UINT32 ) rand() + (- UINT32 ) rand()) %-  sum ;
-   
-    logDebug("dumping bookmove list...\n"); 
-    dumpMovelist(bookMoves); 
-    logDebug("sum: %lu random: %lu\n", sum, randomNumber); 
-   
-    sum = 0; 
-   
-    for (i = 0; i < bookMoves->numberOfMoves; i++) 
-    { 
-       sum += getMoveValue(bookMoves->moves[i]); 
-   
-       if (sum > randomNumber) 
-       { 
-          return bookMoves->moves[i]; 
-       } 
-    } 
-   
-    return bookMoves->moves[bookMoves->numberOfMoves - 1]; 
- } 
-   
- Move getBookmove(const Book * book, const UINT64 hashKey, 
-                  const Movelist * legalMoves) 
- { 
-    Movelist bookMoves; 
-    Move move = NO_MOVE; 
-   
-    if (book->indexFile != 0 && book->moveFile != 0 && 
-        book->numberOfPositions > 0 && book->numberOfMoves > 0) 
-    { 
-       initMovelist(&bookMoves, 0); 
-       getBookmoves(book, hashKey, legalMoves, &bookMoves); 
-   
-       if (bookMoves.numberOfMoves > 0) 
-       { 
-          logDebug("%d bookmoves available. choosing bookmove...\n", 
-                   bookMoves.numberOfMoves); 
-   
-          move = chooseBookmove(&bookMoves); 
-   
-          logDebug("chose bookmove %d-%d\n", getFromSquare(move), 
-                   getToSquare(move)); 
-       } 
-    } 
-   
-    return move; 
- } 
-   
- int initializeModuleBook() 
- { 
-    if (openBook(&globalBook, "book") < 0) 
-    { 
-       logDebug("No opening book available.\n"); 
-    } 
-    else 
-    { 
-       logDebug("Opening book found. %ld positions, %ld moves\n", 
-                globalBook.numberOfPositions, globalBook.numberOfMoves); 
-    } 
-   
-    return 0; 
- } 
-   
- static int testPositionOperations() 
- { 
-    Book book; 
-    UINT64 hashKey = BOOKINDEX_SIZE + 100; 
-    BookPosition position; 
-   
-    position.hashKey = hashKey; 
-    position.nextPosition = ILLEGAL_OFFSET; 
-    position.firstMove = 0; 
-   
-    openBook(&book, "moduletest"); 
-    createEmptyBook(&book); 
-   
-    assert(- getBookpositionOffset (&- book ,-  hashKey ) ==-  ILLEGAL_OFFSET );
 
-    addBookposition(&book, &position); 
-    assert(- getBookpositionOffset (&- book ,-  hashKey ) ==
 
-           getBookpositionIndexOffset(hashKey)); 
-    position.hashKey += BOOKINDEX_SIZE; 
-    addBookposition(&book, &position); 
-    assert(- getBookpositionOffset (&- book ,-  position. hashKey) ==
 
-           BOOKINDEX_SIZE * sizeof(BookPosition)); 
-   
-    closeBook(&book); 
-   
-    return 0; 
- } 
-   
- static int testMoveOperations() 
- { 
-    Book book; 
-    UINT64 hashKey = 4711; 
-    BookMove move; 
-   
-    openBook(&book, "moduletest"); 
-    createEmptyBook(&book); 
-   
-    move.move = 7; 
-    assert(- getBookmoveOffset (&- book ,-  hashKey ,-  move. move) ==-  ILLEGAL_OFFSET );
 
-    move.move = 17; 
-    move.nextAlternative = ILLEGAL_OFFSET; 
-    appendBookmove(&book, hashKey, &move); 
-    assert(- getBookmoveOffset (&- book ,-  hashKey ,-  move. move) ==
 
-           0 * sizeof(BookMove)); 
-    move.move = 19; 
-    appendBookmove(&book, hashKey, &move); 
-    assert(- getBookmoveOffset (&- book ,-  hashKey ,-  move. move) ==
 
-           1 * sizeof(BookMove)); 
-   
-    hashKey += 160939; 
-    assert(- getBookmoveOffset (&- book ,-  hashKey ,-  move. move) ==-  ILLEGAL_OFFSET );
 
-    appendBookmove(&book, hashKey, &move); 
-    assert(- getBookmoveOffset (&- book ,-  hashKey ,-  move. move) ==
 
-           2 * sizeof(BookMove)); 
-   
-    closeBook(&book); 
-   
-    return 0; 
- } 
-   
- int testModuleBook() 
- { 
-    int result; 
-   
-    if ((result = testPositionOperations()) != 0) 
-    { 
-       return result; 
-    } 
-   
-    if ((result = testMoveOperations()) != 0) 
-    { 
-       return result; 
-    } 
-   
-    return 0; 
- } 
-