/// <summary> /// Check GameState /// </summary> /// <param name="player"></param> /// <param name="board"></param> /// <returns></returns> public GameState GetGameState(Player player, Board board) { var rule = new Rules(); var numberplayerPieces = rule.NumberOfPlayerPieces(board, player); var isplayerBlocked = rule.IsPlayerBlocked(board, player); if (numberplayerPieces == 0 || isplayerBlocked) { return GameState.Lost; } var numberopponentPieces = rule.NumberOfPlayerPieces(board, board.GetOpponent(player)); var isopponentBlocked = rule.IsPlayerBlocked(board, board.GetOpponent(player)); if (numberopponentPieces == 0 || isopponentBlocked) { return GameState.Won; } else { return GameState.Undetermined; } }
/// <summary> /// returns the number of ways in which soldier on coord can be captured; /// </summary> /// <param name="board"></param> /// <param name="coord"></param> /// <param name="player"></param> /// <returns></returns> public int CanBeCaptured(Board board, Coordinate coord, Player player) { int num = 0; Rules rule = new Rules(); IList<Coordinate> optionalCoords = rule.OptionalMoves(board, coord, player); IList<Coordinate> coordsInDir = rule.GetMovesInDirection(board, coord, player); //collect all coords behind coord IList<Coordinate> coordsfrombehind = optionalCoords.Where(opCor => !coordsInDir.Contains(opCor)).ToList(); foreach (var cid in coordsInDir) { if (board.GetPlayer(board[cid.X, cid.Y]) == board.GetOpponent(player) && rule.CoordsToCaptureAndDest(board, cid, coord, board.GetOpponent(player)).Count > 0) num++; } foreach (var cfb in coordsfrombehind) { if (board.GetPlayer(board[cfb.X, cfb.Y]) == board.GetOpponent(player) && board.IsKing(coord) && rule.CoordsToCaptureAndDest(board, cfb, coord, board.GetOpponent(player)).Count > 0) num++; } return num; }
/// <summary> /// Pc VS Pc /// </summary> /// <returns> </returns> public void StartGameWithPc(Board board) { int countmovesforDraw = 0; var rule = new Rules(); var print = new PrintBoardState(); int depth; Coordinate srcCoord = new Coordinate(); Coordinate destCoord = new Coordinate(); //Create the file engine who Read\write to file all moves FileEngine file = new FileEngine(); //define that file will be created in the root folder under the name sync.txt string path = "sync.txt"; //define colors. Console.WriteLine("Opponent color is white? [Yes/No]"); Opponet: string opponentColor = Console.ReadLine(); if (!(opponentColor == "Yes" || opponentColor == "yes" || opponentColor == "No" || opponentColor == "no")) { Console.WriteLine("Invalid input,please try again"); goto Opponet; } Player oppColor = (opponentColor == "Yes" || opponentColor == "yes") ? Player.White : Player.Black; Player pcColor = oppColor == Player.White ? Player.Black : Player.White; //define who starts. Console.WriteLine("Opponent Starts? [Yes/No]"); Start: string opponentStarts = Console.ReadLine(); if ( !(opponentStarts == "Yes" || opponentStarts == "yes" || opponentStarts == "No" || opponentStarts == "no")) { Console.WriteLine("Invalid input,please try again"); goto Start; } if (opponentStarts == "Yes" || opponentStarts == "yes") goto OppTurn; goto MyTurn; //oppoenent tuen OppTurn: try { //open file in path with read permision and no sharing using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.None)) { ShowPlayerChange(oppColor); Player color = Player.None; bool capMove = false; IList<Coordinate> oppMove = new List<Coordinate>(); //read moves and captures (if exists) while (oppMove.Count == 0) { oppMove = file.ReadFromFile(stream, board, path, out color); } //Source srcCoord = oppMove.First(); oppMove.RemoveAt(0); //Destination destCoord = oppMove[0]; oppMove.RemoveAt(0); //Captures list var capturesOppdid = oppMove; //if move is not oppoent move or source piece is not opponenet color return to read file if ((color != oppColor) || (board.GetPlayer(srcCoord) != oppColor)) { goto OppTurn; } //Find captures IDictionary<IList<Coordinate>, IList<Coordinate>> capturesAvailable = rule.FindCaptures(board, oppColor); if (capturesAvailable.Count > 0) { var boolean = rule.MapContainsCoordsOfCaptures(capturesAvailable, srcCoord, destCoord, capturesOppdid); if (!boolean) { Console.WriteLine("You must capture maximum opponent soldiers on board"); goto OppTurn; } else { foreach (var coordinate in capturesOppdid) { board[coordinate.X, coordinate.Y].Status = Piece.None; board.UpdateCapturedSoldiers(coordinate, pcColor); capMove = true; } } } if (capMove || rule.IsValidMove(board, srcCoord, destCoord, oppColor)) { board.UpdateBoard(srcCoord, destCoord); rule.IsBecameAKing(board, board[destCoord.X, destCoord.Y]); print.DrawBoard(board); } else { Console.WriteLine("This is not a valid move, please enter again"); goto OppTurn; } //check if game has been determined GameState game = GetGameState(oppColor, board); if (GameState.Draw == CheckDraw(board, board[destCoord.X, destCoord.Y], capMove, ref countmovesforDraw)) { Console.WriteLine("Draw"); return; } if (game == GameState.Lost) { Console.WriteLine("{0} Lost the game and {1} won", oppColor.ToString(), pcColor.ToString()); return; } if (game == GameState.Won) { Console.WriteLine("{0} Won", oppColor.ToString()); return; } } } catch (Exception) { goto OppTurn; } //local turn MyTurn: try { using (var stream = new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) { ShowPlayerChange(pcColor); var alphaBeta = new Alphabeta(); Board temp = new Board(); IList<Coordinate> tempCaptures = new List<Coordinate>(); depth = rule.DefineDepth(board); alphaBeta.AlphaBeta(board, depth, Int32.MinValue, Int32.MaxValue, pcColor, true, ref srcCoord, ref destCoord, ref temp, ref tempCaptures); if ((rule.InBounds(board, srcCoord.X, srcCoord.Y)) && (rule.InBounds(board, destCoord.X, destCoord.Y))) { board = temp.Copy(); print.DrawBoard(board); } //write move to file file.WriteToFile(stream, srcCoord, destCoord, tempCaptures, path, pcColor); //check if game has been determined bool pcCaptured = tempCaptures.Count > 0; GameState game = GetGameState(oppColor, board); if (GameState.Draw == CheckDraw(board, board[destCoord.X, destCoord.Y], pcCaptured, ref countmovesforDraw)) { Console.WriteLine("Draw"); return; } if (game == GameState.Lost) { Console.WriteLine("{0} Lost the game and {1} won", oppColor.ToString(), pcColor.ToString()); return; } if (game == GameState.Won) { Console.WriteLine("{0} Won", oppColor.ToString()); return; } } Thread.Sleep(5000); goto OppTurn; } catch (Exception) { goto MyTurn; } }
/// <summary> /// Human VS PC /// </summary> /// <param name="board"></param> public void StartGameWithHuman(Board board) { int countmovesforDraw = 0; var humanColor = Player.None; var pcColor = Player.None; bool firstTurn = true; var rule = new Rules(); var print = new PrintBoardState(); while (true) { //first turn is always the human's Console.WriteLine("Your turn, please enter a move in format 'from cell number' 'to cell number'"); HumanTurn: bool capMove = false; var input = Console.ReadLine(); IList<Coordinate> coords = ParseStrToCoords(input, board); //If there is no input if (coords == null) { Console.WriteLine("Wrong Input, please try again"); goto HumanTurn; } var srcCoord = coords.First(); var destCoord = coords.Last(); if (firstTurn) { humanColor = board.GetPlayer(srcCoord); pcColor = board.GetOpponent(humanColor); firstTurn = false; } //if select coordinate is not your coordinate then show error message else if (humanColor != board.GetPlayer(srcCoord)) { Console.WriteLine( "This is not your piece , please enter cell number which allocated with your piece color"); goto HumanTurn; } //Fins captures IDictionary<IList<Coordinate>, IList<Coordinate>> capturesAvailable = rule.FindCaptures(board, humanColor); //if there are any captures if (capturesAvailable.Count > 0) { //check if they are contained in captured dictionary by looking on source and destination IList<Coordinate> captures = rule.MapContainsCoords(capturesAvailable, srcCoord, destCoord); //id they are not contained show error message if (captures.Count == 0) { Console.WriteLine("You must capture maximum opponent soldiers on board"); goto HumanTurn; } else { //if there are captures and source and destination are corrrect, update board with move and captures foreach (var coordinate in captures) { board[coordinate.X, coordinate.Y].Status = Piece.None; board.UpdateCapturedSoldiers(coordinate, pcColor); capMove = true; } } } //update board if (capMove || rule.IsValidMove(board, srcCoord, destCoord, humanColor)) { board.UpdateBoard(srcCoord, destCoord); rule.IsBecameAKing(board, board[destCoord.X, destCoord.Y]); print.DrawBoard(board); } else { Console.WriteLine("This is not a valid move, please enter again"); goto HumanTurn; } //check if game is finish by checking if players draw,lost or won GameState game = GetGameState(humanColor, board); if (GameState.Draw == CheckDraw(board, board[destCoord.X, destCoord.Y], capMove, ref countmovesforDraw)) { Console.WriteLine("Draw"); break; } if (game == GameState.Lost) { Console.WriteLine("{0} Lost the game and {1} won", humanColor.ToString(), pcColor.ToString()); break; } if (game == GameState.Won) { Console.WriteLine("{0} Won", humanColor.ToString()); break; } //switch to opponent (PC) ShowPlayerChange(pcColor); var alphaBeta = new Alphabeta(); Board temp = new Board(); IList<Coordinate> tempCaptures = new List<Coordinate>(); //Define depth int depth = rule.DefineDepth(board); //Calling alpha-beta algorithm which return the best move in addition, return source,destination coordinates and a list of captures alphaBeta.AlphaBeta(board, depth, Int32.MinValue, Int32.MaxValue, pcColor, true, ref srcCoord, ref destCoord, ref temp, ref tempCaptures); //Verify the move is in bounds, if yes update the board with it if ((rule.InBounds(board, srcCoord.X, srcCoord.Y)) && (rule.InBounds(board, destCoord.X, destCoord.Y))) { board = temp.Copy(); print.DrawBoard(board); } // check if there were any captures. if yes check for draw bool pcCaptured = tempCaptures.Count > 0; //check if game was determined game = GetGameState(humanColor, board); if (GameState.Draw == CheckDraw(board, board[destCoord.X, destCoord.Y], pcCaptured, ref countmovesforDraw)) { Console.WriteLine("Draw"); break; } if (game == GameState.Lost) { Console.WriteLine("{0} Lost the game and {1} won", humanColor.ToString(), pcColor.ToString()); break; } if (game == GameState.Won) { Console.WriteLine("{0} Won", humanColor.ToString()); break; } } }
/// <summary> /// alpha beta algorithm /// boardcoordlist- each item in this map contains a new board (representing a new state) and a list of 2 coords representing the move that brought to this new state /// mapBoardSrcDestCap- each item in this map contains the new board and source- dest coords (like above) and a list of captured coordinate (in case the new board is a result of a capture) /// </summary> /// <param name="board"></param> /// <param name="depth"></param> /// <param name="alpha"></param> /// <param name="beta"></param> /// <param name="player"></param> /// <param name="maxplayer"></param> /// <param name="srcCoord"></param> /// <param name="destCoord"></param> /// <param name="updateBoard"></param> /// <param name="captures"></param> /// <returns></returns> public int AlphaBeta(Board board, int depth, int alpha, int beta, Player player, bool maxplayer, ref Coordinate srcCoord, ref Coordinate destCoord, ref Board updateBoard, ref IList<Coordinate> captures) { var robj = new Rules(); if (depth == 0 || rule.IsBoardLeaf(player, board)) // is node a terminal node { var obj = new HeuristicFunction(); return obj.Evaluate(board, player); //return Heurisitic value of node } //Finds if there are any captures IDictionary<IList<Coordinate>, IList<Coordinate>> capturesAvailable = robj.FindCaptures(board, player); IDictionary<Board, IList<Coordinate>> boardCoordsList; //Calculating board according to current state (with or without captures) if (capturesAvailable.Count > 0) { boardCoordsList = robj.CreateNewBoards(board, capturesAvailable); } else { boardCoordsList = robj.CalculateNewBoardsFromCoordinates(board, player); } //values which save capture list , source, detination on the chosen move var minsrcCoord = new Coordinate(); var mindestCoord = new Coordinate(); var maxsrcCoord = new Coordinate(); var maxdestCoord = new Coordinate(); var maxCapturesList = new List<Coordinate>(); var minCapturesList = new List<Coordinate>(); var minBoard = new Board(); var maxBoard = new Board(); //player if (maxplayer) { foreach (var newState in boardCoordsList) { Coordinate newSrcCoord = newState.Value[0]; Coordinate newDestCoord = newState.Value[1]; IList<Coordinate> capturesList = robj.MapContainsCoords(capturesAvailable, newSrcCoord, newDestCoord); IList<Coordinate> tempCapList = new List<Coordinate>(); int res = AlphaBeta(newState.Key, depth - 1, alpha, beta, board.GetOpponent(player), !maxplayer, ref newSrcCoord, ref newDestCoord, ref updateBoard, ref tempCapList); if (res > alpha) { alpha = res; maxsrcCoord = newState.Value[0]; maxdestCoord = newState.Value[1]; maxBoard = newState.Key.Copy(); maxCapturesList = new List<Coordinate>(capturesList); } if (beta <= alpha) { break; } if (capturesList.Count > 0) { capturesAvailable.Remove(capturesList); } } srcCoord = maxsrcCoord; destCoord = maxdestCoord; updateBoard = maxBoard.Copy(); captures = maxCapturesList; return alpha; } //opponent else { foreach (var newState in boardCoordsList) { Coordinate newSrcCoord = newState.Value[0]; Coordinate newDestCoord = newState.Value[1]; IList<Coordinate> capturesList = robj.MapContainsCoords(capturesAvailable, newSrcCoord, newDestCoord); IList<Coordinate> tempCapList = new List<Coordinate>(); int res = AlphaBeta(newState.Key, depth - 1, alpha, beta, board.GetOpponent(player), !maxplayer, ref newSrcCoord, ref newDestCoord, ref updateBoard, ref tempCapList); if (res < beta) { beta = res; minsrcCoord = newState.Value[0]; mindestCoord = newState.Value[1]; minBoard = newState.Key.Copy(); minCapturesList = new List<Coordinate>(capturesList); } if (beta <= alpha) { break; } if (capturesList.Count > 0) { capturesAvailable.Remove(capturesList); } } srcCoord = minsrcCoord; destCoord = mindestCoord; updateBoard = minBoard.Copy(); captures = minCapturesList; return beta; } }
/// <summary> /// Constructor which perform alphabeta algorithm and set soruce ,destinationn coordinate and return captures list if exists /// </summary> /// <param name="board"></param> /// <param name="player"></param> /// <param name="depth"></param> public Move(IBoardState board, Player player, int depth) { Rules rule = new Rules(); board.Board = board.ConvertBoardStateToBoard(board); var alphaBeta = new Alphabeta(); Board temp = new Board(); var srcCoord = new Coordinate(); var destCoord = new Coordinate(); IList<Coordinate> tempCaptures = new List<Coordinate>(); if (depth%2 != 0) depth++; alphaBeta.AlphaBeta(board.Board, depth, Int32.MinValue, Int32.MaxValue, player, true, ref srcCoord, ref destCoord, ref temp, ref tempCaptures); if ((rule.InBounds(board.Board, srcCoord.X, srcCoord.Y)) && (rule.InBounds(board.Board, destCoord.X, destCoord.Y))) { board.Board = temp.Copy(); board.BoardCells = board.ConvertBoardToBoardState(board.Board); Board = board; } bool pcCaptured = tempCaptures.Count > 0; board.DrawGame = board.CheckDraw(board.Board, board.Board[destCoord.X, destCoord.Y], pcCaptured); }
/// <summary> /// Returns current board state after moveType from position /// </summary> /// <param name="player"></param> /// <param name="moveType"></param> /// <param name="position"></param> /// <param name="needToContinueEating"></param> /// <param name="mustCapture"></param> /// <returns></returns> public IBoardState GetBoardState(Player player, MoveType moveType, Point position, out bool needToContinueEating,out bool mustCapture) { Rules rule= new Rules(); bool lastmovewasACaptured = false; needToContinueEating = false; this.Board = ConvertBoardStateToBoard(this); var destPoint = ConvertMoveTypeToCoordinate(position, moveType); //returns type point var srcPoint = ConvertPointToCoordinate(position.X, position.Y); // returns type point var srcCoord = new Coordinate { X = srcPoint.X, Y = srcPoint.Y, Status = Board.PieceColor(Board[srcPoint.X, srcPoint.Y]) }; var oppCoord = new Coordinate { X = destPoint.X, Y = destPoint.Y, Status = Board.PieceColor(Board[destPoint.X, destPoint.Y]) }; if (!CheckValidPieceColor(this.Board, srcPoint.X, srcPoint.Y, player)) { needToContinueEating = false; mustCapture = false; return null; } if (!IsEmptyCoord(Board, destPoint.X, destPoint.Y) && CheckValidPieceColor(Board, destPoint.X, destPoint.Y, player)) { needToContinueEating = false; mustCapture = false; return null; } if (!IsEmptyCoord(Board, destPoint.X, destPoint.Y) && !CheckValidPieceColor(Board, destPoint.X, destPoint.Y, player)) { var captures = rule.CoordsToCaptureAndDest(Board, srcCoord, oppCoord, player); if (captures.Count > 0) { foreach (var listOfCap in captures.Keys) { if (listOfCap.Last() == oppCoord) { int length = listOfCap.Count; Coordinate newDestCoord = rule.FindDestByCap(Board, srcCoord, oppCoord); this.Board.UpdateBoard(srcCoord, newDestCoord); this.Board.UpdateCapturedSoldiers(oppCoord, Board.GetOpponent(player)); rule.IsBecameAKing(Board, newDestCoord); Board[oppCoord.X, oppCoord.Y].Status = Piece.None; this.BoardCells = ConvertBoardToBoardState(Board); lastmovewasACaptured = true; drawGame = CheckDraw(Board, Board[newDestCoord.X,newDestCoord.Y], lastmovewasACaptured); if (length > 1) needToContinueEating =true; mustCapture = false; return this; } } mustCapture = true; return null; } } //check if player doesnt have any availble captures- if he does then this move isn't valid var capturesAvaileble = rule.FindCaptures(Board, player); if (capturesAvaileble.Count == 0 ) { if(!rule.IsValidMove(Board, srcCoord, Board[destPoint.X,destPoint.Y],player)) { mustCapture = false; return null; } Board.UpdateBoard(Board[srcPoint.X, srcPoint.Y], Board[destPoint.X, destPoint.Y]); rule.IsBecameAKing(Board, Board[destPoint.X, destPoint.Y]); this.BoardCells = ConvertBoardToBoardState(Board); mustCapture = false; drawGame = CheckDraw(Board, Board[destPoint.X, destPoint.Y], lastmovewasACaptured); return this; } mustCapture = true; return null; }
/// <summary> /// Check the safeness of a coordinate (can be captured). if the sold is on boundary than safe (4) else return the /// delta between number of player soldiers and number of Opp soldiers around the coord. /// </summary> /// <param name="board"></param> /// <param name="coord"></param> /// <param name="player"></param> /// <returns></returns> private int Safeness(Board board, Coordinate coord, Player player) { int playerCoords = 0; int opponentCoords = 0; Rules rule = new Rules(); if (coord.X == 1 || coord.X == 8 || coord.Y == 1 || coord.Y == 8) { return 4; } IList<Coordinate> coordinates = rule.OptionalMoves(board, coord, player); foreach (var coordinate in coordinates) { if (player == board.GetPlayer(coordinate)) { playerCoords++; } else if (board.GetOpponent(player) == board.GetPlayer(coordinate)) { opponentCoords++; } } return playerCoords - opponentCoords; }
/// <summary> /// Checkes whether the coordinate can capture /// </summary> /// <param name="board"></param> /// <param name="coordinate"></param> /// <param name="player"></param> /// <returns></returns> private int CanCapture(Board board, Coordinate coordinate, Player player) { Rules rule = new Rules(); IList<Coordinate> coordinatesinDirection = rule.GetMovesInDirection(board, coordinate, player); int max = 0; foreach (var cid in coordinatesinDirection) { if (board.IsOpponentPiece(player, cid)) { IDictionary<IList<Coordinate>, Coordinate> captures = rule.CoordsToCaptureAndDest(board, coordinate, cid, player); if (captures.Count > 0) { if (captures.ElementAt(0).Key.Count > max) { max = captures.ElementAt(0).Key.Count; } } } } return max; }