static void MinimaxSearch() { /* alpha-beta(player,board,alpha,beta) if(game over in current board position) return winner children = all legal moves for player from this board */ //starting game position (default) GameBoard parent = new GameBoard(); parent.SetNodeType(GameBoard.MinMax.Min); int total_moves = 0; /* //forced loss test parent.SetStones(0, 0, 10, Colour.WHITE); parent.SetStones(1, 0, 3, Colour.BLACK); parent.SetStones(0, 1, 3, Colour.BLACK); parent.SetStones(1, 1, 4, Colour.BLACK); parent.SetStones(3, 0, 0, Colour.NONE); parent.SetStones(0, 3, 0, Colour.NONE); */ Console.WriteLine("Starting move:"); displayBoard(parent); bool turn = false; //turn 0 = player's turn(black,min), turn 1 = our turn(white,max) GameBoard next_move = null; //while we still have moves left, or haven't played over 1000 moves while(total_moves < 5000) { if (turn == false)//their turn (BLACK) { Console.WriteLine("Black - Their Move / Player 1"); //Random moves :( //choose random child int moves = parent.GetChildren().Count; if (moves <= 0) { moves = CalculateMoves(parent); } //player 2 wins if (moves == 0) { break; } Random random_number = new Random(); int black_move = random_number.Next(parent.GetChildren().Count - 1); next_move = parent.GetChildren().ElementAt(black_move); //parent.SetAlphaBetaValue(next_move.GetAlphaBetaValue()); turn = true; } else //my move (WHITE) { Console.WriteLine("White - My Move / Player 2"); //GameBoard start_move = parent; // CalculateMaxMove(parent); //current node is a beta next_move = parent; //GameBoard next_move_tmp = start_move; int counter = 0; //iterative deepening int internal_counter = 1; //keep adding one more iteration while (internal_counter > counter) { int moves = 0; if (next_move.GetChildren().Count > 0) { moves = next_move.GetChildren().Count; } else { moves = CalculateMoves(next_move); } //player 1 wins-need to avoid if (moves == 0) { break; } if (parent.GetNodeType() == GameBoard.MinMax.Min) { if (CalculateMaxMove(next_move) == null) //end node { break; } next_move = CalculateMaxMove(next_move); } else { if (CalculateMinMove(next_move) == null) //end node { break; } next_move = CalculateMinMove(next_move); } counter++; if (counter == internal_counter && internal_counter < 50) //deepen search { internal_counter = internal_counter + 1; } } while (next_move.GetParent().GetParent() != null) { next_move = next_move.GetParent(); } turn = false; } Console.WriteLine("Move #: " + total_moves); displayBoard(next_move); parent = next_move; total_moves++; next_move.SetParent(null); //get rid of useless nodes System.GC.Collect(); // parent is always root node } //TIE if (next_move.GetChildren().Count > 0) { Console.WriteLine("NO winner. Try again..."); return; } //WINNER if (next_move.GetNodeType() == GameBoard.MinMax.Max) { Console.WriteLine("Player 1 wins"); } else { Console.WriteLine("Computer wins"); } return; }
static int CalculateMoves(GameBoard board) { /* goes through all the possible moves * on a gameboard * returns number of moves */ int moves = 0; Colour player_colour = Colour.NONE; GameBoard.MinMax child_type = GameBoard.MinMax.Null; if (board.GetNodeType() == GameBoard.MinMax.Max) { player_colour = Colour.BLACK; child_type = GameBoard.MinMax.Min; }else if (board.GetNodeType() == GameBoard.MinMax.Min) { player_colour = Colour.WHITE; child_type = GameBoard.MinMax.Max; } for (int x = 0; x <= 3; x++) { for (int y = 0; y <= 3; y++) { if (board.ReturnPosition(x,y).stones > 0 && board.ReturnPosition(x,y).colour == player_colour) { //if statement to sort number of stones //1-2 stones = 1 square if (board.ReturnPosition(x, y).stones == 1 || board.ReturnPosition(x, y).stones == 2) { //north int a = x; int b = y + 1; moves = CheckAdjacentMove(board, child_type, player_colour, x, y, a, b, moves); //south a = x; b = y - 1; moves = CheckAdjacentMove(board, child_type, player_colour, x, y, a, b, moves); //east a = x - 1; b = y; moves = CheckAdjacentMove(board, child_type, player_colour, x, y, a, b, moves); //west a = x + 1; b = y; moves = CheckAdjacentMove(board, child_type, player_colour, x, y, a, b, moves); //ne a = x + 1; b = y - 1; moves = CheckAdjacentMove(board, child_type, player_colour, x, y, a, b, moves); //nw a = x - 1; b = y - 1; moves = CheckAdjacentMove(board, child_type, player_colour, x, y, a, b, moves); //se a = x + 1; b = y + 1; moves = CheckAdjacentMove(board, child_type, player_colour, x, y, a, b, moves); //sw a = x - 1; b = y + 1; moves = CheckAdjacentMove(board, child_type, player_colour, x, y, a, b, moves); } else if (board.ReturnPosition(x, y).stones == 3)//3 stones = 2 squares { //north x2 int a = x; int b = y + 1; int c = x; int d = y + 2; moves = CheckTwoSquares(board, child_type, player_colour, x, y, a, b, c, d, moves); //south x2 a = x; b = y - 1; c = x; d = y - 2; moves = CheckTwoSquares(board, child_type, player_colour, x, y, a, b, c, d, moves); //eastx2 a = x - 1; b = y; c = x - 2; d = y; moves = CheckTwoSquares(board, child_type, player_colour, x, y, a, b, c, d, moves); //westx2 a = x + 1; b = y; c = x + 2; d = y; moves = CheckTwoSquares(board, child_type, player_colour, x, y, a, b, c, d, moves); //nex2 a = x + 1; b = y - 1; c = x + 2; d = y - 2; moves = CheckTwoSquares(board, child_type, player_colour, x, y, a, b, c, d, moves); //nwx2 a = x - 1; b = y - 1; c = x - 2; d = y - 2; moves = CheckTwoSquares(board, child_type, player_colour, x, y, a, b, c, d, moves); //se x2 a = x + 1; b = y + 1; c = x + 2; d = y + 2; moves = CheckTwoSquares(board, child_type, player_colour, x, y, a, b, c, d, moves); //swx2 a = x - 1; b = y + 1; c = x - 2; d = y + 2; moves = CheckTwoSquares(board, child_type, player_colour, x, y, a, b, c, d, moves); } else // 4+ stones = 3 squares { //north x3 int a = x; int b = y + 1; int c = x; int d = y + 2; int e = x; int f = y + 3; moves = CheckThreeSquares(board, child_type, player_colour, x, y, a, b, c, d, e, f, moves); //south x3 a = x; b = y - 1; c = x; d = y - 2; e = x; f = y - 3; moves = CheckThreeSquares(board, child_type, player_colour, x, y, a, b, c, d, e, f, moves); //westx3 a = x - 1; b = y; c = x - 2; d = y; e = x - 3; f = y; moves = CheckThreeSquares(board, child_type, player_colour, x, y, a, b, c, d, e, f, moves); //eastx3 a = x + 1; b = y; c = x + 2; d = y; e = x + 3; f = y; moves = CheckThreeSquares(board, child_type, player_colour, x, y, a, b, c, d, e, f, moves); //nex3 a = x + 1; b = y + 1; c = x + 2; d = y + 2; e = x + 3; f = y + 3; moves = CheckThreeSquares(board, child_type, player_colour, x, y, a, b, c, d, e, f, moves); //nwx3 //---------???? a = x - 1; b = y + 1; c = x - 2; d = y + 2; e = x - 3; f = y + 3; moves = CheckThreeSquares(board, child_type, player_colour, x, y, a, b, c, d, e, f, moves); //se x3 a = x + 1; b = y - 1; c = x + 2; d = y - 2; e = x + 3; f = y - 3; moves = CheckThreeSquares(board, child_type, player_colour, x, y, a, b, c, d, e, f, moves); //swx3 a = x - 1; b = y - 1; c = x - 2; d = y - 2; e = x - 3; f = y - 3; moves = CheckThreeSquares(board, child_type, player_colour, x, y, a, b, c, d, e, f, moves); } } } } //store moves in parent - number of squares covereed - failed eval fxn /* int squares = 0; for (int x = 0; x < 4; x++) { for (int y = 0; y < 4; y++) { if (board.ReturnPosition(x, y).colour == player_colour) { squares++; } } } board.SetAlphaBetaValue(squares); return squares; */ board.SetAlphaBetaValue(moves); return moves; }