public void Color_should_be_set_for_new_instance() { PieceColor expected = PieceColor.White; Piece piece = new Piece(expected, 0, 0); PieceColor actual = piece.Color; Assert.AreEqual(expected, actual); }
//returns all possible moves, including jumps and regular moves, given a board and a turn public static List<Move> GenerateAllMoves(Piece[,] cboard, bool turn) { var possibleMoves = new List<Move>(); for (var x = 0; x < 6; x++) { for (var y = 0; y < 6; y++) { possibleMoves.AddRange(GenerateSingleJumps(cboard, x, y, turn)); } } //if there were no jumps, check for regular moves if (possibleMoves.Count == 0) { for (var x = 0; x < 6; x++) { for (var y = 0; y < 6; y++) { possibleMoves.AddRange(GenerateSingleMove(cboard, x, y, turn)); } } } return possibleMoves; }
public void SetPosition(bool animable, Field field, Piece toDestroy, double? x = null, double? y = null) { var thicknessOld = new Point(Drawable.Margin.Left, Drawable.Margin.Top); Point thicknessNew; if (x != null && y != null) thicknessNew = new Point((double) x + Board.PieceMargin, (double) y + Board.PieceMargin); else thicknessNew = new Point(field.DisplayX + Board.PieceMargin, field.DisplayY + Board.PieceMargin); if (animable) { AnimableMove(thicknessOld, thicknessNew, toDestroy); } else { Drawable.Margin = new Thickness(thicknessNew.X, thicknessNew.Y, 0, 0); if (IsKing) KingImage.Margin = Drawable.Margin; } Field = field; if (!IsKing && field.Y == FinishY) { IsKing = true; KingImage = new Image { Source = new BitmapImage(new Uri(KingUrlString)), Width = Drawable.Width, Height = Drawable.Height }; Board.BoardCanvas.Children.Add(KingImage); } if (IsKing) KingImage.Margin = Drawable.Margin; }
//construct node from just a board state public Node(Piece[,] b) { Parent = null; CBoard = b; Alpha = int.MinValue; Beta = int.MaxValue; }
public void Update() { if (p != null) p.Update(); if (killPc) if (p.kill()) { p = null; killPc = false; } }
//returns all possible moves thare are jumps, given a board and a turn public static List<Move> GenerateAllJumps(Piece[,] cboard, bool turn) { var possibleMoves = new List<Move>(); for (var x = 0; x < 6; x++) { for (var y = 0; y < 6; y++) { possibleMoves.AddRange(GenerateSingleJumps(cboard, x, y, turn)); } } return possibleMoves; }
//function to check if two boards are in the same state public static bool Check(Piece[,] x, Piece[,] y) { var check = 0; for (var i = 0; i < 6; i++) { for (var j = 0; j < 6; j++) { if (x[i, j] == null || y[i, j] == null) { if (x[i, j] == null && y[i, j] == null) check++; } else if (x[i, j].Color == y[i, j].Color) check++; } } return check == 36; }
//will return a new board with the provided move applied //will not alter the original board public static Piece[,] CopyAndMove(Piece[,] cboard, Move m) { var newBoard = new Piece[6,6]; for (var x = 0; x < 6; x++) { for (var y = 0; y < 6; y++) { if (cboard[x,y] != null) { newBoard[x,y] = new Piece(cboard[x,y]); } } } MakeMove(newBoard,m); return newBoard; }
public async void AnimableMove(Point thicknessOld, Point thicknessNew, Piece toDestroy) { for (var i = 0; i <= 15; ++i) { var point = new Point((thicknessNew.X * i + thicknessOld.X * (15 - i)) / 15, (thicknessNew.Y * i + thicknessOld.Y * (15 - i)) / 15); Drawable.Margin = new Thickness(point.X, point.Y, 0, 0); if (IsKing) KingImage.Margin = Drawable.Margin; await Task.Delay(250 / 15); if (i == 7 && toDestroy != null) toDestroy.Destroy(); } }
/// <summary> /// Returns a list of all possible directions that a specified piece can move in (does not take neighboring pieces or the edge of the board into account). /// </summary> /// <param name="piece">The piece to determine where it can move to.</param> /// <returns></returns> private static List<Directions> PossibleDirections(Piece piece) { List<Directions> retVal = new List<Directions>(4); //If the player is black, which starts out on top, or the piece is a king then add DownRight and DownLeft to movesFound. if (piece.Player == Players.Black || piece.King) { //If there is a square right of source and it is empty then add DownRight to movesFound. retVal.Add(Directions.DownRight); //DownLeft retVal.Add(Directions.DownLeft); } //If the player is red, which starts out at the bottom of the board, or the piece is a king then add UpRight and UpLeft to RetVal. if (piece.Player == Players.Red || piece.King) { //UpRight retVal.Add(Directions.UpRight); //UpLeft retVal.Add(Directions.UpLeft); } return retVal; }
public static Board GetStartingBoard() { Piece[] squares = new Piece[64]; BoardStatus status = new BoardStatus(); var blackInitial = new List<int>() { 1,3,5,7,8,10,12,14,17,19,21,23 }; foreach (var i in blackInitial) { squares[i] = new BlackChecker(); } var whiteInitial = new List<int>() { 40, 42, 44, 46, 49, 51, 53, 55, 56, 58, 60, 62 }; foreach (var i in whiteInitial) { squares[i] = new WhiteCheker(); } status.WhiteTurn = true; status.Moves = 1; return new Board(squares, status); }
//returns a list of boards, given a list of possible jumps, a board, and a turn //the returned list will contain the final board states of all possible jump strings public static List<Piece[, ]> GenerateJumps(List<Move> moves, Piece[,] cboard, bool turn) { var bQueue = new Queue<Tuple<Piece[,], int, int>>(); var bFinal = new List<Piece[,]>(); //create a board with each possible jump and add them to a queue, along with the moved piece foreach (var m in moves) { bQueue.Enqueue(new Tuple<Piece[,], int, int>(Move.CopyAndMove(cboard, m), (int)m.End.X, (int)m.End.Y)); } //while there are boards in the queue go through them while (bQueue.Any()) { //dequeue the first board var tBoard = bQueue.Dequeue(); //generate all possible jumps with the piece that already jumped List<Move> tMoves = Move.GenerateSingleJumps(tBoard.Item1, tBoard.Item2, tBoard.Item3, turn); //if there are any, enqueue all the new boards if (tMoves.Count > 0) foreach (Move m in tMoves) { bQueue.Enqueue(new Tuple<Piece[,], int, int>(Move.CopyAndMove(tBoard.Item1, m), (int)m.End.X, (int)m.End.Y)); } //otherwise the current board is a finalized jump string else bFinal.Add(tBoard.Item1); } return bFinal; }
public void PiecePrint(Piece a) { if (a.Color == 'b') { Console.ForegroundColor = ConsoleColor.Green; } else { Console.ForegroundColor = ConsoleColor.Red; } Console.WriteLine(type); Console.ResetColor(); }
//generate a list of boards given a list of moves and a starting board static List<Piece[, ]> GenerateBoards(List<Move> moves, Piece[,] cboard ) { var boards = new List<Piece[,]>(); foreach (var m in moves) { boards.Add(Move.CopyAndMove(cboard,m)); } return boards; }
public Piece(Piece p) { this.Color = p.Color; }
//evaluation function public static int UtilityFunc(Piece[,] b, bool turn) { int best = int.MinValue; //checks if the node has any jumps for the current player, //if there are, it will find the value of the best possible jump string //finds all possible jump strings var alljumps = Move.GenerateJumps(Move.GenerateAllJumps(b, turn), b, turn); //if any jumps if (alljumps.Any()) { foreach (var board in alljumps) { int count = 0; for (var i = 0; i < 6; i++) { for (var j = 0; j < 6; j++) { { if (board[i, j] != null) { //if red subtract //if black add //4 if (board[i, j]) count -= 3; else count += 3; } } } } //2 //if it's the computer's turn, subtract 5 //else add 5 if (!turn) count -= 5; else count += 5; //save the best possible value if (count > best) best = count; } } //otherwise just use the current board state else { int count = 0; for (var i = 0; i < 6; i++) { for (var j = 0; j < 6; j++) { { if (b[i, j] != null) { //if red subtract //if black add if (b[i, j]) count -= 4; else count += 4; } } } } //if its the player's turn subtract 2 //otherwise add 2 if (turn) count -= 2; else count += 2; best = count; } return best; }
//the main alpha-beta search function //takes in a board state, the current turn, and the maximum depth that the function should go to //returns a board state public static Piece[,] AlphaBetaSearch(Piece[,] cboard, int turn, int maxDepth) { //write some info to the console Console.WriteLine("Starting Alpha-Beta Search"); Console.WriteLine("Turn: " + turn); //depth counter int depth = 0; //value of best node Value v; //counter class holding statistics Counter c; //set values c.Nodes = 1; c.Minprune = 0; c.Maxprune = 0; c.Maxdepth = 0; //start counting time var startTime = DateTime.Now; //if the difficulty is set to very hard, increase depth as the //number of turns increases if(maxDepth == 18) { switch (turn) { case 0: _currentdepth = maxDepth; break; case 1: _currentdepth = maxDepth; break; case 2: _currentdepth = maxDepth + 2; break; case 3: _currentdepth = maxDepth + 3; break; case 4: _currentdepth = maxDepth + 5; break; case 5: _currentdepth = maxDepth + 7; break; default: _currentdepth = maxDepth + 100; break; } } else _currentdepth = maxDepth; //create root node Node p = new Node(cboard); //start the search v = MaxValue(ref p, ref c, depth); //go up the chain of parents until reaching the proper move to choose p = v.Nod; while(p.Parent.Parent != null) { p = p.Parent; } //write out the statistics Console.WriteLine( "Nodes: " + c.Nodes + "\n" + "Min Prune: " + c.Minprune + "\n" + "Max Prune: " + c.Maxprune + "\n" + "Maximum Depth: " + c.Maxdepth); Console.WriteLine("Time Elapsed: " + (DateTime.Now - startTime) + "\n"); return p.CBoard; }
//will generate a list of single jumps, given a board, a piece's position, and the turn public static List<Move> GenerateSingleJumps(Piece[,] cboard, int x, int y, bool turn ) { var possibleMoves = new List<Move>(); if (cboard[x, y] != null && cboard[x, y] == turn) { //check jumps if (x >= 2) { if (y >= 2) { if (cboard[x - 1, y - 1] != null) if (cboard[x - 1, y - 1] != turn && cboard[x - 2, y - 2] == null) possibleMoves.Add(new Move(new Vector2(x, y), new Vector2(x - 2, y - 2))); } if (y <= 3) { if (cboard[x - 1, y + 1] != null) if (cboard[x - 1, y + 1] != turn && cboard[x - 2, y + 2] == null) possibleMoves.Add(new Move(new Vector2(x, y), new Vector2(x - 2, y + 2))); } } if (x <= 3) { if (y >= 2) { if (cboard[x + 1, y - 1] != null) if (cboard[x + 1, y - 1] != turn && cboard[x + 2, y - 2] == null) possibleMoves.Add(new Move(new Vector2(x, y), new Vector2(x + 2, y - 2))); } if (y <= 3) { if (cboard[x + 1, y + 1] != null) if (cboard[x + 1, y + 1] != turn && cboard[x + 2, y + 2] == null) possibleMoves.Add(new Move(new Vector2(x, y), new Vector2(x + 2, y + 2))); } } } return possibleMoves; }
/// <summary> /// Returns a dictionary with the key the squares that the specified piece can move to and the value a list of the pieces that would be jumped if that piece moves to the key. /// </summary> /// <param name="board">A 2-dimensional array of squares representing the board.</param> /// <param name="currentPiece">The piece that is being moved.</param> /// <returns>A dictionary with the key the squares that the piece on the specified square can move to and the value a list of the pieces that would be jumped if that piece moves to the key.</returns> public static Dictionary<Square, List<Piece>> PossibleMoves(Square[,] board, Piece pieceMoved) { return RecursivePossibleMoves(board, pieceMoved, pieceMoved.Location, new Dictionary<Square, List<Piece>>( )); }
public void remPiece() { p = null; }
//generates all valid moves for a single piece //will only return jumps if one is found //takes a board, a piece position, and the turn public static List<Move> GenerateSingleAll(Piece[,] cboard, int x, int y, bool turn) { var possibleMoves = new List<Move>(); possibleMoves.AddRange(GenerateSingleJumps(cboard, x, y, turn)); if (possibleMoves.Count == 0) possibleMoves.AddRange(GenerateSingleMove(cboard, x, y, turn)); return possibleMoves; }
public bool validateAttack(Piece srcPc, Vector src, Vector possAttack) { Vector tmp = findEnemy(possAttack, src); //Finds the enemy if(tmp != null) //If the enemy exists. return isKingClear(tmp.stepBack(), src); //Check if the path between enemy and king is clear. return false; //Else return false cause there is no enemy ! }
public void setPiece(Piece game_piece) { p = game_piece; }
public static Piece[,] AlphaBetaSearch(Piece[,] cboard) { Console.WriteLine("Starting"); int depth = 0; int v = int.MinValue; counter c; c.nodes = 1; c.minprune = 0; c.maxprune = 0; var startTime = DateTime.Now; Node p = new Node(cboard); List<Move> moves = Move.GenerateAllMoves(p.CBoard, false); if (moves.Count() > 0) if (moves[0].Jump) { var pairs = new List<Tuple<Piece[,], int>>(); foreach (Piece[,] b in GenerateJumps(moves, p.CBoard, false)) { Node tNode = new Node(b); tNode.Alpha = p.Alpha; tNode.Beta = p.Beta; tNode.Parent = p; v = Math.Max(v, MinValue(ref tNode, ref c, depth)); if (v >= p.Beta) { Console.WriteLine("Time Elapsed: " + (DateTime.Now - startTime)); return b; } p.Alpha = Math.Max(p.Alpha, v); pairs.Add(new Tuple<Piece[,], int>(b, v)); } foreach (var d in pairs) { if (d.Item2 == v) { Console.WriteLine("Time Elapsed: " + (DateTime.Now - startTime)); return d.Item1; } } } else { var pairs = new List<Tuple<Move, int>>(); foreach (Move m in moves) { Node tNode = new Node(p, m, p.Alpha, p.Beta); v = Math.Max(v,MinValue(ref tNode, ref c, depth)); if (v >= p.Beta) { Console.WriteLine("Time Elapsed: " + (DateTime.Now - startTime)); return Move.CopyAndMove(cboard, m); } p.Alpha = Math.Max(p.Alpha, v); pairs.Add(new Tuple<Move, int>(m, v)); } foreach (var d in pairs) { if (d.Item2 == v) { Console.WriteLine("Time Elapsed: "+ (DateTime.Now - startTime)); return Move.CopyAndMove(cboard, d.Item1); } } } return Move.CopyAndMove(cboard,new Move(new Vector2(1), new Vector2(1)) ); }
public bool validateMove(Piece srcPc, Vector src, Vector possMove) { return isKingClear(possMove.stepBack(), src); }
//will generate all single moves for a single piece, given a board, a peice position, and a turn public static List<Move> GenerateSingleMove(Piece[,] cboard, int x, int y, bool turn) { var possibleMoves = new List<Move>(); if (cboard[x, y] != null && cboard[x, y] == turn) { if (turn && y > 0) { if (x > 0 && cboard[x - 1, y - 1] == null) possibleMoves.Add(new Move(new Vector2(x, y), new Vector2(x - 1, y - 1))); if (x < 5 && cboard[x + 1, y - 1] == null) possibleMoves.Add(new Move(new Vector2(x, y), new Vector2(x + 1, y - 1))); } else if (!turn && y < 5) { if (x > 0 && cboard[x - 1, y + 1] == null) possibleMoves.Add(new Move(new Vector2(x, y), new Vector2(x - 1, y + 1))); if (x < 5 && cboard[x + 1, y + 1] == null) possibleMoves.Add(new Move(new Vector2(x, y), new Vector2(x + 1, y + 1))); } } return possibleMoves; }
/// <summary> /// Returns a dictionary with the key the squares that the specified piece can move to from the specified square and the value a list of the pieces that would be jumped if that piece moves to the key. It is recursive. /// </summary> /// <param name="source">The square to determine the possible moves from. It does not necessarily contain a piece.</param> /// <param name="PieceMoved">The piece that is being moved, even if it is moved from a different square.</param> /// <param name="movesFound">A dictionary of the results found so far. If it is not called recursively then it should be an empty list.</param> /// <returns>A dictionary with the key the squares that the piece on the specified square can move to and the value a list of the pieces that would be jumped if that piece moves to the key.</returns> private static Dictionary<Square, List<Piece>> RecursivePossibleMoves(Square[,] board, Piece pieceMoved, Square source, Dictionary<Square, List<Piece>> movesFound) { Dictionary<Square, List<Piece>> retVal = new Dictionary<Square, List<Piece>>(movesFound); List<Directions> directions = PossibleDirections(pieceMoved); //A list of all directions that source.Piece can move in if the surrounding squares are empty and it is not in that edge of the board. foreach (Directions direction in directions) { //For each direction in which source.Piece might be able to move. Square adjSquare = AdjacentSquare(board, source, direction); //The square on direction's side from source. if (adjSquare == null) //If source is on the edge of the board. continue; //If this function was called for a single move (and wasn't called for the second move of a multi-jump) and adjSquare is empty the source.Piece can move there, so add adjSquare to movesFound. if (pieceMoved.Location == source && adjSquare.Piece == null) { retVal.Add(adjSquare, new List<Piece>( )); //The list of pieces jumped should be empty. continue; } //If adjSquare belongs to the opponent of source.Piece.Player and the next square (if it exists) in direction is empty then source.Piece can jump adjSquare.Piece if (adjSquare.Piece != null && adjSquare.Piece.Player != pieceMoved.Player) { Square nextSquare = AdjacentSquare(board, adjSquare, direction); //If adjSquare is at the edge of the board then nextSquare would be null. If nextSquare is not null and it is empty and nextSquare was not found before and it is not the orignal square then add nextSquare to movesFound. if (nextSquare != null && nextSquare.Piece == null && !retVal.ContainsKey(nextSquare) && nextSquare != pieceMoved.Location) { retVal.Add(nextSquare, new List<Piece> { adjSquare.Piece }); //Add the nextSquare as the key because source.Piece can move there and adjSquare.Piece as the value because it would be jumped. //Implement double-jumps by calling PossibleMoves on nextSquare. Add all items that jump in the return value to retVal. foreach (KeyValuePair<Square, List<Piece>> item in RecursivePossibleMoves(board, pieceMoved, nextSquare, retVal)) { if (item.Value != null && !retVal.ContainsKey(item.Key)) { item.Value.Add(adjSquare.Piece); //This move will also jump adjSquare. retVal.Add(item.Key, item.Value); } } } } } return retVal; }
//will make a move, given a board and a move to do public static void MakeMove(Piece[,] cboard, Move m) { int startX = (int)m.Start.X; int startY = (int)m.Start.Y; int endX = (int)m.End.X; int endY = (int)m.End.Y; if (m.Jump) { int dx = startX - endX; int dy = startY - endY; cboard[startX - dx/2, startY - dy/2] = null; cboard[endX, endY] = cboard[startX, startY]; cboard[startX,startY] = null; } else { cboard[endX, endY] = cboard[startX, startY]; cboard[startX, startY] = null; } }
public Tile(Piece pc) { p = pc; killPc = false; }
static List<Piece[, ]> GenerateJumps(List<Move> moves, Piece[,] cboard, bool turn) { Queue<Piece[,]> bQueue = new Queue<Piece[,]>(); List<Piece[,]> bFinal = new List<Piece[,]>(); foreach (var m in moves ) { bQueue.Enqueue(Move.CopyAndMove(cboard,m)); } while(bQueue.Any()) { Piece[,] tBoard = bQueue.Dequeue(); List<Move> tMoves = Move.GenerateAllJumps(tBoard, turn); if(tMoves.Count>0) foreach(Move m in Move.GenerateAllJumps(tBoard,turn)) { bQueue.Enqueue(Move.CopyAndMove(tBoard,m)); } else bFinal.Add(tBoard); } return bFinal; }