- /* 
-     Texel - A UCI chess engine. 
-     Copyright (C) 2012-2014  Peter Ă–sterlund, peterosterlund2@gmail.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/>. 
- */ 
-   
- /* 
-  * game.cpp 
-  * 
-  *  Created on: Feb 25, 2012 
-  *      Author: petero 
-  */ 
-   
- #include "game.hpp" 
- #include "moveGen.hpp" 
- #include "textio.hpp" 
- #include "util/timeUtil.hpp" 
-   
- #include <iostream> 
- #include <iomanip> 
- #include <cassert> 
-   
-   
- Game::Game(const std::shared_ptr<Player>& whitePlayer, 
-            const std::shared_ptr<Player>& blackPlayer) { 
-     this->whitePlayer = whitePlayer; 
-     this->blackPlayer = blackPlayer; 
-     handleCommand("new"); 
- } 
-   
- bool 
- Game::processString(const std::string& str) { 
-     if (handleCommand(str)) 
-         return true; 
-     if (getGameState() != ALIVE) 
-         return false; 
-   
-     Move m = TextIO::stringToMove(pos, str); 
-     if (m.isEmpty()) 
-         return false; 
-   
-     UndoInfo ui; 
-     pos.makeMove(m, ui); 
-     TextIO::fixupEPSquare(pos); 
-     if (currentMove < (int)moveList.size()) { 
-         moveList.erase(moveList.begin() + currentMove, moveList.end()); 
-         uiInfoList.erase(uiInfoList.begin() + currentMove, uiInfoList.end()); 
-         drawOfferList.erase(drawOfferList.begin() + currentMove, drawOfferList.end()); 
-     } 
-     moveList.push_back(m); 
-     uiInfoList.push_back(ui); 
-     drawOfferList.push_back(pendingDrawOffer); 
-     pendingDrawOffer = false; 
-     currentMove++; 
-     return true; 
- } 
-   
- std::string 
- Game::getGameStateString() { 
-     switch (getGameState()) { 
-     case ALIVE: 
-         return ""; 
-     case WHITE_MATE: 
-         return "Game over, white mates!"; 
-     case BLACK_MATE: 
-         return "Game over, black mates!"; 
-     case WHITE_STALEMATE: 
-     case BLACK_STALEMATE: 
-         return "Game over, draw by stalemate!"; 
-     case DRAW_REP: 
-     { 
-         std::string ret = "Game over, draw by repetition!"; 
-         if (drawStateMoveStr.length() > 0) 
-             ret += " [" + drawStateMoveStr + "]"; 
-         return ret; 
-     } 
-     case DRAW_50: 
-     { 
-         std::string ret = "Game over, draw by 50 move rule!"; 
-         if (drawStateMoveStr.length() > 0) 
-             ret += " [" + drawStateMoveStr + "]"; 
-         return ret; 
-     } 
-     case DRAW_NO_MATE: 
-         return "Game over, draw by impossibility of mate!"; 
-     case DRAW_AGREE: 
-         return "Game over, draw by agreement!"; 
-     case RESIGN_WHITE: 
-         return "Game over, white resigns!"; 
-     case RESIGN_BLACK: 
-         return "Game over, black resigns!"; 
-     default: 
-         assert(false); 
-         return ""; 
-     } 
- } 
-   
- Move 
- Game::getLastMove() { 
-     Move m; 
-     if (currentMove > 0) 
-         m = moveList[currentMove - 1]; 
-     return m; 
- } 
-   
- Game::GameState 
- Game::getGameState() { 
-     MoveList moves; 
-     MoveGen::pseudoLegalMoves(pos, moves); 
-     MoveGen::removeIllegal(pos, moves); 
-     if (moves.size == 0) { 
-         if (MoveGen::inCheck(pos)) 
-             return pos.isWhiteMove() ? BLACK_MATE : WHITE_MATE; 
-         else 
-             return pos.isWhiteMove() ? WHITE_STALEMATE : BLACK_STALEMATE; 
-     } 
-     if (insufficientMaterial()) 
-         return DRAW_NO_MATE; 
-     if (resignState != ALIVE) 
-         return resignState; 
-     return drawState; 
- } 
-   
- bool 
- Game::haveDrawOffer() { 
-     if (currentMove > 0) 
-         return drawOfferList[currentMove - 1]; 
-     else 
-         return false; 
- } 
-   
- bool 
- Game::handleCommand(const std::string& moveStr) { 
-     if (moveStr == "new") { 
-         moveList.clear(); 
-         uiInfoList.clear(); 
-         drawOfferList.clear(); 
-         currentMove = 0; 
-         pendingDrawOffer = false; 
-         drawState = ALIVE; 
-         resignState = ALIVE; 
-         pos = TextIO::readFEN(TextIO::startPosFEN); 
-         whitePlayer->clearTT(); 
-         blackPlayer->clearTT(); 
-         activateHumanPlayer(); 
-         return true; 
-     } else if (moveStr == "undo") { 
-         if (currentMove > 0) { 
-             pos.unMakeMove(moveList[currentMove - 1], uiInfoList[currentMove - 1]); 
-             currentMove--; 
-             pendingDrawOffer = false; 
-             drawState = ALIVE; 
-             resignState = ALIVE; 
-             return handleCommand("swap"); 
-         } else { 
-             std::cout << "Nothing to undo" << std::endl; 
-         } 
-         return true; 
-     } else if (moveStr == "redo") { 
-         if (currentMove < (int)moveList.size()) { 
-             pos.makeMove(moveList[currentMove], uiInfoList[currentMove]); 
-             currentMove++; 
-             pendingDrawOffer = false; 
-             return handleCommand("swap"); 
-         } else { 
-             std::cout << "Nothing to redo" << std::endl; 
-         } 
-         return true; 
-     } else if (moveStr == "swap" || moveStr == "go") { 
-         std::swap(whitePlayer, blackPlayer); 
-         return true; 
-     } else if (moveStr == "list") { 
-         listMoves(); 
-         return true; 
-     } else if (startsWith(moveStr, "setpos ")) { 
-         std::string fen = moveStr.substr(moveStr.find_first_of(' ') + 1); 
-         try { 
-             Position newPos(TextIO::readFEN(fen)); 
-             handleCommand("new"); 
-             pos = newPos; 
-             activateHumanPlayer(); 
-         } catch (const ChessParseError& ex) { 
-             std::cout << "Invalid FEN: " << fen << " (" << ex.what() << ")" << std::endl; 
-         } 
-         return true; 
-     } else if (moveStr == "getpos") { 
-         std::string fen(TextIO::toFEN(pos)); 
-         std::cout << fen << std::endl; 
-         return true; 
-     } else if (startsWith(moveStr, "draw ")) { 
-         if (getGameState() == ALIVE) { 
-             std::string drawCmd = moveStr.substr(moveStr.find_first_of(' ') + 1); 
-             return handleDrawCmd(drawCmd); 
-         } else { 
-             return true; 
-         } 
-     } else if (moveStr == "resign") { 
-         if (getGameState()== ALIVE) { 
-             resignState = pos.isWhiteMove() ? RESIGN_WHITE : RESIGN_BLACK; 
-             return true; 
-         } else { 
-             return true; 
-         } 
-     } else if (startsWith(moveStr, "book")) { 
-         std::string bookCmd = moveStr.substr(moveStr.find_first_of(' ') + 1); 
-         return handleBookCmd(bookCmd); 
-     } else if (startsWith(moveStr, "time")) { 
-         std::string timeStr = moveStr.substr(moveStr.find_first_of(' ') + 1); 
-         int timeLimit; 
-         if (!str2Num(timeStr, timeLimit)) { 
-             std::cout << "Can not parse number: " << timeStr << std::endl; 
-             return false; 
-         } 
-         whitePlayer->timeLimit(timeLimit, timeLimit); 
-         blackPlayer->timeLimit(timeLimit, timeLimit); 
-         return true; 
-     } else if (startsWith(moveStr, "perft ")) { 
-         std::string depthStr = moveStr.substr(moveStr.find_first_of(' ') + 1); 
-         int depth; 
-         if (!str2Num(depthStr, depth)) { 
-             std::cout << "Can not parse number: " << depthStr << std::endl; 
-             return false; 
-         } 
-         S64 t0 = currentTimeMillis(); 
-         U64 nodes = perfT(pos, depth); 
-         S64 t1 = currentTimeMillis(); 
-         double t = (t1 - t0) * 1e-3; 
-         std::stringstream ss; 
-         ss.precision(3); 
-         std::cout << "perft(" << depth << ") = " << nodes << ", t=" 
-                   << (ss << std::fixed << t).rdbuf() 
-                   << "s" << std::endl; 
-         return true; 
-     } else { 
-         return false; 
-     } 
- } 
-   
- void 
- Game::activateHumanPlayer() { 
-     if (!(pos.isWhiteMove() ? whitePlayer : blackPlayer)->isHumanPlayer()) 
-         std::swap(whitePlayer, blackPlayer); 
- } 
-   
- void 
- Game::getPosHistory(std::vector<std::string> ret) { 
-     ret.clear(); 
-     Position pos(this->pos); 
-     for (int i = currentMove; i > 0; i--) 
-         pos.unMakeMove(moveList[i - 1], uiInfoList[i - 1]); 
-     ret.push_back(TextIO::toFEN(pos)); // Store initial FEN 
-   
-     std::string moves; 
-     UndoInfo ui; 
-     for (size_t i = 0; i < moveList.size(); i++) { 
-         const Move& move = moveList[i]; 
-         std::string strMove(TextIO::moveToString(pos, move, false)); 
-         moves += ' '; 
-         moves += strMove; 
-         pos.makeMove(move, ui); 
-     } 
-     ret.push_back(moves); // Store move list string 
-   
-     int numUndo = (int)moveList.size() - currentMove; 
-     ret.push_back(num2Str(numUndo)); 
- } 
-   
- std::string 
- Game::getMoveListString(bool compressed) { 
-     std::string ret; 
-   
-     // Undo all moves in move history. 
-     Position pos(this->pos); 
-     for (int i = currentMove; i > 0; i--) 
-         pos.unMakeMove(moveList[i - 1], uiInfoList[i - 1]); 
-   
-     // Print all moves 
-     std::string whiteMove; 
-     std::string blackMove; 
-     for (int i = 0; i < currentMove; i++) { 
-         const Move& move = moveList[i]; 
-         std::string strMove = TextIO::moveToString(pos, move, false); 
-         if (drawOfferList[i]) 
-             strMove += " (d)"; 
-         if (pos.isWhiteMove()) { 
-             whiteMove = strMove; 
-         } else { 
-             blackMove = strMove; 
-             if (whiteMove.length() == 0) 
-                 whiteMove = "..."; 
-             if (compressed) { 
-                 ret += num2Str(pos.getFullMoveCounter()) + ". " + whiteMove + 
-                        " " + blackMove + " "; 
-             } else { 
-                 std::stringstream ss; 
-                 ss << std::setw(3) << pos.getFullMoveCounter() << ".  " 
-                    << std::setw(10) << std::left << whiteMove << " " 
-                    << std::setw(10) << std::left << blackMove << std::endl; 
-                 ret += ss.str(); 
-             } 
-             whiteMove.clear(); 
-             blackMove.clear(); 
-         } 
-         UndoInfo ui; 
-         pos.makeMove(move, ui); 
-     } 
-     if ((whiteMove.length() > 0) || (blackMove.length() > 0)) { 
-         if (whiteMove.length() == 0) 
-             whiteMove = "..."; 
-         if (compressed) { 
-             ret += num2Str(pos.getFullMoveCounter()) + ". " + whiteMove + 
-                    " " + blackMove + " "; 
-         } else { 
-             std::stringstream ss; 
-             ss << std::setw(3) << pos.getFullMoveCounter() << ".  " 
-                << std::setw(10) << std::left << whiteMove << " " 
-                << std::setw(10) << std::left << blackMove << std::endl; 
-             ret += ss.str(); 
-         } 
-     } 
-     std::string gameResult = getPGNResultString(); 
-     if (gameResult != "*") { 
-         ret += gameResult; 
-         if (!compressed) 
-             ret += '\n'; 
-     } 
-     return ret; 
- } 
-   
- std::string 
- Game::getPGNResultString() { 
-     std::string gameResult = "*"; 
-     switch (getGameState()) { 
-     case ALIVE: 
-         break; 
-     case WHITE_MATE: 
-     case RESIGN_BLACK: 
-         gameResult = "1-0"; 
-         break; 
-     case BLACK_MATE: 
-     case RESIGN_WHITE: 
-         gameResult = "0-1"; 
-         break; 
-     case WHITE_STALEMATE: 
-     case BLACK_STALEMATE: 
-     case DRAW_REP: 
-     case DRAW_50: 
-     case DRAW_NO_MATE: 
-     case DRAW_AGREE: 
-         gameResult = "1/2-1/2"; 
-         break; 
-     } 
-     return gameResult; 
- } 
-   
- /** Return a list of previous positions in this game, back to the last "zeroing" move. */ 
- void 
- Game::getHistory(std::vector<Position>& posList) { 
-     posList.clear(); 
-     Position pos(this->pos); 
-     for (int i = currentMove; i > 0; i--) { 
-         if (pos.getHalfMoveClock() == 0) 
-             break; 
-         pos.unMakeMove(moveList[i - 1], uiInfoList[i - 1]); 
-         posList.push_back(pos); 
-     } 
-     std::reverse(posList.begin(), posList.end()); 
- } 
-   
- void 
- Game::listMoves() { 
-     std::string movesStr = getMoveListString(false); 
-     std::cout << movesStr; 
- } 
-   
- bool 
- Game::handleDrawCmd(std::string drawCmd) { 
-     if (startsWith(drawCmd, "rep") || startsWith(drawCmd, "50")) { 
-         bool rep = startsWith(drawCmd, "rep"); 
-         Move m; 
-         size_t idx = drawCmd.find_first_of(' '); 
-         std::string ms; 
-         if (idx != drawCmd.npos) { 
-             ms = drawCmd.substr(idx + 1); 
-             if (ms.length() > 0) 
-                 m = TextIO::stringToMove(pos, ms); 
-         } 
-         bool valid; 
-         if (rep) { 
-             valid = false; 
-             std::vector<Position> oldPositions; 
-             if (!m.isEmpty()) { 
-                 UndoInfo ui; 
-                 Position tmpPos(pos); 
-                 tmpPos.makeMove(m, ui); 
-                 oldPositions.push_back(tmpPos); 
-             } 
-             oldPositions.push_back(pos); 
-             Position tmpPos(pos); 
-             for (int i = currentMove - 1; i >= 0; i--) { 
-                 tmpPos.unMakeMove(moveList[i], uiInfoList[i]); 
-                 oldPositions.push_back(tmpPos); 
-             } 
-             int repetitions = 0; 
-             Position firstPos = oldPositions[0]; 
-             for (size_t i = 0; i < oldPositions.size(); i++) { 
-                 if (oldPositions[i].drawRuleEquals(firstPos)) 
-                     repetitions++; 
-             } 
-             if (repetitions >= 3) { 
-                 valid = true; 
-             } 
-         } else { 
-             Position tmpPos(pos); 
-             if (!m.isEmpty()) { 
-                 UndoInfo ui; 
-                 tmpPos.makeMove(m, ui); 
-             } 
-             valid = tmpPos.getHalfMoveClock() >= 100; 
-         } 
-         if (valid) { 
-             drawState = rep ? DRAW_REP : DRAW_50; 
-             drawStateMoveStr.clear(); 
-             if (!m.isEmpty()) 
-                 drawStateMoveStr = TextIO::moveToString(pos, m, false); 
-         } else { 
-             pendingDrawOffer = true; 
-             if (!m.isEmpty()) 
-                 processString(ms); 
-         } 
-         return true; 
-     } else if (startsWith(drawCmd, "offer ")) { 
-         pendingDrawOffer = true; 
-         size_t idx = drawCmd.find_first_of(' '); 
-         if (idx != drawCmd.npos) { 
-             std::string ms = drawCmd.substr(idx + 1); 
-             if (!TextIO::stringToMove(pos, ms).isEmpty()) 
-                 processString(ms); 
-         } 
-         return true; 
-     } else if (drawCmd == "accept") { 
-         if (haveDrawOffer()) 
-             drawState = DRAW_AGREE; 
-         return true; 
-     } else { 
-         return false; 
-     } 
- } 
-   
- bool 
- Game::handleBookCmd(const std::string& bookCmd) { 
-     if (bookCmd == "off") { 
-         whitePlayer->useBook(false); 
-         blackPlayer->useBook(false); 
-         return true; 
-     } else if (bookCmd == "on") { 
-         whitePlayer->useBook(true); 
-         whitePlayer->useBook(true); 
-         return true; 
-     } 
-     return false; 
- } 
-   
- bool 
- Game::insufficientMaterial() { 
-     if (pos.pieceTypeBB(Piece::WQUEEN) != 0) return false; 
-     if (pos.pieceTypeBB(Piece::WROOK)  != 0) return false; 
-     if (pos.pieceTypeBB(Piece::WPAWN)  != 0) return false; 
-     if (pos.pieceTypeBB(Piece::BQUEEN) != 0) return false; 
-     if (pos.pieceTypeBB(Piece::BROOK)  != 0) return false; 
-     if (pos.pieceTypeBB(Piece::BPAWN)  != 0) return false; 
-     int wb = BitBoard::bitCount(pos.pieceTypeBB(Piece::WBISHOP)); 
-     int wn = BitBoard::bitCount(pos.pieceTypeBB(Piece::WKNIGHT)); 
-     int bb = BitBoard::bitCount(pos.pieceTypeBB(Piece::BBISHOP)); 
-     int bn = BitBoard::bitCount(pos.pieceTypeBB(Piece::BKNIGHT)); 
-     if (wb + wn + bb + bn <= 1) 
-         return true;    // King + bishop/knight vs king is draw 
-     if (wn + bn == 0) { 
-         // Only bishops. If they are all on the same color, the position is a draw. 
-         U64 bMask = pos.pieceTypeBB(Piece::WBISHOP) | pos.pieceTypeBB(Piece::BBISHOP); 
-         if (((bMask & BitBoard::maskDarkSq) == 0) || 
-                 ((bMask & BitBoard::maskLightSq) == 0)) 
-             return true; 
-     } 
-     return false; 
- } 
-   
- U64 
- Game::perfT(Position& pos, int depth) { 
-     if (depth == 0) 
-         return 1; 
-     U64 nodes = 0; 
-     MoveList moves; 
-     MoveGen::pseudoLegalMoves(pos, moves); 
-     MoveGen::removeIllegal(pos, moves); 
-     if (depth == 1) 
-         return moves.size; 
-     UndoInfo ui; 
-     for (int mi = 0; mi < moves.size; mi++) { 
-         const Move& m = moves[mi]; 
-         pos.makeMove(m, ui); 
-         nodes += perfT(pos, depth - 1); 
-         pos.unMakeMove(m, ui); 
-     } 
-     return nodes; 
- } 
-