public Square(Coord coords, GameBoard.Pieces pieceP, GameBoard.Colour pieceColourP) { coordinates = coords; piece = pieceP; pieceColour = pieceColourP; underAttack = false; isEnPassantSquare = false; //destroyEP = false; }
static string PieceToNotation(GameBoard.Pieces piece, GameBoard.Colour colour) { string notation = ""; switch (piece) { case GameBoard.Pieces.Pawn: notation = "P"; break; case GameBoard.Pieces.Rook: notation = "R"; break; case GameBoard.Pieces.Knight: notation = "N"; break; case GameBoard.Pieces.Bishop: notation = "B"; break; case GameBoard.Pieces.Queen: notation = "Q"; break; case GameBoard.Pieces.King: notation = "K"; break; } if (colour == GameBoard.Colour.Black) { notation = notation.ToLower(); } return(notation); }
public Move GetMoveFromNotation(string pieceType, string targetSquare, string disambiguation, string promotionPieceString, Square[,] analysisBoard, GameBoard.Colour colourToMove, string originalNotation = "") { bool debugMode = (originalNotation == "xxx"); Coord toCoord = new Coord("abcdefgh".IndexOf(targetSquare[0]), int.Parse(targetSquare[1].ToString()) - 1); GameBoard.Pieces movePiece = GameBoard.Pieces.Empty; GameBoard.Pieces promotePiece = GameBoard.Pieces.Empty; moveIndex++; #region piece type switch (pieceType) { case "P": movePiece = GameBoard.Pieces.Pawn; break; case "R": movePiece = GameBoard.Pieces.Rook; break; case "N": movePiece = GameBoard.Pieces.Knight; break; case "B": movePiece = GameBoard.Pieces.Bishop; break; case "Q": movePiece = GameBoard.Pieces.Queen; break; case "K": movePiece = GameBoard.Pieces.King; break; } #endregion if (promotionPieceString != "") { switch (promotionPieceString) { case "R": promotePiece = GameBoard.Pieces.Rook; break; case "N": promotePiece = GameBoard.Pieces.Knight; break; case "B": promotePiece = GameBoard.Pieces.Bishop; break; case "Q": promotePiece = GameBoard.Pieces.Queen; break; } } // if more than one piece is able to reach the target square, e.g. Rfd1 (where f is the disambiguation) if (disambiguation != "") { bool findRank = false; // true if given file int givenValue = 0; if ("abcdefgh".Contains(disambiguation)) // given file { givenValue = "abcdefgh".IndexOf(disambiguation); findRank = true; } if ("12345678".Contains(disambiguation)) // given rank { int givenRank = "12345678".IndexOf(disambiguation); if (findRank) { Move m = new Move(analysisBoard[givenValue, givenRank], analysisBoard[toCoord.x, toCoord.y]); m.promotionPiece = promotePiece; return(m); } givenValue = givenRank; } for (int i = 0; i < 8; i++) { Coord checkCoord = new Coord((findRank)?givenValue:i, (findRank)?i:givenValue); if (analysisBoard[checkCoord.x, checkCoord.y].piece == movePiece && analysisBoard[checkCoord.x, checkCoord.y].pieceColour == colourToMove) { Move proposedMove = new Move(analysisBoard[checkCoord.x, checkCoord.y], analysisBoard[toCoord.x, toCoord.y]); proposedMove.promotionPiece = promotePiece; if (IsLegalMove(proposedMove, analysisBoard, debugMode)) { return(proposedMove); } } } } else // Only one piece can reach this square { Coord moveFromCoords; foreach (Square s in analysisBoard) { if (s.piece == movePiece && s.pieceColour == colourToMove) { Move proposedMove = new Move(s, analysisBoard[toCoord.x, toCoord.y]); proposedMove.promotionPiece = promotePiece; if (IsLegalMove(proposedMove, analysisBoard, debugMode)) { return(proposedMove); } } } } print("Move illegal " + originalNotation + " " + gameIndex + " " + Mathf.CeilToInt(moveIndex / 2f)); return(null); }
void NextPuzzle() { board.ResetBoardToStarting(); legal.NewGame(); //print (puzzleIndex); //print ("Move Count: " +allMoves[puzzleIndex].Count); foreach (Move m in allMoves[puzzleIndex]) { board.MakeMove(m.moveFrom.coordinates, m.moveTo.coordinates); } bool mated = false; bool flip = false; if (legal.Mated(board.analysisBoard, GameBoard.Colour.Black)) { mated = true; } else if (legal.Mated(board.analysisBoard, GameBoard.Colour.White)) { mated = true; flip = true; } if (mated) { blacksLastMove = allMoves[puzzleIndex][allMoves[puzzleIndex].Count - 2]; board.ResetBoardToStarting(); for (int i = 0; i < allMoves[puzzleIndex].Count - 2; i++) { Move m = allMoves[puzzleIndex][i]; board.MakeMove(m.moveFrom.coordinates, m.moveTo.coordinates); } if (flip) { for (int ranks = 0; ranks < 4; ranks++) { for (int files = 0; files < 8; files++) { GameBoard.Pieces tempPiece = board.analysisBoard[files, ranks].piece; GameBoard.Colour tempColour = board.analysisBoard[files, ranks].pieceColour; bool tempEp = board.analysisBoard[files, ranks].isEnPassantSquare; board.analysisBoard[files, ranks].piece = board.analysisBoard[7 - files, 7 - ranks].piece; board.analysisBoard[files, ranks].pieceColour = (board.analysisBoard[7 - files, 7 - ranks].pieceColour == GameBoard.Colour.White)?GameBoard.Colour.Black:GameBoard.Colour.White; board.analysisBoard[files, ranks].isEnPassantSquare = board.analysisBoard[7 - files, 7 - ranks].isEnPassantSquare; board.analysisBoard[7 - files, 7 - ranks].piece = tempPiece; board.analysisBoard[7 - files, 7 - ranks].pieceColour = (tempColour == GameBoard.Colour.White)?GameBoard.Colour.Black:GameBoard.Colour.White; board.analysisBoard[7 - files, 7 - ranks].isEnPassantSquare = tempEp; } } blacksLastMove.moveFrom.coordinates = new Coord(7 - blacksLastMove.moveFrom.coordinates.x, 7 - blacksLastMove.moveFrom.coordinates.y); blacksLastMove.moveTo.coordinates = new Coord(7 - blacksLastMove.moveTo.coordinates.x, 7 - blacksLastMove.moveTo.coordinates.y); } puzzleFen = DatabaseManager.GetPuzzleFEN(board.analysisBoard, blacksLastMove.moveFrom.coordinates, blacksLastMove.moveTo.coordinates, legal); board.SetToAnalysisBoard(); board.MakeMove(blacksLastMove.moveFrom.coordinates, blacksLastMove.moveTo.coordinates); board.SetToAnalysisBoard(); } else { SetPuzzle(false); } }
public bool IsLegalMove(Move move, Square[,] board, bool debugMode = false) { Square[,] analysisBoard = new Square[8, 8]; for (int ranks = 0; ranks < 8; ranks++) { for (int files = 0; files < 8; files++) { analysisBoard[files, ranks] = new Square(board[files, ranks].coordinates, board[files, ranks].piece, board[files, ranks].pieceColour); analysisBoard[files, ranks].isEnPassantSquare = board[files, ranks].isEnPassantSquare; } } GameBoard.Pieces pieceType = move.moveFrom.piece; GameBoard.Colour friendlyColour = move.moveFrom.pieceColour; Coord toCoord = move.moveTo.coordinates; Coord fromCoord = move.moveFrom.coordinates; Square targetSquare = analysisBoard[toCoord.x, toCoord.y]; GameBoard.Pieces capturePiece = targetSquare.piece; if (debugMode) { // print (pieceType + " from " + fromCoord.x +";"+fromCoord.y + " to " + toCoord.x + ";" + toCoord.y + " " ); } // Do not allow capture of friendly pieces OR of kings if (targetSquare.pieceColour == friendlyColour && targetSquare.piece != GameBoard.Pieces.Empty || targetSquare.piece == GameBoard.Pieces.King) { if (debugMode) { print("Trying to capture friendly piece / king"); } return(false); } // apply suggested move to analysis board (whether legal or not) analysisBoard[toCoord.x, toCoord.y].piece = analysisBoard[fromCoord.x, fromCoord.y].piece; analysisBoard[toCoord.x, toCoord.y].pieceColour = friendlyColour; analysisBoard[fromCoord.x, fromCoord.y].piece = GameBoard.Pieces.Empty; Coord epCoord = new Coord(); GameBoard.Pieces epRemovedPiece = GameBoard.Pieces.Empty; bool isEP = false; if (analysisBoard[toCoord.x, toCoord.y].isEnPassantSquare && toCoord.x != fromCoord.x && pieceType == GameBoard.Pieces.Pawn) { isEP = true; int epDir = (toCoord.y == 5)?-1:1; epCoord = new Coord(toCoord.x, toCoord.y + epDir); epRemovedPiece = analysisBoard[epCoord.x, epCoord.y].piece; analysisBoard[epCoord.x, epCoord.y].piece = GameBoard.Pieces.Empty; } Coord deltaMove = toCoord - fromCoord; // Check if resulting position is legal (is king in check) Coord friendlyKingCoord = new Coord(); foreach (Square s in analysisBoard) { if (s.pieceColour == friendlyColour && s.piece == GameBoard.Pieces.King) { friendlyKingCoord = s.coordinates; break; } } Coord offsetFromMyKing = fromCoord - friendlyKingCoord; bool pinned = false; if (SquareUnderAttack(friendlyKingCoord, analysisBoard, friendlyColour)) { if (debugMode) { print("Piece is pinned"); } pinned = true; } if (isEP) { analysisBoard[epCoord.x, epCoord.y].piece = epRemovedPiece; } if (pinned) { return(false); } // check if move direction is allowed by this piece // reset analysis board analysisBoard[fromCoord.x, fromCoord.y].piece = analysisBoard[toCoord.x, toCoord.y].piece; analysisBoard[fromCoord.x, fromCoord.y].pieceColour = friendlyColour; analysisBoard[toCoord.x, toCoord.y].piece = capturePiece; analysisBoard[toCoord.x, toCoord.y].pieceColour = (friendlyColour == GameBoard.Colour.White)?GameBoard.Colour.Black:GameBoard.Colour.White; if (pieceType == GameBoard.Pieces.Knight) // Check if knight move is legal { foreach (Coord c in knightDirections) { if (fromCoord + c == toCoord) { return(true); } } return(false); } else if (pieceType == GameBoard.Pieces.Pawn) { if (toCoord.y == 0 || toCoord.y == 7) // is promoting if reached first/eigth rank { move.isPromotion = true; if (move.promotionPiece == GameBoard.Pieces.Empty) { move.promotionPiece = GameBoard.Pieces.Queen; foreach (Coord c in knightDirections) { Coord knightAttackRange = toCoord + c; if (CoordInRange(knightAttackRange)) { if (analysisBoard[knightAttackRange.x, knightAttackRange.y].piece == GameBoard.Pieces.King && analysisBoard[knightAttackRange.x, knightAttackRange.y].pieceColour != friendlyColour) { move.promotionPiece = GameBoard.Pieces.Knight; } } } } } int pawnMoveDir = (friendlyColour == GameBoard.Colour.White)?1:-1; if (deltaMove.x == 0 && Mathf.Sign(deltaMove.y) == pawnMoveDir && analysisBoard[toCoord.x, toCoord.y].piece == GameBoard.Pieces.Empty) // pawn is advancing in correct direction and landing on empty square { if (Mathf.Abs(deltaMove.y) == 1) // single step forward { return(true); } else if (Mathf.Abs(deltaMove.y) == 2) // two steps forward { if ((fromCoord.y == 1 && pawnMoveDir == 1) || (fromCoord.y == 6 && pawnMoveDir == -1)) // is on starting square { if (analysisBoard[fromCoord.x, fromCoord.y + pawnMoveDir].piece == GameBoard.Pieces.Empty) // not jumping over any pieces { move.createEnPassant = true; move.enPassantSquare = new Coord(fromCoord.x, fromCoord.y + pawnMoveDir); // set en passant square return(true); } } } } if (Mathf.Sign(deltaMove.y) == pawnMoveDir && Mathf.Abs(deltaMove.y) == 1 && Mathf.Abs(deltaMove.x) == 1) // capturing in correct direction { if (analysisBoard[toCoord.x, toCoord.y].isEnPassantSquare) // capturing ep { move.isEnPassantCapture = true; move.enPassantSquare = analysisBoard[toCoord.x, toCoord.y].coordinates; move.enPassantCaptureSquare = analysisBoard[fromCoord.x + deltaMove.x, fromCoord.y].coordinates; return(true); } if (capturePiece != GameBoard.Pieces.Empty) // is capturing enemy piece { return(true); } } return(false); } else if (pieceType == GameBoard.Pieces.King) { if (Mathf.Abs(deltaMove.x) <= 1 && Mathf.Abs(deltaMove.y) <= 1) { // Castling is henceforth illegal as king has moved if (friendlyColour == GameBoard.Colour.White) { whiteCanCastleKingside = false; whiteCanCastleQueenside = false; } else { blackCanCastleKingside = false; blackCanCastleQueenside = false; } return(true); } if (deltaMove.y == 0 && Mathf.Abs(deltaMove.x) == 2) // castling { int castleDir = (int)Mathf.Sign(deltaMove.x); bool canCastle = false; if (castleDir == -1) { canCastle = (friendlyColour == GameBoard.Colour.White)?whiteCanCastleQueenside:blackCanCastleQueenside; } else if (castleDir == 1) { canCastle = (friendlyColour == GameBoard.Colour.White)?whiteCanCastleKingside:blackCanCastleKingside; } if (!canCastle) { print(analysisBoard[fromCoord.x, fromCoord.y].pieceColour + " " + blackCanCastleQueenside); return(false); } Coord passingSquare = new Coord(fromCoord.x + castleDir, fromCoord.y); int min = (castleDir == 1)?5:1; int max = (castleDir == 1)?7:4; for (int i = min; i < max; i++) { if (analysisBoard[i, toCoord.y].piece != GameBoard.Pieces.Empty) // cant castle through occupied squares { return(false); } } if (!SquareUnderAttack(passingSquare, analysisBoard, friendlyColour)) //cant castle through check { move.isCastling = true; move.rookStartSquare = new Coord((castleDir == -1)?0:7, fromCoord.y); move.rookTargetSquare = new Coord(fromCoord.x + castleDir, fromCoord.y); if (friendlyColour == GameBoard.Colour.White) { whiteCanCastleKingside = false; whiteCanCastleQueenside = false; } else { blackCanCastleKingside = false; blackCanCastleQueenside = false; } return(true); } else { return(false); } } } Coord moveDir = ClampCoordToDir(deltaMove); int moveLength = Mathf.Max(Mathf.Abs(deltaMove.x), Mathf.Abs(deltaMove.y)); if ((deltaMove.x == 0 || deltaMove.y == 0) && (pieceType == GameBoard.Pieces.Rook || pieceType == GameBoard.Pieces.Queen)) // horizontal/vertical for Rook or Queen { for (int i = 1; i < moveLength; i++) { Coord c = fromCoord + moveDir * i; if (analysisBoard[c.x, c.y].piece != GameBoard.Pieces.Empty) // moving through a piece { return(false); } } if (pieceType == GameBoard.Pieces.Rook) { if (move.moveFrom.coordinates == new Coord(0, 0)) { whiteCanCastleQueenside = false; } if (move.moveFrom.coordinates == new Coord(7, 0)) { whiteCanCastleKingside = false; } if (move.moveFrom.coordinates == new Coord(0, 7)) { blackCanCastleQueenside = false; } if (move.moveFrom.coordinates == new Coord(7, 7)) { blackCanCastleKingside = false; } } return(true); } if (Mathf.Abs(deltaMove.x) == Mathf.Abs(deltaMove.y) && (pieceType == GameBoard.Pieces.Bishop || pieceType == GameBoard.Pieces.Queen)) // diagonal for bishop or Queen { for (int i = 1; i < moveLength; i++) { Coord c = fromCoord + moveDir * i; if (analysisBoard[c.x, c.y].piece != GameBoard.Pieces.Empty) // moving through a piece { if (debugMode) { print("Moving diagonally through a piece"); } return(false); } } return(true); } if (debugMode) { print("Returned false by default"); } return(false); }