| 
					
				 | 
			
			
				@@ -1,4 +1,7 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "ChessGame.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "Util.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include <sstream> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include <stdexcept> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -14,6 +17,7 @@ MoveInfo::MoveInfo(Move move, const ChessGame& cg) : 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ChessGame::ChessGame(void) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     board.resetBoard(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    hash = zobrist::getHash(*this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -23,19 +27,6 @@ ChessGame::ChessGame(const std::string& fenString) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-bool ChessGame::isValidMove(const Move& move) const 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-std::vector<Move> ChessGame::getValidMoves(void) const 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    std::vector<Move> ret; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    return ret; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 void ChessGame::move(Move move) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     MoveInfo mi; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -73,25 +64,26 @@ void ChessGame::loadFromFen(const std::string& fenString) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     else throw runtime_error("invalid turn "s + turn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     castlingRights = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (castling != "-") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (castling != "-") { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         for (auto character : castling) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             switch (character) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                case 'k': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    setCanCastleKingSide(WHITE_SIDE, true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                case 'q': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    setCanCastleQueenSide(WHITE_SIDE, true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                case 'K': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    setCanCastleKingSide(BLACK_SIDE, true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                case 'Q': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    setCanCastleQueenSide(BLACK_SIDE, true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    throw runtime_error("invalid castling right: "s + character); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            case 'k': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                setCanCastleKingSide(WHITE_SIDE, true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            case 'q': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                setCanCastleQueenSide(WHITE_SIDE, true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            case 'K': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                setCanCastleKingSide(BLACK_SIDE, true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            case 'Q': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                setCanCastleQueenSide(BLACK_SIDE, true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                throw runtime_error("invalid castling right: "s + character); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (enPassant == "-"s) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         this->enPassant = -1; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -99,7 +91,7 @@ void ChessGame::loadFromFen(const std::string& fenString) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if (enPassant.size() != 2 || (enPassant[1] != '3' && enPassant[1] != '6')) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             throw runtime_error("invalid en passant string: "s + enPassant); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        this->enPassant = Index{ enPassant }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this->enPassant = Index{ enPassant }.getColumn(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     try { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -115,6 +107,8 @@ void ChessGame::loadFromFen(const std::string& fenString) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     catch(...) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         throw runtime_error("invalid number of moves: "s + halfmoves); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    hash = zobrist::getHash(*this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -139,7 +133,7 @@ std::string ChessGame::generateFen(void) const 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         enPassant = "-"s; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        enPassant = this->enPassant.getName(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        enPassant = Index{ this->turn == WHITE_SIDE ? 3 : 5, this->enPassant }.getName(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     string halfmoves = to_string(reversibleHalfMoves); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -152,68 +146,88 @@ std::string ChessGame::generateFen(void) const 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 UndoInfo ChessGame::doMove(const MoveInfo& mi) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    UndoInfo ui; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert(hash == zobrist::getHash(*this)); // valid zobrist hash 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    UndoInfo ui; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ui.hash = hash; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     // adjust castling rights 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ui.castlingRights = castlingRights; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    hash ^= zobrist::castlingRights[castlingRights]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (mi.movedPiece == KING) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         setCanCastleKingSide(turn, false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         setCanCastleQueenSide(turn, false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    hash ^= zobrist::castlingRights[castlingRights]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     // update possible en-passant moves 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ui.enPassantBefore = enPassant; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (enPassant != -1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hash ^= zobrist::enPassant[enPassant]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (mi.movedPiece == PAWN && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        std::abs(mi.move.destination.getRow() - mi.move.destination.getRow()) == 2) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        std::abs(mi.move.origin.getRow() - mi.move.destination.getRow()) == 2) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         enPassant = mi.move.origin.getRow(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         enPassant = -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (enPassant != -1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hash ^= zobrist::enPassant[enPassant]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ui.type = mi.movedPiece; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     Bitboard& b = board.getBitboards(turn)[ui.type]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ui.before = b; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     Bitboard target = Bitboard::fromIndex(mi.move.destination); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    hash ^= zobrist::get(mi.movedPiece, turn, mi.move.origin); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     b ^= Bitboard::fromIndex(mi.move.origin); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (mi.move.promotion == PAWN) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         b |= target; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hash ^= zobrist::get(mi.movedPiece, turn, mi.move.destination); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         ui.promotion = PAWN; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         ui.promotion = mi.move.promotion; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         ui.promotionBefore = board.getBitboards(turn)[ui.promotion]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         board.getBitboards(turn)[ui.promotion] |= target; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hash ^= zobrist::get(ui.promotion, turn, mi.move.destination); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (mi.move.isEnPassant) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int asas = 4; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ui.captured = PieceType::EMPTY; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (mi.move.isEnPassant) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         target = Bitboard::fromIndex(Index{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            turn == WHITE_SIDE ? 5 : 2, mi.move.destination.getColumn() }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            turn == WHITE_SIDE ? 4 : 3, mi.move.destination.getColumn() }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     for (int i = 0; i < 6; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         Bitboard& e = board.getBitboards(otherSide(turn))[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if (target & e) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             ui.captured = static_cast<PieceType>(i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             ui.beforeCaptured = e; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             e ^= target; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            hash ^= zobrist::get(ui.captured, otherSide(turn), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                target.getLeastSignificantBit()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     turn = otherSide(turn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    hash ^= zobrist::turn; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     moveCount++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ui.reversibleHalfMoves = reversibleHalfMoves; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if(mi.movedPiece != PAWN && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             board.getAtPosition(mi.move.destination) != EMPTY) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         reversibleHalfMoves++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert(hash == zobrist::getHash(*this)); // valid zobrist hash 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return ui; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 void ChessGame::undoMove(const UndoInfo& ui) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert(hash == zobrist::getHash(*this)); // valid zobrist hash 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     turn = otherSide(turn); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     Bitboard& b = board.getBitboards(turn)[ui.type]; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -222,9 +236,13 @@ void ChessGame::undoMove(const UndoInfo& ui) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         board.getBitboards(otherSide(turn))[ui.captured] = ui.beforeCaptured; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (ui.promotion != PieceType::PAWN) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         board.getBitboards(turn)[ui.promotion] = ui.promotionBefore; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     moveCount--; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     reversibleHalfMoves = ui.reversibleHalfMoves; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     castlingRights = ui.castlingRights; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     enPassant = ui.enPassantBefore; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    hash = ui.hash; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert(hash == zobrist::getHash(*this)); // valid zobrist hash 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 |