/// <summary> /// Safely read from a file and convert to our coordinate data and /// First list is source, destanation coordinates and (if there are) capture list /// </summary> /// <param name="stream"></param> /// <param name="board"></param> /// <param name="path"></param> /// <param name="playerColor">return the last played player</param> /// <returns>returns a coordinate list which repesnt the move and captures</returns> public IList<Coordinate> ReadFromFile(FileStream stream, Board board, string path, out Player playerColor) { IList<Coordinate> cor = new List<Coordinate>(); string temp = string.Empty; if (File.Exists(@path)) { byte[] byteData = new byte[stream.Length]; stream.Read(byteData, 0, (int) stream.Length); string content = Encoding.ASCII.GetString(byteData); cor = ShmulToCoordinate(board, content, out temp); } //Who made the last move if (temp == "B") { playerColor = Player.Black; } else if (temp == "W") { playerColor = Player.White; } else { playerColor = Player.None; } return cor; }
/// <summary> /// Print Board in Console /// </summary> /// <param name="board"></param> /// <param name="writer"></param> private void drawBoard(Board board, TextWriter writer) { var buf1 = new StringBuilder(); var buf2 = new StringBuilder(); writer.WriteLine("+--------------------------------+ +--------------------------------+"); for (int k = 1; k <= 32; k++) { for (int i = 8; i > 0; i--) { int j = 1; if (i%2 == 0) { j = 2; buf1.AppendFormat(" "); } int shift; for (shift = 3; (j <= 8 && shift >= 0); j += 2, shift--) { int cellNum = i*4 - shift; var coord = board[i, j]; string soldierColor; if (board.IsBlack(coord)) { soldierColor = "b"; if (board.IsKing(coord)) soldierColor = "bk"; } else if (board.IsWhite(coord)) { soldierColor = "w"; if (board.IsKing(coord)) soldierColor = "wk"; } else { soldierColor = "."; } k++; buf1.AppendFormat(" | {0} | ", soldierColor); if (cellNum >= 1 && cellNum <= 9) { buf2.AppendFormat(" | {0} | ", cellNum); } else { buf2.AppendFormat(" | {0}| ", cellNum); } } writer.WriteLine("{0} {1}", buf1, buf2); writer.WriteLine("+--------------------------------+ +--------------------------------+"); buf1.Length = 0; buf2.Length = 0; } } buf1.Append("|"); buf2.Append("|"); }
/// <summary> /// Calucalte new game boards which are optional moves /// </summary> /// <param name="board"></param> /// <param name="player"></param> /// <returns></returns> public IDictionary<Board, IList<Coordinate>> CalculateNewBoardsFromCoordinates(Board board, Player player) { IDictionary<Board, IList<Coordinate>> newBoardsPositions = new Dictionary<Board, IList<Coordinate>>(); for (int i = 1; i <= board.Size; i++) { if (board.IsOwner(player, board[i])) { IList<Coordinate> coordinateList = GetMovesInDirection(board, board[i], player); foreach (Coordinate coordinate in coordinateList.Reverse()) { //if a soldier of mine exists in this coord then this coord is not optional; if (board.IsOwner(player, coordinate)) { coordinateList.Remove(coordinate); } //if an oppenent soldier exsist in this coord try capturing him! else if (board.IsOpponentPiece(player, coordinate)) { IList<Coordinate> destList = CoordsToCaptureAndDest(board, board[i], coordinate, player).Values.ToList(); if (destList.Count != 0) { // destList is all the coordinates presenting the board after the capture. foreach (Coordinate coord in destList.Reverse()) { Board nBoard = board.Copy(); nBoard.UpdateBoard(nBoard[nBoard.Search(board[i])], coord); IsBecameAKing(nBoard, coord); IList<Coordinate> temp = new List<Coordinate>(); temp.Add(nBoard[nBoard.Search(board[i])]); temp.Add(nBoard[nBoard.Search(coord)]); newBoardsPositions.Add(nBoard, temp); } } } else if (!board.IsAloacted(coordinate)) { //create new board that represnt board after the move Board nBoard = board.Copy(); nBoard.UpdateBoard(nBoard[nBoard.Search(board[i])], coordinate); IsBecameAKing(nBoard, coordinate); IList<Coordinate> temp = new List<Coordinate>(); temp.Add(nBoard[nBoard.Search(board[i])]); temp.Add(nBoard[nBoard.Search(coordinate)]); newBoardsPositions.Add(nBoard, temp); } } } } return newBoardsPositions; }
/// <summary> /// Checks if draw and return number of moves (draw - if there are 15 king's moves with no captures of both opponent and player) /// </summary> /// <param name="board"></param> /// <param name="coordinate"></param> /// <param name="canCapture"></param> /// <param name="count"></param> public GameState CheckDraw(Board board, Coordinate coordinate, bool canCapture, ref int count) { if (board.IsKing(coordinate) && !canCapture) { count++; if (count == 15) { return GameState.Draw; } } else { count = 0; } return GameState.Undetermined; }
/// <summary> /// Checks if draw and return number of moves (draw - if there are 15 king's moves with no captures of both opponent and player) /// </summary> /// <param name="board"></param> /// <param name="coordinate"></param> /// <param name="captured"></param> public GameState CheckDraw(Board board, Coordinate coordinate, bool captured) { if (board.IsKing(coordinate) && !captured) { countMove++; if (countMove == 15) { return GameState.Draw; } } else { countMove = 0; } return GameState.Undetermined; }
/// <summary> /// Parse input to coordinates /// </summary> /// <param name="input"></param> /// <param name="board"></param> /// <returns></returns> public IList<Coordinate> ParseStrToCoords(string input, Board board) { IList<Coordinate> moves = new List<Coordinate>(); const char delimiterChar = ' '; string[] word = input.Split(delimiterChar); try { Coordinate srcCoord = new Coordinate(board[Int32.Parse(word[0])]); moves.Add(srcCoord); Coordinate destCoord = new Coordinate(board[Int32.Parse(word[1])]); moves.Add(destCoord); } catch (Exception) { return null; } return moves; }
/// <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> /// Evalution function which counts number of pieces per player and calculates if player can be captured /// </summary> /// <param name="board"></param> /// <param name="player"></param> /// <returns></returns> public int Evaluate(Board board, Player player) { const int kingConstant = 120; const int soldierConstant = 100; int score = 0; int blackCaptures = 0; int whiteCaptures = 0; int numWhiteKings = board.NumberOfWhiteKings; int numBlackKings = board.NumberOfBlackKings; int numOfWhiteSold = board.NumberOfWhitePieces; int numOfBlackSold = board.NumberOfBlackPieces; int numOfSoldOnBoard = numWhiteKings + numBlackKings + numOfWhiteSold + numOfBlackSold; if (numOfSoldOnBoard <= 7) return Evaluate2(board, player); int blackScore = (numOfBlackSold*soldierConstant) + (numBlackKings*kingConstant); int whiteScore = (numOfWhiteSold*soldierConstant) + (numWhiteKings*kingConstant); score += ((blackScore - whiteScore)*200)/(blackScore + whiteScore); score += blackScore - whiteScore; for (int i = 1; i <= 32; i++) { if (board.GetPlayer(board[i]) == Player.Black) { blackCaptures += (CanCapture(board, board[i], Player.Black)/(numOfBlackSold + numBlackKings))*30; } else if (board.GetPlayer(board[i]) == Player.White) { whiteCaptures += (CanCapture(board, board[i], Player.White)/(numOfWhiteSold + numWhiteKings))*30; } } score += (blackCaptures - whiteCaptures); return (player == Player.Black) ? score : -score; }
/// <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> /// Finds destination by captured coordinate /// </summary> /// <param name="board"></param> /// <param name="srcCoordinate"></param> /// <param name="oponentCoordinate"></param> /// <returns></returns> public Coordinate FindDestByCap(Board board, Coordinate srcCoordinate, Coordinate oponentCoordinate) { int srcX = srcCoordinate.X; int srcY = srcCoordinate.Y; int oponentX = oponentCoordinate.X; int oponentY = oponentCoordinate.Y; var dest = new Coordinate(); int destX, destY; //find the direction of the optional capture and set destination accordingly if (srcX < oponentX) destX = oponentX + 1; else destX = oponentX - 1; if (srcY < oponentY) destY = oponentY + 1; else destY = oponentY - 1; if (InBounds(board, destX, destY)) { dest = new Coordinate(board[destX, destY]); } return dest; }
/// <summary> /// Write the board state to the console /// </summary> /// <param name="board">The board</param> public void DrawBoard(Board board) { drawBoard(board, Console.Out); }
/// <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> /// Checks if Piece on coordinate became a King /// </summary> /// <param name="board"></param> /// <param name="coordinate"></param> public bool IsBecameAKing(Board board, Coordinate coordinate) { int index; if ((board[index = board.Search(coordinate)].Status == Piece.BlackPiece) && (coordinate.X == 1)) { board[index].Status = Piece.BlackKing; board.NumberOfBlackKings++; board.NumberOfBlackPieces--; } else if ((board[index = board.Search(coordinate)].Status == Piece.WhitePiece) && (coordinate.X == board.Rows)) { board[index].Status = Piece.WhiteKing; board.NumberOfWhiteKings++; board.NumberOfWhitePieces--; } else { return false; } return true; }
/// <summary> /// checks if player lost the game- is he blocked or have no soldiers; /// </summary> /// <param name="player"></param> /// <param name="srcBoard"></param> /// <returns></returns> public bool DidPlayerLost(Player player, Board srcBoard) { var numberplayerPieces = NumberOfPlayerPieces(srcBoard, player); var isplayerBlocked = IsPlayerBlocked(srcBoard, player); if (numberplayerPieces == 0 || isplayerBlocked) { return true; } return false; }
/// <summary> /// For debug /// </summary> /// <param name="board"></param> /// <param name="coordinates"></param> /// <param name="playerColor"></param> /// <returns></returns> private IList<Coordinate> Debugging(Board board, string coordinates, out string playerColor) { IList<Coordinate> coords = new List<Coordinate>(); const char delimiterChar = ' '; string[] word = coordinates.Split(delimiterChar); for (int i = 0; i < word.Length - 1; i++) { int x = Int32.Parse(word[i].Substring(1, 1)); int y = Int32.Parse(word[i].Substring(3, 1)); coords.Add(new Coordinate {X = x, Y = y}); } foreach (var item in coords) { item.Status = board[board.Search(item)].Status; } playerColor = word[word.Length - 1]; return coords; }
/// <summary> /// in case this move isn't a capture- check if valid /// </summary> /// <param name="board"></param> /// <param name="srcCoord"></param> /// <param name="destCoord"></param> /// <param name="player"></param> /// <returns></returns> public bool IsValidMove(Board board, Coordinate srcCoord, Coordinate destCoord, Player player) { //Check if the move is in bounds if (!(InBounds(board, srcCoord.X, srcCoord.Y)) || !(InBounds(board, destCoord.X, destCoord.Y))) return false; //Check if is in direction and not more than 1 step if ((Math.Abs(srcCoord.X - destCoord.X) > 1) || (Math.Abs(srcCoord.Y - destCoord.Y) > 1)) return false; //Find all availables move for the piece IList<Coordinate> coordsInDir = GetMovesInDirection(board, srcCoord, player); //crossing data with available moves and free location return coordsInDir.Contains(destCoord) && !board.IsAloacted(destCoord); }
/// <summary> /// Copy Boards /// </summary> /// <returns></returns> public Board Copy() { var nboard = new Board(); //Array.Copy(board,0,nboard.board,0,Size); for (int i = 1; i <= 32; i++) { nboard[i].Status = this[i].Status; nboard[i].X = this[i].X; nboard[i].Y = this[i].Y; } nboard.NumberOfWhitePieces = this.NumberOfWhitePieces; nboard.NumberOfBlackPieces = this.NumberOfBlackPieces; nboard.NumberOfBlackKings = this.NumberOfBlackKings; nboard.NumberOfWhiteKings = this.NumberOfWhiteKings; nboard.Size = this.Size; nboard.Rows = this.Rows; nboard.Columns = this.Columns; return nboard; }
/// <summary> /// Is opponet won the game by blocking player /// </summary> /// <param name="board"></param> /// <param name="player"></param> /// <returns></returns> public bool IsPlayerBlocked(Board board, Player player) { for (int i = 1; i <= 32; i++) { if (board.GetPlayer(board[i]) == player) { if (!IsCoordinateBlocked(board, board[i], player)) { return false; } } } return true; }
/// <summary> /// Checks if a coordinate can't move (capture or just move) /// </summary> /// <param name="srcBoard"></param> /// <param name="coordinate"></param> /// <param name="player"></param> /// <returns></returns> public bool IsCoordinateBlocked(Board srcBoard, Coordinate coordinate, Player player) { int count = 0; IList<Coordinate> moves = GetMovesInDirection(srcBoard, coordinate, player); if (moves.Count == 0) { return true; } foreach (var move in moves) { if (move.Status == Piece.None) { return false; } if (srcBoard.GetPlayer(move) == player) { count++; if (moves.Count == count) { return true; } } else if (srcBoard.GetPlayer(move) != player) { IDictionary<IList<Coordinate>, Coordinate> captures = CoordsToCaptureAndDest(srcBoard, coordinate, move, player); if (captures.Count > 0) { return false; } } } return true; }
/// <summary> /// checks if the game is already determined (one of the oppenents) /// </summary> /// <param name="player"></param> /// <param name="srcBoard"></param> /// <returns></returns> public bool IsBoardLeaf(Player player, Board srcBoard) { if (DidPlayerLost(player, srcBoard) || (DidPlayerLost(srcBoard.GetOpponent(player), srcBoard))) return true; return false; }
/// <summary> /// Find dictionary of all captures on board per player /// </summary> /// <param name="board"></param> /// <param name="player"></param> /// <returns>dictionary of 2 lists : first list of coordinates (captured coordinates) , second coordinates (src-destination cords)-</returns> public IDictionary<IList<Coordinate>, IList<Coordinate>> FindCaptures(Board board, Player player) { IDictionary<IList<Coordinate>, IList<Coordinate>> res = new Dictionary<IList<Coordinate>, IList<Coordinate>>(); for (int i = 1; i <= 32; i++) { if (board.IsOwner(player, board[i])) { var coordsInDir = GetMovesInDirection(board, board[i], player); if (coordsInDir.Count == 0) break; foreach (Coordinate coordindir in coordsInDir) { if (board.IsOpponentPiece(player, coordindir)) { var coordsToJumpTo = CoordsToCaptureAndDest(board, board[i], coordindir, player); if (coordsToJumpTo.Count != 0) { foreach (var item in coordsToJumpTo) { res.Add(item.Key, new List<Coordinate> {board[i], item.Value}); } } } } } } return res; }
/// <summary> /// Convert Shmul and Limor moves to our coordinate /// </summary> /// <param name="board"></param> /// <param name="coordinates"></param> /// <param name="playerColor"></param> /// <returns>A list of coordinates</returns> private IList<Coordinate> ShmulToCoordinate(Board board, string coordinates, out string playerColor) { IList<Coordinate> coords = new List<Coordinate>(); const char delimiterChar = ' '; string[] word = coordinates.Split(delimiterChar); for (int i = 0; i < word.Length - 1; i++) { int x = Int32.Parse(word[i].Substring(1, 1)); int y = Int32.Parse(word[i].Substring(3, 1)); coords.Add(new Coordinate {X = x, Y = y}); } //If list is not empty if (coords.Count > 0) { //Convert to our ccordinates and update their status foreach (var item in coords) { item.X = 8 - item.X; item.Y++; item.Status = board[board.Search(item)].Status; } } playerColor = word[word.Length - 1]; return coords; }
/// <summary> /// Console application entry /// </summary> private static void Main() { bool input = true; var print = new PrintBoardState(); //Create new board var board = new Board(8); Console.WriteLine("Game started"); //print start board print.DrawBoard(board); Program p = new Program(); Console.WriteLine("for PC vs Human Press 1, for PC vs PC press 2"); while (input) { string type = Console.ReadLine(); if (type == "1") { input = false; p.StartGameWithHuman(board); } else if (type == "2") { input = false; p.StartGameWithPc(board); } else { Console.WriteLine("Incorrect Input, please try again"); } } }
/// <summary> /// Get Moves In Direction /// </summary> /// <param name="board"></param> /// <param name="coordinate"></param> /// <param name="player"></param> /// <returns></returns> public IList<Coordinate> GetMovesInDirection(Board board, Coordinate coordinate, Player player) { //Finds all optional move for player IList<Coordinate> coordinateList = OptionalMoves(board, coordinate, player); if (coordinateList.Count != 0) { //checks if player is the owner of the piece if (board.IsOwner(player, coordinate)) { foreach (Coordinate item in coordinateList.Reverse()) { //Removing coordinates which are not in the piece direction white - forward and black backword (according to board orientation) if (board.IsBlack(coordinate) && (board.IsSoldier(coordinate))) { if (item.X > coordinate.X) { coordinateList.Remove(item); } } if (board.IsWhite(coordinate) && (board.IsSoldier(coordinate))) { if (item.X < coordinate.X) { coordinateList.Remove(item); } } } } } return coordinateList; }
/// <summary> /// Count the number of player pieces on board /// </summary> /// <param name="board"></param> /// <param name="player"></param> /// <returns></returns> public int NumberOfPlayerPieces(Board board, Player player) { switch (player) { case Player.White: { return board.NumberOfWhiteKings + board.NumberOfWhitePieces; } case Player.Black: { return board.NumberOfBlackKings + board.NumberOfBlackPieces; } } return 0; }
/// <summary> /// Check if in bound /// </summary> /// <param name="board"></param> /// <param name="row"></param> /// <param name="column"></param> /// <returns></returns> public bool InBounds(Board board, int row, int column) { return ((row > 0) && (row <= board.Rows) && (column > 0) && (column <= board.Columns)); }
/// <summary> /// Finds 2 boards difference /// </summary> /// <param name="before"></param> /// <param name="after"></param> /// <returns></returns> public IList<Coordinate> FindBoardsDifference(Board before, Board after) { IList<Coordinate> diff = new List<Coordinate>(); for(int i=1;i<=32;i++) { if (before[i] != after[i]) { if (before[i].Status == Piece.None) { diff.Add(before[i]); } if (before[i].Status == before.PieceColor(before[i])) { diff.Add(before[i]); } } } return diff; }
/// <summary> /// Get all valid moves for a coordinate /// </summary> /// <param name="board"></param> /// <param name="coordinate"></param> /// <param name="player"></param> /// <returns></returns> public IList<Coordinate> OptionalMoves(Board board, Coordinate coordinate, Player player) { IList<Coordinate> coordinateList = new List<Coordinate>(); //Check that player own the piece on that coordinate if (board.IsOwner(player, coordinate)) { //Check in bounds if (InBounds(board, coordinate.X + 1, coordinate.Y + 1)) { var temp1 = new Coordinate(board[coordinate.X + 1, coordinate.Y + 1]); coordinateList.Add(temp1); } //Check in bounds if (InBounds(board, coordinate.X + 1, coordinate.Y - 1)) { var temp2 = new Coordinate(board[coordinate.X + 1, coordinate.Y - 1]); coordinateList.Add(temp2); } //Check in bounds if (InBounds(board, coordinate.X - 1, coordinate.Y + 1)) { var temp3 = new Coordinate(board[coordinate.X - 1, coordinate.Y + 1]); coordinateList.Add(temp3); } //Check in bounds if (InBounds(board, coordinate.X - 1, coordinate.Y - 1)) { var temp4 = new Coordinate(board[coordinate.X - 1, coordinate.Y - 1]); coordinateList.Add(temp4); } } return coordinateList; }