// Gets move at row turn in file and makes it public override Move getInput(Board B) { System.Threading.Thread.Sleep(sleepTime); uint turn = B.getTurn() - 1; if (turn <= moves.Count) { Move move = moves.ElementAt((int) turn); return move; } return new Move(); }
// Gets move at row turn in file and makes it public override Move getInput(Board B) { System.Threading.Thread.Sleep(sleepTime); uint turn = B.getTurn() - 1; if (turn <= moves.Count) { Move move = moves.ElementAt((int)turn); return(move); } return(new Move()); }
// Reset the game public void reset() { // Stop the game running = false; paused = false; // Create a new board and update the GUI board = new Board(); gui.updateBoard(board); // White allways starts turnWhite = true; // Update GUI fields gui.putPlayerTurn(turnWhite); gui.putTurn(board.getTurn()); gui.putScore(0); }
// --- The main game loop --- // The game is powered by an infinite loop that works as this: // 1) Get move from active player. // 2) Check validity of move, and make move if valid. // 3) Allow the GUI to run all events as to not freeze the program. // 4) If the move was legal: // * Save move if playback saving is enabled. // * Update the GUI with the new board state. // * Check if the game is over, either by a win or remi. // * Update the GUI with new turn, score, etc. // * Save the current state to a file. // 5) Check if the current state file has been manualy changed. // 6) Allow the GUI to run all events (again) as to not freeze the program. // // The reason we use a loop to control the game instead of a compleatly event // driven design is the we do not want the game to know the differens between // a human player and an AI (which is a requirement of the program). // In an event driven design the AI would either have to be activated be a // human player each turn, or be activated by a very fast timer event, or the // AI would have to run in a different thread. The first two options are not // very nice, and the last would prevent the AI from interacting with the GUI, // because WinForms controls can only be accessed from the thread that created them. // With our loop solutions, none of these issues exist, which is why we feel it is // the best option. public void run() { Move selectedMove = null; bool oldTurnWhite = turnWhite; while (running) { if (paused) { // Run the program at 10 fps if it is paused. Thread.Sleep(100); } else { // gets a new move from the active player if (turnWhite) { selectedMove = white.getInput(board); } else { selectedMove = black.getInput(board); } // Makes the move and switches player if it was a legal move if (Rules.movePossible(board, selectedMove, (turnWhite ? "white" : "black"))) { board.makeMove((turnWhite ? "white" : "black"), selectedMove); turnWhite = !turnWhite; } // Run everything else Application.DoEvents(); // New move accepted, update GUI and check for winner. if (oldTurnWhite != turnWhite) { // Print accepted move gui.putString(selectedMove.ToString()); // Save move to file if (gui.getPlaybackEnabled()) { string name = gui.getFileName(); if (!name.Equals("")) { SaveManager.saveMove(selectedMove, name); } } // Update graphics gui.updateBoard(board); // Check if game over if (checkGameOver()) { return; } // Update turn GUI board.updateTurn(); oldTurnWhite = turnWhite; gui.putPlayerTurn(turnWhite); gui.putTurn(board.getTurn()); gui.putScore(board.getScore("white")); // Save current state fileMonitor.ignoreFor(500); SaveManager.saveCurrent(board); } // Check file monitor checkFileChanged(); } Application.DoEvents(); } }
// Returns a list of all possible moves public static List<Tuple<uint, uint>> getPossibleMoves(Board board, Piece piece) { List<Tuple<uint, uint>> tmpList = new List<Tuple<uint, uint>>(); short yMod; short passantRow; if (piece.getColour() == "white") { yMod = 1; passantRow = 4; } else { yMod = -1; passantRow = 3; } // Take left if (board.withinBoard((int) piece.getX() - 1, (int) piece.getY() + yMod)) { Piece P = board.getPieceAt((uint)(piece.getX() - 1), (uint)(piece.getY() + yMod)); if (P != null) { if (!piece.isSameColour(P)) { tmpList.Add(new Tuple<uint, uint>((uint)(piece.getX() - 1), (uint)(piece.getY() + yMod))); } } } //Take right if (board.withinBoard((int)piece.getX() + 1, (int)piece.getY() + yMod)) { Piece P = board.getPieceAt((uint)(piece.getX() + 1), (uint)(piece.getY() + yMod)); if (P != null) { if (!piece.isSameColour(P)) { tmpList.Add(new Tuple<uint, uint>((uint)(piece.getX() + 1), (uint)(piece.getY() + yMod))); } } } //Move 1 if (board.withinBoard((int)piece.getX(), (int)piece.getY() + yMod)) { Piece P = board.getPieceAt(piece.getX(), (uint)(piece.getY() + yMod)); if (P == null) { tmpList.Add(new Tuple<uint, uint>(piece.getX(), (uint)(piece.getY() + yMod))); } } //Move 2 (Only first move) if (!piece.movedFromInit()) { if (board.withinBoard((int)piece.getX(), (int)piece.getY() + 2 * yMod)) { Piece P = board.getPieceAt(piece.getX(), (uint)(piece.getY() + 2 * yMod)); Piece P2 = board.getPieceAt(piece.getX(), (uint)(piece.getY() + yMod)); if (P == null && P2 == null) { tmpList.Add(new Tuple<uint, uint>(piece.getX(), (uint)(piece.getY() + 2 * yMod))); //((Pawn)piece).setDoubleStepTurn(board.getTurn()); } } } //En Passant if (piece.getY() == passantRow) { if ((piece.getX() + 1) < Board.BOARD_SIZE_X) { Piece P1 = board.getPieceAt(piece.getX() + 1, piece.getY()); if (P1 != null) { if (P1 is Pawn) if (((Pawn)P1).getDoubleStepTurn() == board.getTurn() - 1) tmpList.Add(new Tuple<uint, uint>(piece.getX() + 1, (uint)(piece.getY() + yMod))); } } if ((int)piece.getX() - 1 >= 0) { Piece P2 = board.getPieceAt(piece.getX() - 1, piece.getY()); if (P2 != null) { if (P2 is Pawn) if (((Pawn)P2).getDoubleStepTurn() == board.getTurn() - 1) tmpList.Add(new Tuple<uint, uint>(piece.getX() - 1, (uint)(piece.getY() + yMod))); } } } // Filter for check situations CommonRules.checkFilter(ref tmpList, board, piece); return tmpList; }
// Reset the game public void reset() { // Stop the game running = false; paused = false; // Create a new board and update the GUI board = new Board(); gui.updateBoard(board); // White allways starts turnWhite = true; // Update GUI fields gui.putPlayerTurn(turnWhite); gui.putTurn(board.getTurn()); gui.putScore(0); }
public Tuple<Move, int> runMinMax(Board board, string activePlayer, uint depth, bool max, int alpha, int beta, putScore put) { // Prints number of searched moves put(1); string nonActivePlayer = ""; if (activePlayer == "white") { nonActivePlayer = "black"; } else { nonActivePlayer = "white"; } // First check if this is leaf node if (depth <= 0) { return new Tuple<Move, int>(null, (max ? board.getScore(activePlayer) : board.getScore(nonActivePlayer))); } // Not a leaf node, branch out List<Move> moves = new List<Move>(); // Get moves from active player if (activePlayer == "white") { moves = ChessForms.rules.Rules.getWhiteMoves(board); } else { moves = ChessForms.rules.Rules.getBlackMoves(board); } // Check if no legal moves if (moves.Count == 0) { return new Tuple<Move, int>(null, (max ? MINIMUM : MAXIMUM)); } // Assume horrible best int bestScore = (max ? MINIMUM : MAXIMUM); Tuple<Move, int> bestResult = new Tuple<Move, int>(null, bestScore); // Loop through all moves and minmax them Board nextBoard = new Board(board.getTurn()); Tuple<Move, int> nextResult; foreach (Move move in moves) { nextBoard.Copy(board); nextBoard.makeMove(activePlayer, move); nextResult = runMinMax(nextBoard, nonActivePlayer, depth - 1, !max, alpha, beta, put); // If new best result, then change bestResult. if ((nextResult.Item2 > bestResult.Item2 && max) || (nextResult.Item2 < bestResult.Item2 && !max)) { bestResult = new Tuple<Move, int>(move, nextResult.Item2); } // Alpha-Beta pruning if (max) { alpha = Math.Max(alpha, bestResult.Item2); } else { beta = Math.Min(beta, bestResult.Item2); } if (beta <= alpha) { // Need not explore subtree. break; } // Run events to not stall the entire application while searching. Application.DoEvents(); } return bestResult; }