public bool contains(move toAdd, int depth) { List<List<bool>> thisDepth = _killerMovesAtDepth[depth]; List<bool> fromThisSq = thisDepth[toAdd.dstPos.flatten()]; return fromThisSq[toAdd.dstPos.flatten()]; }
public void testQueensideCastlingNotation() { DoktorChessAIBoard ourBoard = new DoktorChessAIBoard(gameType.normal, boardSearchConfig.getDebugConfig()); square ourKing = ourBoard.addPiece(pieceType.king, pieceColour.white, 4, 0); ourBoard.addPiece(pieceType.rook, pieceColour.white, 0, 0); move theMove = new move(ourKing, new square(2, 0)); Assert.AreEqual("O-O-O", theMove.ToString(moveStringStyle.chessNotation)); }
public void add(int depth, move toAdd) { if (contains(toAdd, depth)) return; List<List<bool>> thisDepth = _killerMovesAtDepth[depth]; List<bool> fromThisSq = thisDepth[toAdd.dstPos.flatten()]; fromThisSq[toAdd.dstPos.flatten()] = true; }
public void testPieceMoveNotation() { DoktorChessAIBoard ourBoard = new DoktorChessAIBoard(gameType.normal, boardSearchConfig.getDebugConfig()); square bish = new bishopSquare(new squarePos(0, 0), pieceColour.black); square targetSpace = new square( new squarePos(0, 1) ); move theMove = new move(bish, targetSpace); Assert.AreEqual("Ba2", theMove.ToString(moveStringStyle.chessNotation)); }
public void testKingsideCastlingMoveIsExecutedCorrectly() { DoktorChessAIBoard ourBoard = new DoktorChessAIBoard(gameType.normal, boardSearchConfig.getDebugConfig()); square ourKing = ourBoard.addPiece(pieceType.king, pieceColour.white, 4, 0); square ourRook = ourBoard.addPiece(pieceType.rook, pieceColour.white, 7, 0); ourBoard.addPiece(pieceType.king, pieceColour.black, 0, 0); // Make our castling move.. move castlingMove = new move(ourKing, ourBoard[6, 0]); ourBoard.doMove(castlingMove); // Verify that the rook and king have both moved to their correct squares. Assert.IsTrue(ourBoard[6, 0] == ourKing); Assert.IsTrue(ourBoard[5, 0] == ourRook); }
public void verifyMoveConstructorWithCapture() { // Make two occupied squares and construct a move from one to the other. Test // that the capture is correctly propagated to the move. square src = new pawnSquare(new squarePos(1, 1), pieceColour.black); square dst = new pawnSquare(new squarePos(2, 1), pieceColour.white); move captureMove = new move(src, dst); // First, check that the move has the correct squares associated with it.. Assert.IsTrue(captureMove.srcPos.isSameSquareAs(src.position)); Assert.IsTrue(captureMove.dstPos.isSameSquareAs(dst.position)); Assert.IsTrue(captureMove.isCapture); Assert.IsTrue(captureMove.capturedSquare == dst); }
public void initFromMove(move initWith) { movedPieceSrc = initWith.srcPos; movedPieceDst = initWith.dstPos; // If this is an en passant capture, we need to express that the capture square is not the dest. if (initWith.capturedSquare == null || initWith.capturedSquare.position.isSameSquareAs(initWith.dstPos)) { hasExtraCaptureSquare = false; } else { hasExtraCaptureSquare = true; extraCaptureSquarePos = initWith.capturedSquare.position; } }
public void testIterator() { sizableArray<move> foo = new sizableArray<move>(5); move move1 = new move(new square(0,0), new square(1,1)); move move2 = new move(new square(1,1), new square(2,2)); foo.Add(move1); foo.Add(move2); bool move1seen = false; bool move2seen = false; foreach (move iterated in foo) { Debug.WriteLine("Iterated object " + iterated); if (iterated == move1) { if (move1seen) throw new Exception("Move one iterated twice"); move1seen = true; } else if (iterated == move2) { if (move2seen) throw new Exception("Move two iterated twice"); move2seen = true; } else if (iterated == null) throw new Exception("Iterator returned null"); else throw new Exception("Iterator returned something crazy"); } if (!move1seen || !move2seen) throw new Exception("Iterator did not iterate over all elements"); }
/// <summary> /// Check a list of moves contains only one capture, which has the supplied src and dst/enemysquare. /// </summary> /// <param name="possibleMoves"></param> /// <param name="ourPiece"></param> /// <param name="enemyPiece"></param> /// <returns></returns> public move checkContainsSingleCapture(move[] possibleMoves, square ourPiece, square enemyPiece) { bool captureFound = false; move capture = null; foreach (move thisMove in possibleMoves) { if (thisMove.isCapture) { Assert.IsTrue(thisMove.srcPos.isSameSquareAs(ourPiece.position)); Assert.IsTrue(thisMove.dstPos.isSameSquareAs(enemyPiece.position)); Assert.AreEqual(thisMove.dstPos, enemyPiece.position); Assert.AreEqual(thisMove.capturedSquare, enemyPiece); if (captureFound) throw new AssertFailedException("Multiple captures found, one expected"); captureFound = true; capture = thisMove; } } if (!captureFound) throw new AssertFailedException("No captures found, one expected"); return capture; }
public void testThatEnPassantDoesNotOccurAfterTwoPawnAdvances() { DoktorChessAIBoard ourBoard = DoktorChessAIBoard.makeFromFEN("8/8/8/8/6P1/8/7p/8 b - - 0 1", gameType.normal, boardSearchConfig.getDebugConfig()); // Verify that we cannot en passant after our opponent has moved a pawn forward one, not two, squares. square ourPawn = ourBoard[6, 3]; square enemyPawn = ourBoard[7, 1]; square ourNewSquare = ourBoard[ourPawn.position.rightOne().upOne()]; // Advance the enemy pawn twice move advanceOne = new move(enemyPawn, ourBoard[enemyPawn.position.upOne()]); ourBoard.doMove(advanceOne); ourBoard.colToMove = pieceColour.black; advanceOne = new move(enemyPawn, ourBoard[enemyPawn.position.upOne()]); ourBoard.doMove(advanceOne); sizableArray<move> possibleMoves = ourPawn.getPossibleMoves(ourBoard); if (Array.Find(possibleMoves.getArray(), a => a.isCapture == true) != null) throw new AssertFailedException("Found en passant capture when none is legal"); }
public void testThreatMapDeep_discovered() { DoktorChessAIBoard ourBoard = new DoktorChessAIBoard(gameType.queenAndPawns, boardSearchConfig.getDebugConfig() ); square ourPawn = ourBoard.addPiece(pieceType.pawn, pieceColour.white, 4, 1); square ourRook = ourBoard.addPiece(pieceType.rook, pieceColour.white, 0, 1); move ourMove = new move(ourPawn, ourBoard[4, 2]); ourBoard.doMove(ourMove); // Observe the squares to the right of our pawn - they should now be accessible to the rook for (int x = 1; x < 7; x++) { if (ourBoard.getCoverLevel(new squarePos(x, 1), pieceColour.white) != 1) throw new AssertFailedException("Threatmap did not update cover levels correctly"); } }
public void testThreatMapDeep_discoveredCapture() { DoktorChessAIBoard ourBoard = new DoktorChessAIBoard(gameType.queenAndPawns, boardSearchConfig.getDebugConfig()); square ourPawn = ourBoard.addPiece(pieceType.pawn, pieceColour.white, 0, 1); square enemyPawn = ourBoard.addPiece(pieceType.pawn, pieceColour.black, 1, 2); square ourRook = ourBoard.addPiece(pieceType.rook, pieceColour.white, 0, 0); square enemyRook = ourBoard.addPiece(pieceType.rook, pieceColour.black, 0, 7); move ourMove = new move(ourPawn, enemyPawn); ourBoard.doMove(ourMove); // Squares between rooks our pawn should be threatened by both rooks, so should have a threat // level of 0, apart from the one at y=3, which is threatened by a pawn. for (int x = 1; x < 7; x++) { if (x == 3) { if (ourBoard.getCoverLevel(new squarePos(0, x), pieceColour.black) != -1) throw new AssertFailedException("Threatmap did not update cover levels correctly for discovered spaces"); } else { if (ourBoard.getCoverLevel(new squarePos(0, x), pieceColour.black) != 0) throw new AssertFailedException("Threatmap did not update cover levels correctly for discovered spaces"); } } // Both rooks should be threatened once, by the other rook. if (ourBoard.getCoverLevel(new squarePos(0, 0), pieceColour.black) != 1 || ourBoard.getCoverLevel(new squarePos(0, 7), pieceColour.white) != 1 ) throw new AssertFailedException("Threatmap did not update cover levels correctly for rooks"); }
public void testThatEnPassantDoesNotOccurAfterExtraMove() { DoktorChessAIBoard ourBoard = DoktorChessAIBoard.makeFromFEN("8/8/8/8/6P1/8/1P5p/8 b - - 0 1", gameType.normal, boardSearchConfig.getDebugConfig()); // Verify that we cannot en passant after we move a piece square ourPawn = ourBoard[6, 3]; square ourKing = ourBoard[1, 1]; square enemyPawn = ourBoard[7, 1]; // Advance the enemy pawn two squares, and then move our king. This should cause en passant to be impossible. move advanceTwo = new move(enemyPawn, ourBoard[enemyPawn.position.up(2)]); ourBoard.doMove(advanceTwo); // Then, move our king move kingMove = new move(ourKing, ourBoard[ourKing.position.upOne()]); ourBoard.doMove(kingMove); // Now. Can we en passant? sizableArray<move> possibleMoves = ourPawn.getPossibleMoves(ourBoard); if (Array.Find(possibleMoves.getArray(), a => a.isCapture == true) != null) throw new AssertFailedException("Found en passant capture when none is legal"); }
/// <summary> /// Would the specified move put the player of the specified colour in to check? /// </summary> /// <param name="playerCol">Colour which may move in ot check</param> /// <param name="playersMove">Move to examine</param> /// <returns></returns> public bool wouldMovePutPlayerInCheck(pieceColour playerCol, move playersMove) { doMove(playersMove); bool toRet = isPlayerInCheck(playerCol); undoMove(playersMove); return toRet; }
public void testThreatMapDeep_discoveredPromotion() { DoktorChessAIBoard ourBoard = new DoktorChessAIBoard(gameType.queenAndPawns, boardSearchConfig.getDebugConfig()); square ourPawn = ourBoard.addPiece(pieceType.pawn, pieceColour.white, 3, 6); square enemyPawn = ourBoard.addPiece(pieceType.pawn, pieceColour.black, 3, 7); square ourRook = ourBoard.addPiece(pieceType.rook, pieceColour.white, 0, 7); move ourMove = new move(ourPawn, ourBoard[3, 7], pieceType.queen); ourBoard.doMove(ourMove); // Observe the squares to the right of our pawn - they should not be accessible to the rook for (int x = 4; x < 7; x++) { if (ourBoard.getCoverLevel(new squarePos(x, 7), pieceColour.white) != 1) throw new AssertFailedException("Threatmap did not update cover levels correctly"); } // the pawn itself is protected once. if (ourBoard.getCoverLevel(new squarePos(3, 7), pieceColour.white) != 1) throw new AssertFailedException("Threatmap did not update cover levels of promoted piece correctly"); }
public void testKingsideCastlingMoveIsUnExecutedCorrectly() { DoktorChessAIBoard ourBoard = new DoktorChessAIBoard(gameType.normal, boardSearchConfig.getDebugConfig()); square ourKing = ourBoard.addPiece(pieceType.king, pieceColour.white, 4, 0); square ourRook = ourBoard.addPiece(pieceType.rook, pieceColour.white, 7, 0); ourBoard.addPiece(pieceType.king, pieceColour.black, 0, 0); string origBoard = ourBoard.ToString(); // Make out castling move move castlingMove = new move(ourKing, ourBoard[6, 0]); ourBoard.doMove(castlingMove); Assert.AreNotEqual(origBoard, ourBoard.ToString(), "Castling did not affect the board"); // Now undo our castling and verify that we get back to the original position. ourBoard.undoMove(castlingMove); Assert.AreEqual(origBoard, ourBoard.ToString(), "Castling and then un-castling did not return the original board"); }
public void testMoveUndoingThreatmapWithCapture() { DoktorChessAIBoard ourBoard = DoktorChessAIBoard.makeFromFEN("8/8/8/8/4p3/5P2/8/8 b - - 0 1", gameType.normal, boardSearchConfig.getDebugConfig()); square ourPawn = ourBoard[4, 3]; square enemyPawn = ourBoard[5, 2]; string origThreatMap = ourBoard.coverLevel.ToString(); int[,] threatCounts = new int[DoktorChessAIBoard.sizeX,DoktorChessAIBoard.sizeY]; for (int x = 0; x < DoktorChessAIBoard.sizeX; x++) { for (int y = 0; y < DoktorChessAIBoard.sizeY; y++) { threatCounts[x, y] = ourBoard[x, y].coveredSquares.Count; } } move ourMove = new move(ourPawn, enemyPawn); ourBoard.doMove(ourMove); if (ourBoard.coverLevel.ToString() == origThreatMap) throw new AssertFailedException("After a move, the threat map has not changed"); ourBoard.undoMove(ourMove); if (ourBoard.coverLevel.ToString() != origThreatMap) { Debug.WriteLine("Expected:"); Debug.WriteLine(origThreatMap); Debug.WriteLine("Actual:"); Debug.WriteLine(ourBoard.coverLevel.ToString()); throw new AssertFailedException("After a move undo, the threat map has changed"); } for (int x = 0; x < DoktorChessAIBoard.sizeX; x++) { for (int y = 0; y < DoktorChessAIBoard.sizeY; y++) { if (threatCounts[x, y] != ourBoard[x, y].coveredSquares.Count) throw new AssertFailedException("Piece covered count incorrect"); } } }
public lineAndScore(move[] newLine, int newFinalScore, baseBoardScorer scorer) { line = newLine; finalScore = newFinalScore; _scorer = scorer; }
public void testThatEnPassantOccursWhenItShouldAsBlack() { DoktorChessAIBoard ourBoard = new DoktorChessAIBoard(gameType.normal, boardSearchConfig.getDebugConfig()); // En passant requires that the enemy pawn has just advanced two squares. Because of this, we make this move on a board and then check that en passant can occur. square ourPawn = ourBoard.addPiece(pieceType.pawn, pieceColour.black, 6, 3); square enemyPawn = ourBoard.addPiece(pieceType.pawn, pieceColour.white, 7, 1); // Advance the enemy pawn move advanceTwo = new move(enemyPawn, ourBoard[enemyPawn.position.up(2)]); ourBoard.doMove(advanceTwo); // Now verify that the enemy pawn is captured. sizableArray<move> possibleMoves = ourPawn.getPossibleMoves(ourBoard); move enPassantCapture = null; foreach (move thisMove in possibleMoves) { if (thisMove.isCapture) { if (enPassantCapture != null) throw new AssertFailedException("More than one capture was found"); // Note that our dest square is not the enemy square here. Assert.IsTrue(thisMove.srcPos.isSameSquareAs(ourPawn.position)); Assert.IsTrue(thisMove.dstPos.isSameSquareAs(ourPawn.position.rightOne().downOne() )); Assert.AreSame(thisMove.capturedSquare, enemyPawn); enPassantCapture = thisMove; } } if (enPassantCapture == null) throw new AssertFailedException("En passant capture did not occur"); // Make sure that the en passant capture ends up putting our pawn in the square above the enemy pawn Assert.IsTrue(enemyPawn.position.downOne().isSameSquareAs( enPassantCapture.dstPos) ); }
public override void undoMove(move move) { if (move.isACastling) { if (this[move.dstPos].colour == pieceColour.white) whiteHasCastled = false; else if (this[move.dstPos].colour == pieceColour.black) blackHasCastled = false; else throw new Exception("Cannot identify colour"); } base.undoMove(move); }
public override void doMove(move move) { // If this move is a castling, update the rooks movedCount if (move.isACastling) { if (this[move.srcPos].colour == pieceColour.white) whiteHasCastled = true; else if (this[move.srcPos].colour == pieceColour.black) blackHasCastled = true; else throw new Exception("Cannot identify colour"); } base.doMove(move); }
public void verifyMoveOfEmptySpaceIsIllegal() { DoktorChessAIBoard ourBoard = DoktorChessAIBoard.makeQueenAndPawnsStartPosition(boardSearchConfig.getDebugConfig()); move illegalMove = new move(ourBoard[3, 3], ourBoard[4, 4]); Assert.IsFalse(illegalMove.isLegal(ourBoard)); }
public void testThreatMapDeep_pawnCapture() { DoktorChessAIBoard ourBoard = new DoktorChessAIBoard(gameType.queenAndPawns, boardSearchConfig.getDebugConfig()); square ourPawn = ourBoard.addPiece(pieceType.pawn, pieceColour.white, 4, 1); square enemyPawn = ourBoard.addPiece(pieceType.pawn, pieceColour.black, 3, 2); if (ourBoard.getCoverLevel(new squarePos(3, 2), pieceColour.white) != 1 || ourBoard.getCoverLevel(new squarePos(5, 2), pieceColour.white) != 1) throw new AssertFailedException("Threatmap created wrongly"); if (ourBoard.getCoverLevel(new squarePos(2, 1), pieceColour.white) != -1 || ourBoard.getCoverLevel(new squarePos(4, 1), pieceColour.white) != -1) throw new AssertFailedException("Enemy pawn create with no threatened squares"); if (ourPawn.coveredSquares.Count != 2) throw new AssertFailedException("Pawn created not covering two squares"); if ((!ourPawn.coveredSquares[3, 2]) || (!ourPawn.coveredSquares[5, 2]) ) throw new AssertFailedException("Pawn created with incorrect .coveredSquares"); if (((threatMap)ourBoard.coverLevel).piecesWhichThreatenSquare[3, 2].Count != 1 || ((threatMap)ourBoard.coverLevel).piecesWhichThreatenSquare[3, 2].Count != 1) throw new AssertFailedException("Pawn created with incorrect .piecesWhichThreatenSquare count"); //if (((threatMap)ourBoard.coverLevel).piecesWhichThreatenSquare[3, 2][ourPawn.position.flatten()] != ourPawn || // ((threatMap)ourBoard.coverLevel).piecesWhichThreatenSquare[5, 2][ourPawn.position.flatten()] != ourPawn) // throw new AssertFailedException("Pawn created with incorrect .piecesWhichThreatenSquare contents"); move ourMove = new move(ourPawn, ourBoard[3, 2]); ourBoard.doMove(ourMove); if (ourBoard.getCoverLevel(new squarePos(2, 3), pieceColour.white) != 1 || ourBoard.getCoverLevel(new squarePos(4, 3), pieceColour.white) != 1) throw new AssertFailedException("Threatmap did not update cover levels correctly"); if (ourBoard.getCoverLevel(new squarePos(2, 1), pieceColour.white) != 0 || ourBoard.getCoverLevel(new squarePos(4, 1), pieceColour.white) != 0) throw new AssertFailedException("Captured pawn still has threatened squares"); if (ourPawn.coveredSquares.Count != 2) throw new AssertFailedException("Pawn updated not covering two squares"); if (!ourPawn.coveredSquares[2, 3] || !ourPawn.coveredSquares[4, 3] ) throw new AssertFailedException("Pawn updated with incorrect .coveredSquares"); if (((threatMap)ourBoard.coverLevel).piecesWhichThreatenSquare[3, 2].Count != 0 || ((threatMap)ourBoard.coverLevel).piecesWhichThreatenSquare[3, 2].Count != 0) throw new AssertFailedException("Pawn's pre-update .piecesWhichThreatenSquare was not changed"); if (((threatMap)ourBoard.coverLevel).piecesWhichThreatenSquare[2, 3].Count != 1 || ((threatMap)ourBoard.coverLevel).piecesWhichThreatenSquare[4, 3].Count != 1) throw new AssertFailedException("Pawn updated with incorrect .piecesWhichThreatenSquare count"); //if (((threatMap)ourBoard.coverLevel).piecesWhichThreatenSquare[2, 3][ourPawn.position.flatten()] != ourPawn || // ((threatMap)ourBoard.coverLevel).piecesWhichThreatenSquare[4, 3][ourPawn.position.flatten()] != ourPawn) // throw new AssertFailedException("Pawn updated with incorrect .piecesWhichThreatenSquare contents"); }
public void verifyLegalMoveIsLegal() { DoktorChessAIBoard ourBoard = DoktorChessAIBoard.makeQueenAndPawnsStartPosition(boardSearchConfig.getDebugConfig()); move legalMove = new move(ourBoard[1, 1], ourBoard[1, 3]); Assert.IsTrue(legalMove.isLegal(ourBoard)); }
public void testThatEnPassantOccursWhenItShouldAsWhite() { DoktorChessAIBoard ourBoard = DoktorChessAIBoard.makeFromFEN("8/6p1/8/7P/8/8/8/8 b - - 0 1", gameType.normal, boardSearchConfig.getDebugConfig()); square enemyPawn = ourBoard[6, 6]; square ourPawn = ourBoard[7, 4]; // Advance the enemy pawn move advanceTwo = new move(enemyPawn, ourBoard[enemyPawn.position.down(2)]); ourBoard.doMove(advanceTwo); // Now verify that the enemy pawn is captured. sizableArray<move> possibleMoves = ourPawn.getPossibleMoves(ourBoard); move enPassantCapture = null; foreach (move thisMove in possibleMoves) { if (thisMove.isCapture) { if (enPassantCapture != null) throw new AssertFailedException("More than one capture was found"); // Note that our dest square is not the enemy square here. Assert.IsTrue(thisMove.srcPos.isSameSquareAs(ourPawn.position)); Assert.IsTrue(thisMove.dstPos.isSameSquareAs(ourPawn.position.leftOne().upOne())); Assert.AreSame(thisMove.capturedSquare, enemyPawn); enPassantCapture = thisMove; } } if (enPassantCapture == null) throw new AssertFailedException("En passant capture did not occur"); // Make sure that the en passant capture ends up putting our pawn in the square above the enemy pawn Assert.IsTrue(enemyPawn.position.upOne().isSameSquareAs(enPassantCapture.dstPos)); }
/// <summary> /// Perform the specified move /// </summary> /// <param name="move">The move to play</param> public virtual void doMove(move move) { sanityCheck(); #if DEBUG if (this[move.srcPos].type == pieceType.none) throw new ArgumentException("Moving empty space"); if (this[move.srcPos].colour != colToMove) throw new ArgumentException("Moving peice of wrong colour"); #endif // If this is a pawn move or a capture, reset the fifty-move rule counter. if (this[move.srcPos].type == pieceType.pawn || move.isCapture) { fiftyMoveCounter.Push(0); } else { if (moveCount > 0) fiftyMoveCounter.Push(fiftyMoveCounter.Peek() + 1); else fiftyMoveCounter.Push(1); } // Update movedness count for the moving piece this[move.srcPos].moveNumbers.Push(moveCount); this[move.srcPos].movedCount++; square movingSquare = this[move.srcPos]; // If this move is a castling, update the rooks movedCount if (move.isACastling) { this[move.castlingRookSrcPos].movedCount++; this[move.castlingRookSrcPos].moveNumbers.Push(moveCount); } // Update the number of moves on this board moveCount++; // Move our piece from the source to the destination, removing any piece that might be there if (this[move.dstPos].type != pieceType.none) { removePiece(this[move.dstPos]); if (!move.isCapture) throw new Exception("Non-capture in to occupied square"); } movePiece(movingSquare, move.dstPos); // If we're castling, move the rook appropriately if (move.isACastling) { square rook = move.findCastlingRook(this); movePiece(rook, move.findNewPosForCastlingRook()); } square captured; if (move.isCapture) { captured = move.capturedSquare; if (!captured.position.isSameSquareAs(move.dstPos)) { // The capture was not in to our piece's destination square. Set the captured // square to be empty. removePiece(captured); } } if (move.isPawnPromotion) { removePiece(movingSquare); this[move.dstPos] = addPiece(move.typeToPromoteTo, movingSquare.colour, move.dstPos); this[move.dstPos].pastLife = movingSquare; } colToMove = getOtherSide(colToMove); // Store this new position on our stack if (positionsSoFar != null) positionsSoFar.Push(this.ToString()); sanityCheck(); }
public virtual void undoMove(move move) { //sanityCheck(); #if DEBUG if (this[move.dstPos].colour == colToMove) throw new ArgumentException("Unmoving peice of wrong colour"); #endif // undo our fifty-move counter fiftyMoveCounter.Pop(); // remove this position from our list of played positions if (positionsSoFar != null) { string oldPos = positionsSoFar.Pop(); #if DEBUG if(oldPos != this.ToString()) throw new Exception("positionsSoFar contains incorrect pos"); #endif } // Revert any promotion if (move.isPawnPromotion) { square promoted = this[move.dstPos]; removePiece(promoted); this[move.dstPos] = promoted.pastLife; addPiece(promoted.pastLife, move.dstPos); } // dec the move counters moveCount--; this[move.dstPos].movedCount--; if (this[move.dstPos].moveNumbers.Count == 0) this[move.dstPos].moveNumbers = this[move.dstPos].moveNumbers; int popped = this[move.dstPos].moveNumbers.Pop(); #if DEBUG if (popped != moveCount) throw new Exception("moveNumbers contains wrong move count"); #endif // Dec the rook's move counter if this is a castling square castlingRook = null; if (move.isACastling) { castlingRook = this[move.castlingRookDstPos]; castlingRook.movedCount--; int poppedRook = castlingRook.moveNumbers.Pop(); #if DEBUG if (moveCount != poppedRook) throw new Exception("moveNumbers contains wrong move count after popping uncastling rook"); #endif } unmovePiece(move.srcPos, move.dstPos); // If a castling, move the rook back too. if (move.isACastling) { removePiece(castlingRook); // ReSharper disable PossibleNullReferenceException // castlingRook cannot be null at this point, as we set it if there is a castling. this[castlingRook.position] = new square(castlingRook.position); // ReSharper restore PossibleNullReferenceException if (castlingRook.position.x == 3) { addPiece(castlingRook, new squarePos(0, castlingRook.position.y)); } else if (castlingRook.position.x == 5) { addPiece(castlingRook, new squarePos(7, castlingRook.position.y)); } else { throw new Exception("While uncastling, could not find castled rook"); } } // Restore any captured piece if (move.isCapture) addPiece(move.capturedSquare, move.capturedSquarePos); colToMove = getOtherSide(colToMove); sanityCheck(); }
public void testMoveUndoingEnPassant() { DoktorChessAIBoard ourBoard = DoktorChessAIBoard.makeFromFEN("8/6p1/8/7P/8/8/8/8 b - - 0 1", gameType.normal, boardSearchConfig.getDebugConfig()); square enemyPawn = ourBoard[6, 6]; // Advance the enemy pawn, so we can capture it via en passant move advanceTwo = new move(enemyPawn, ourBoard[enemyPawn.position.down(2)]); ourBoard.doMove(advanceTwo); string origBoard = ourBoard.ToString(); sizableArray<move> moves = ourBoard.getMoves(pieceColour.white); // Play our only capturing move move enPassant = Array.Find(moves.getArray(), a => a.isCapture == true); if (enPassant == null) Assert.Inconclusive("No en passant move found"); ourBoard.doMove(enPassant); if (ourBoard.ToString() == origBoard) throw new AssertFailedException("After a move, the board has not changed"); ourBoard.undoMove(enPassant); if (ourBoard.ToString() != origBoard) throw new AssertFailedException("After a move undo, the board has changed"); }
public static move fromJSON(string JSON, baseBoard parentBoard) { minimalMove json = new JavaScriptSerializer().Deserialize<minimalMove>(JSON); // Don't forget that the board is inverted, as we show it to the user json.srcSquarePos = new squarePos(json.srcSquarePos.x, 7 - json.srcSquarePos.y); json.dstSquarePos = new squarePos(json.dstSquarePos.x, 7 - json.dstSquarePos.y); move toRet = new move( parentBoard[json.srcSquarePos], parentBoard[json.dstSquarePos]); return toRet; }
public void testMoveUndoingThreatmap_Castling() { DoktorChessAIBoard ourBoard = new DoktorChessAIBoard(gameType.normal, boardSearchConfig.getDebugConfig()); square ourKing = ourBoard.addPiece(pieceType.king, pieceColour.white, 4, 0); square ourRook = ourBoard.addPiece(pieceType.rook, pieceColour.white, 7, 0); square enemyPawn = ourBoard.addPiece(pieceType.pawn, pieceColour.black, 6, 6); string origThreatMap = ourBoard.coverLevel.ToString(); int[,] threatCounts = new int[DoktorChessAIBoard.sizeX,DoktorChessAIBoard.sizeY]; for (int x = 0; x < DoktorChessAIBoard.sizeX; x++) { for (int y = 0; y < DoktorChessAIBoard.sizeY; y++) { threatCounts[x, y] = ourBoard[x, y].coveredSquares.Count; } } move castling = new move(ourKing, ourBoard[6, 0]); ourBoard.doMove(castling); if (ourBoard.coverLevel.ToString() == origThreatMap) throw new AssertFailedException("After a move, the threat map has not changed"); ourBoard.undoMove(castling); if (ourBoard.coverLevel.ToString() != origThreatMap) { Debug.WriteLine("Expected:"); Debug.WriteLine(origThreatMap); Debug.WriteLine("Actual:"); Debug.WriteLine(ourBoard.coverLevel.ToString()); throw new AssertFailedException("After a move undo, the threat map has changed"); } for (int x = 0; x < DoktorChessAIBoard.sizeX; x++) { for (int y = 0; y < DoktorChessAIBoard.sizeY; y++) { if (threatCounts[x, y] != ourBoard[x, y].coveredSquares.Count) throw new AssertFailedException("Piece covered count incorrect"); } } }