/// <summary> /// Detects Checkmate, Stalemate or Draw conditions. /// </summary> /// <returns>True if no legal moves, or only kings left.</returns> public bool detectCheckmate() { bool wkingonly = this.Board.Pieces[Player.WHITE].Count == 1 && this.Board.Grid[this.Board.Pieces[Player.WHITE][0].number][this.Board.Pieces[Player.WHITE][0].letter].piece == Piece.KING; bool bkingonly = this.Board.Pieces[Player.BLACK].Count == 1 && this.Board.Grid[this.Board.Pieces[Player.BLACK][0].number][this.Board.Pieces[Player.BLACK][0].letter].piece == Piece.KING; if (!LegalMoveSet.hasMoves(this.Board, this.Turn)) { if (LegalMoveSet.isCheck(this.Board, this.Turn)) { this.m_UI.LogMove("Checkmate!\n"); this.m_UI.SetStatus(false, ((this.Turn == Player.WHITE) ? "Black" : "White") + " wins!"); } else { this.m_UI.LogMove("Stalemate!\n"); } return(true); } else if (wkingonly && bkingonly) { this.m_UI.LogMove("Draw.\n"); return(true); } return(false); }
/// <summary> /// Get any legal move from the current position on the provided board. /// </summary> /// <param name="board">The state of the game.</param> /// <param name="pos">The piece/position to check for valid moves.</param> /// <param name="verify_check">Whether or not to recurse and check if the current move puts you in check.</param> /// <returns>A list of positions the piece can move to.</returns> public static List <position_t> getLegalMove(ChessBoard board, position_t pos, bool verify_check = true) { piece_t p = board.Grid[pos.number][pos.letter]; if (p.piece == Piece.NONE) { return(new List <position_t>()); } switch (p.piece) { case Piece.PAWN: return(LegalMoveSet.Pawn(board, pos, verify_check)); case Piece.ROOK: return(LegalMoveSet.Rook(board, pos, verify_check)); case Piece.KNIGHT: return(LegalMoveSet.Knight(board, pos, verify_check)); case Piece.BISHOP: return(LegalMoveSet.Bishop(board, pos, verify_check)); case Piece.QUEEN: return(LegalMoveSet.Queen(board, pos, verify_check)); case Piece.KING: return(LegalMoveSet.King(board, pos, verify_check)); default: return(new List <position_t>()); } }
private static List <position_t> Rook(ChessBoard board, position_t pos, bool verify_check = true) { List <position_t> moves = new List <position_t>(); piece_t p = board.Grid[pos.number][pos.letter]; if (p.piece == Piece.NONE) { return(moves); } // slide along vert/hor for possible moves moves.AddRange(Slide(board, p.player, pos, new position_t(1, 0))); moves.AddRange(Slide(board, p.player, pos, new position_t(-1, 0))); moves.AddRange(Slide(board, p.player, pos, new position_t(0, 1))); moves.AddRange(Slide(board, p.player, pos, new position_t(0, -1))); if (verify_check)// make sure each move doesn't put us in check { for (int i = moves.Count - 1; i >= 0; i--) { ChessBoard b2 = LegalMoveSet.move(board, new move_t(pos, moves[i])); if (isCheck(b2, p.player)) { moves.RemoveAt(i); } } } return(moves); }
private static List <position_t> Knight(ChessBoard board, position_t pos, bool verify_check = true) { List <position_t> moves = new List <position_t>(); piece_t p = board.Grid[pos.number][pos.letter]; if (p.piece == Piece.NONE) { return(moves); } // collect all relative moves possible List <position_t> relative = new List <position_t>(); relative.Add(new position_t(2, 1)); relative.Add(new position_t(2, -1)); relative.Add(new position_t(-2, 1)); relative.Add(new position_t(-2, -1)); relative.Add(new position_t(1, 2)); relative.Add(new position_t(-1, 2)); relative.Add(new position_t(1, -2)); relative.Add(new position_t(-1, -2)); // iterate moves foreach (position_t move in relative) { position_t moved = new position_t(move.letter + pos.letter, move.number + pos.number); // bounds check if (moved.letter < 0 || moved.letter > 7 || moved.number < 0 || moved.number > 7) { continue; } // if empty space or attacking if (board.Grid[moved.number][moved.letter].piece == Piece.NONE || board.Grid[moved.number][moved.letter].player != p.player) { moves.Add(moved); } } if (verify_check)// make sure each move doesn't put us in check { for (int i = moves.Count - 1; i >= 0; i--) { ChessBoard b2 = LegalMoveSet.move(board, new move_t(pos, moves[i])); if (isCheck(b2, p.player)) { moves.RemoveAt(i); } } } return(moves); }
private static bool allowCastle(ChessBoard board, Player player, position_t pos, bool isRight) { bool isValid = true; int rookPos; int kingDirection; if (isRight) { rookPos = 7; kingDirection = 1; } else { rookPos = 0; kingDirection = -1; } //Check for valid right castling // Is the peice at H,7 a rook owned by the player and has it moved if (board.Grid[pos.number][rookPos].piece == Piece.ROOK && board.Grid[pos.number][rookPos].player == player && board.Grid[pos.number][rookPos].lastPosition.Equals(new position_t(-1, -1))) { // Check that the adjacent two squares are empty for (int i = 0; i < 2; i++) { if (board.Grid[pos.number][pos.letter + (i + 1) * kingDirection].piece != Piece.NONE) { isValid = false; break; } } // Don't bother running secondary checks if the way isn't even clear if (isValid) { for (int i = 0; i < 2; i++) { // Move kings postion over i squares to check if king is passing over an attackable // square ChessBoard b2 = LegalMoveSet.move(board, new move_t(pos, new position_t(pos.letter + (i + 1) * kingDirection, pos.number))); // Attackable square is in between king and rook so // its not possible to castle to the right rook if (isCheck(b2, player)) { isValid = false; break; } } } } else { isValid = false; } return(isValid); }
/// <summary> /// Calculate and return the boards fitness value. /// </summary> /// <param name="max">Who's side are we viewing from.</param> /// <returns>The board fitness value, what else?</returns> public int fitness(Player max) { int fitness = 0; int[] blackPieces = { 0, 0, 0, 0, 0, 0 }; int[] whitePieces = { 0, 0, 0, 0, 0, 0 }; int blackMoves = 0; int whiteMoves = 0; // sum up the number of moves and pieces foreach (position_t pos in Pieces[Player.BLACK]) { blackMoves += LegalMoveSet.getLegalMove(this, pos).Count; blackPieces[(int)Grid[pos.number][pos.letter].piece]++; } // sum up the number of moves and pieces foreach (position_t pos in Pieces[Player.WHITE]) { whiteMoves += LegalMoveSet.getLegalMove(this, pos).Count; whitePieces[(int)Grid[pos.number][pos.letter].piece]++; } // if viewing from black side if (max == Player.BLACK) { // apply weighting to piece counts for (int i = 0; i < 6; i++) { fitness += pieceWeights[i] * (blackPieces[i] - whitePieces[i]); } // apply move value fitness += (int)(0.5 * (blackMoves - whiteMoves)); } else { // apply weighting to piece counts for (int i = 0; i < 6; i++) { fitness += pieceWeights[i] * (whitePieces[i] - blackPieces[i]); } // apply move value fitness += (int)(0.5 * (whiteMoves - blackMoves)); } return(fitness); }
/// <summary> /// Get all legal moves for the player on the current board. /// </summary> /// <param name="b">The state of the game.</param> /// <param name="player">The player whose moves you want.</param> /// <returns>A 1-to-many dictionary of moves from one position to many</returns> public static Dictionary <position_t, List <position_t> > getPlayerMoves(ChessBoard b, Player player) { Dictionary <position_t, List <position_t> > moves = new Dictionary <position_t, List <position_t> >(); foreach (position_t pos in b.Pieces[player]) { if (b.Grid[pos.number][pos.letter].piece != Piece.NONE) { if (!moves.ContainsKey(pos)) { moves[pos] = new List <position_t>(); } moves[pos].AddRange(LegalMoveSet.getLegalMove(b, pos)); } } return(moves); }
private void MakeMove(move_t m) { // start move log output string move = (this.Turn == Player.WHITE) ? "W" : "B"; move += ":\t"; // piece switch (this.Board.Grid[m.from.number][m.from.letter].piece) { case Piece.PAWN: move += "P"; break; case Piece.ROOK: move += "R"; break; case Piece.KNIGHT: move += "k"; break; case Piece.BISHOP: move += "B"; break; case Piece.QUEEN: move += "Q"; break; case Piece.KING: move += "K"; break; } // kill if (this.Board.Grid[m.to.number][m.to.letter].piece != Piece.NONE || LegalMoveSet.isEnPassant(this.Board, m)) { move += "x"; } // letter switch (m.to.letter) { case 0: move += "a"; break; case 1: move += "b"; break; case 2: move += "c"; break; case 3: move += "d"; break; case 4: move += "e"; break; case 5: move += "f"; break; case 6: move += "g"; break; case 7: move += "h"; break; } // number move += (m.to.number + 1).ToString(); // update board / make actual move this.Board = LegalMoveSet.move(this.Board, m); // if that move put someone in check if (LegalMoveSet.isCheck(this.Board, (Turn == Player.WHITE) ? Player.BLACK : Player.WHITE)) { move += "+"; } // show log this.m_UI.LogMove(move + "\n"); }
public List <position_t> Select(position_t pos) { // has previously selected something if (this.Board.Grid[this.Selection.number][this.Selection.letter].piece != Piece.NONE && this.Turn == this.Board.Grid[this.Selection.number][this.Selection.letter].player && (this.m_nPlayers == 2 || this.Turn == Player.WHITE)) { // get previous selections moves and determine if we chose a legal one by clicking List <position_t> moves = LegalMoveSet.getLegalMove(this.Board, this.Selection); foreach (position_t move in moves) { if (move.Equals(pos)) { // we selected a legal move so update the board MakeMove(new move_t(this.Selection, pos)); // If piece that was just moved is a king and it moved anyhthing other than 1 square, it was // a castling move, so we need to move the rook if (this.Board.Grid[pos.number][pos.letter].piece == Piece.KING && Math.Abs(pos.letter - this.Selection.letter) == 2) { int row = (this.Turn == Player.WHITE) ? 0 : 7; // Left rook if (pos.letter < 4) { LegalMoveSet.move(this.Board, new move_t(new position_t(0, row), new position_t(3, row))); } // right rook else { LegalMoveSet.move(this.Board, new move_t(new position_t(7, row), new position_t(5, row))); } } // finish move switchPlayer(); if (detectCheckmate()) { return(new List <position_t>()); } if (this.m_nPlayers == 1) // start ai { new Thread(AISelect).Start(); // thread turn } return(new List <position_t>()); } } } // first click, let's show possible moves if (this.Board.Grid[pos.number][pos.letter].player == this.Turn && (this.m_nPlayers == 2 || this.Turn == Player.WHITE)) { List <position_t> moves = LegalMoveSet.getLegalMove(this.Board, pos); this.Selection = pos; return(moves); } // reset this.Selection = new position_t(); return(new List <position_t>()); }
private static int mimaab(ChessBoard board, Player turn, int depth, int alpha, int beta) { // base case, at maximum depth return board fitness if (depth >= DEPTH) { return(board.fitness(MAX)); } else { List <ChessBoard> boards = new List <ChessBoard>(); // get available moves / board states from moves for the current player foreach (position_t pos in board.Pieces[turn]) { if (STOP) { return(-1); // interupts } List <position_t> moves = LegalMoveSet.getLegalMove(board, pos); foreach (position_t move in moves) { if (STOP) { return(-1); // interupts } ChessBoard b2 = LegalMoveSet.move(board, new move_t(pos, move)); boards.Add(b2); } } int a = alpha, b = beta; if (turn != MAX) // minimize { foreach (ChessBoard b2 in boards) { if (STOP) { return(-1); // interupt } b = Math.Min(b, mimaab(b2, (turn == Player.WHITE) ? Player.BLACK : Player.WHITE, depth + 1, a, b)); if (a >= b) { return(a); } } return(b); } else // maximize { foreach (ChessBoard b2 in boards) { if (STOP) { return(-1); // interupt } a = Math.Max(a, mimaab(b2, (turn == Player.WHITE) ? Player.BLACK : Player.WHITE, depth + 1, a, b)); if (a >= b) { return(b); } } return(a); } } }
public static move_t MiniMaxAB(ChessBoard board, Player turn) { RUNNING = true; // we've started running STOP = false; // no interupt command sent MAX = turn; // who is maximizing // gather all possible moves Dictionary <position_t, List <position_t> > moves = LegalMoveSet.getPlayerMoves(board, turn); // because we're threading safely store best result from each thread int[] bestresults = new int[moves.Count]; move_t[] bestmoves = new move_t[moves.Count]; // thread the generation of each move Parallel.ForEach(moves, (movelist, state, index) => { if (STOP) // interupt { state.Stop(); return; } // initialize thread best bestresults[index] = int.MinValue; bestmoves[index] = new move_t(new position_t(-1, -1), new position_t(-1, -1)); // for each move for the current piece(thread) foreach (position_t move in movelist.Value) { if (STOP) // interupt { state.Stop(); return; } // make initial move and start recursion ChessBoard b2 = LegalMoveSet.move(board, new move_t(movelist.Key, move)); int result = mimaab(b2, (turn == Player.WHITE) ? Player.BLACK : Player.WHITE, 1, Int32.MinValue, Int32.MaxValue); // if result is better or best hasn't been set yet if (bestresults[index] < result || (bestmoves[index].to.Equals(new position_t(-1, -1)) && bestresults[index] == int.MinValue)) { bestresults[index] = result; bestmoves[index].from = movelist.Key; bestmoves[index].to = move; } } }); // interupted if (STOP) { return(new move_t(new position_t(-1, -1), new position_t(-1, -1))); } // find the best of the thread results int best = int.MinValue; move_t m = new move_t(new position_t(-1, -1), new position_t(-1, -1)); for (int i = 0; i < bestmoves.Length; i++) { if (best < bestresults[i] || (m.to.Equals(new position_t(-1, -1)) && !bestmoves[i].to.Equals(new position_t(-1, -1)))) { best = bestresults[i]; m = bestmoves[i]; } } return(m); }
private static List <position_t> Pawn(ChessBoard board, position_t pos, bool verify_check = true) { List <position_t> moves = new List <position_t>(); piece_t p = board.Grid[pos.number][pos.letter]; if (p.piece == Piece.NONE) { return(moves); } // gather relative moves List <position_t> relative = new List <position_t>(); relative.Add(new position_t(-1, 1 * ((p.player == Player.BLACK) ? -1 : 1))); relative.Add(new position_t(0, 1 * ((p.player == Player.BLACK) ? -1 : 1))); relative.Add(new position_t(0, 2 * ((p.player == Player.BLACK) ? -1 : 1))); relative.Add(new position_t(1, 1 * ((p.player == Player.BLACK) ? -1 : 1))); // iterate moves foreach (position_t move in relative) { position_t moved = new position_t(move.letter + pos.letter, move.number + pos.number); // bounds check if (moved.letter < 0 || moved.letter > 7 || moved.number < 0 || moved.number > 7) { continue; } // double forward move if (moved.letter == pos.letter && board.Grid[moved.number][moved.letter].piece == Piece.NONE && Math.Abs(moved.number - pos.number) == 2) { // check the first step int step = -((moved.number - pos.number) / (Math.Abs(moved.number - pos.number))); bool hasnt_moved = pos.number == ((p.player == Player.BLACK) ? 6 : 1); if (board.Grid[moved.number + step][moved.letter].piece == Piece.NONE && hasnt_moved) { moves.Add(moved); } } // if it's not blocked we can move forward else if (moved.letter == pos.letter && board.Grid[moved.number][moved.letter].piece == Piece.NONE) { moves.Add(moved); } // angled attack else if (moved.letter != pos.letter && board.Grid[moved.number][moved.letter].piece != Piece.NONE && board.Grid[moved.number][moved.letter].player != p.player) { moves.Add(moved); } // en passant else if (isEnPassant(board, new move_t(pos, moved))) { moves.Add(moved); } } if (verify_check)// make sure each move doesn't put us in check { for (int i = moves.Count - 1; i >= 0; i--) { ChessBoard b2 = LegalMoveSet.move(board, new move_t(pos, moves[i])); if (isCheck(b2, p.player)) { moves.RemoveAt(i); } } } return(moves); }
private static List <position_t> King(ChessBoard board, position_t pos, bool verify_check = true) { List <position_t> moves = new List <position_t>(); piece_t p = board.Grid[pos.number][pos.letter]; if (p.piece == Piece.NONE) { return(moves); } // collect all relative moves possible List <position_t> relative = new List <position_t>(); relative.Add(new position_t(-1, 1)); relative.Add(new position_t(0, 1)); relative.Add(new position_t(1, 1)); relative.Add(new position_t(-1, 0)); relative.Add(new position_t(1, 0)); relative.Add(new position_t(-1, -1)); relative.Add(new position_t(0, -1)); relative.Add(new position_t(1, -1)); // Iterate moves foreach (position_t move in relative) { position_t moved = new position_t(move.letter + pos.letter, move.number + pos.number); // bound check if (moved.letter < 0 || moved.letter > 7 || moved.number < 0 || moved.number > 7) { continue; } // if it's not blocked we can move if (board.Grid[moved.number][moved.letter].piece == Piece.NONE || board.Grid[moved.number][moved.letter].player != p.player) { if (verify_check) // make sure we don't put ourselves in check { ChessBoard b2 = LegalMoveSet.move(board, new move_t(pos, moved)); if (!isCheck(b2, p.player)) { moves.Add(moved); } } else { moves.Add(moved); } } } // Castling /* A king can only castle if: * king has not moved * rook has not moved * king is not in check * king does not end up in check * king does not pass through any other peieces * king does not pass through any squares under attack * king knows secret handshake */ if (verify_check) { if (!isCheck(board, p.player) && p.lastPosition.Equals(new position_t(-1, -1))) { bool castleRight = allowCastle(board, p.player, pos, true); bool castleLeft = allowCastle(board, p.player, pos, false); if (castleRight) { moves.Add(new position_t(6, pos.number)); } if (castleLeft) { moves.Add(new position_t(2, pos.number)); } } } return(moves); }
private void BoardClick(object sender, EventArgs e) { if (chess != null && !m_checkmate) { // clear board for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { Board[i][j].BackColor = ((i + j) % 2 == 0) ? Color.Black : Color.White; } } for (int i = 0; i < 8; i++) { int k = Array.IndexOf(Board[i], sender); if (k > -1) { // draw highlighting if ((!m_manualBoard || m_finalizedBoard) && !m_aigame) { List <position_t> moves = chess.Select(new position_t(k, i)); foreach (position_t move in moves) { if ((chess.Board.Grid[move.number][move.letter].player != chess.Turn && chess.Board.Grid[move.number][move.letter].piece != Piece.NONE) || LegalMoveSet.isEnPassant(chess.Board, new move_t(chess.Selection, move))) { // attack Board[move.number][move.letter].BackColor = Color.Red; } else { // move Board[move.number][move.letter].BackColor = Color.Yellow; } } } // place piece else { chess.Board.SetPiece(m_manualPiece, m_manualPlayer, k, i); SetPiece(m_manualPiece, m_manualPlayer, k, i); if (m_manualPiece == Piece.KING) { if (m_manualPlayer == Player.WHITE) { White_King.Enabled = false; } else { Black_King.Enabled = false; } // both players have kings, we could technically start if (!White_King.Enabled && !Black_King.Enabled) { doneToolStripMenuItem.Enabled = true; } } } } } } }