/* This is the minimax function with alpha beta pruning * * Inputs: board, the current state; depth, the desired search depth; * a, the alpha value; b, the beta value; finalDepth, the total search depth * Output: Tuple<int,int> Result: Item1 = The heuristic of the move. Item2 = the move number */ private Tuple <int, int> alphaBeta(Board board, int depth, int a, int b, int finalDepth) { int v = 0; int v2 = 0; int move = -1; if (board.gameOver() || depth == 0) { return(new Tuple <int, int>(0, evaluate(board, finalDepth))); } if (board.whoseMove() == Position.Top) // Max player's turn { v = -99999; for (int i = 12; i >= 7; i--) // Try each of the possible moves { if (board.legalMove(i) && (move == -1 || timer.ElapsedMilliseconds < getTimePerMove() - 1)) { Board board1 = new Board(board); board1.makeMove(i, false); v2 = alphaBeta(board1, depth - 1, a, b, finalDepth).Item2; // Find value of that move if (v2 > v) // pick the best move { v = v2; move = i; } a = Math.Max(a, v); if (b <= a) { break; } } } return(new Tuple <int, int>(move, v)); // Return the result } else // Minimizing player's turn { v = 99999; for (int i = 5; i >= 0; i--) // Try each of the possible moves { if (board.legalMove(i) && (move == -1 || timer.ElapsedMilliseconds < getTimePerMove() - 1)) { Board board1 = new Board(board); board1.makeMove(i, false); v2 = alphaBeta(board1, depth - 1, a, b, finalDepth).Item2; // Find value of that move if (v2 < v) // Pick the best move { v = v2; move = i; } b = Math.Min(b, v); if (b <= a) { break; } } } return(new Tuple <int, int>(move, v)); // Return the result } }
/* * minimax function * based on the psuedocode from Prof Plantiga's lecture slides */ private Result minimax(Board b, int depth, int alpha, int beta) { int bestNum = 0; int currentBestMove = 0; if (b.gameOver() || depth == 0) // game is over or depth is 0 { return(new Result(0, evaluate(b))); } if (b.whoseMove() == Position.Top) // searching moves for when top player { bestNum = Int32.MinValue; for (int move = 7; move <= 12; move++) { if (b.legalMove(move)) { Board b1 = new Board(b); b1.makeMove(move, false); Result num = minimax(b1, depth - 1, alpha, beta); if (num.getBestScore() > bestNum) { bestNum = num.getBestScore(); currentBestMove = move; } if (bestNum > alpha) { alpha = bestNum; } } } return(new Result(currentBestMove, bestNum)); } else // search moves for when bottom player { bestNum = int.MaxValue; for (int move = 0; move <= 5; move++) { if (b.legalMove(move)) { Board b1 = new Board(b); b1.makeMove(move, false); Result num = minimax(b1, (depth - 1), alpha, beta); if (num.getBestScore() < bestNum) { bestNum = num.getBestScore(); currentBestMove = move; } if (bestNum < beta) { beta = bestNum; } } } return(new Result(currentBestMove, bestNum)); } }
private int[] minmaxVal(Board b, int d, float alpha, float beta, ref Stopwatch timer) { if (d == 0 || b.gameOver()) { return(new int[] { 0, evaluate(b) }); } int[] bestMove = { 0, int.MinValue }; if (b.whoseMove() == us) { int bestVal = int.MinValue; for (int move = 0; move <= 13; move++) { if (b.legalMove(move) && timer.ElapsedMilliseconds < (max_time - 200)) { Board b1 = new Board(b); b1.makeMove(move, false); int[] val = minmaxVal(b1, d - 1, alpha, beta, ref timer); if (val[1] > bestVal) { bestVal = val[1]; bestMove[0] = move; bestMove[1] = bestVal; } alpha = Math.Max(alpha, bestMove[1]); if (beta <= alpha) { break; } } } } else { int bestVal = int.MaxValue; bestMove = new int[] { 0, bestVal }; for (int move = 0; move <= 13; move++) { if (b.legalMove(move) && timer.ElapsedMilliseconds < (max_time - 200)) { Board b1 = new Board(b); b1.makeMove(move, false); int[] val = minmaxVal(b1, d - 1, alpha, beta, ref timer); if (val[1] < bestVal) { bestVal = val[1]; bestMove[0] = move; bestMove[1] = bestVal; } beta = Math.Min(beta, bestMove[1]); if (beta <= alpha) { break; } } } } return(bestMove); }
/* Minimax search * top player is max and bottom is min * returns a resulting move from recursive calculations */ private Result minimax(Board board, int depth, int alpha, int beta) { if (board.gameOver() || depth == 0) { return(new Result(0, evaluate(board))); } int bestVal = int.MinValue; int bestMove = 0; if (board.whoseMove() == Position.Top) { for (int move = 7; move < 13 && alpha < beta; move++) { if (board.legalMove(move)) { Board b1 = new Board(board); b1.makeMove(move, false); Result val = minimax(b1, depth - 1, alpha, beta); if (val.getBestScore() > bestVal) { bestVal = val.getBestScore(); bestMove = move; } if (bestVal > alpha) { alpha = bestVal; } } } } else { bestVal = Int32.MaxValue; for (int move = 0; move < 6 && alpha < beta; move++) { if (board.legalMove(move)) { Board b1 = new Board(board); b1.makeMove(move, false); Result val = minimax(b1, depth - 1, alpha, beta); if (val.getBestScore() < bestVal) { bestVal = val.getBestScore(); bestMove = move; } if (bestVal < beta) { beta = bestVal; } } } } return(new Result(bestMove, bestVal)); }
/* minimax() * @param: b, a Board type && d, and int type * returns new Result w/ bestMove && bestValue * this code follows the pseudocode given in class */ private Result minimaxVal(Board b, int d, int alpha, int beta) //d is depth { int bestValue = 0; int bestMove = 0; if (b.gameOver() || d == 0) //if the game is over or depth is 0 { return(new Result(0, evaluate(b))); } if (b.whoseMove() == Position.Top) { //if TOP is max bestValue = Int32.MinValue; for (int move = 7; move <= 12 && alpha < beta; move++) { if (b.legalMove(move)) { Board b1 = new Board(b); //duplicate board b1.makeMove(move, false); Result val = minimaxVal(b1, d - 1, alpha, beta); if (val.GetScore() > bestValue) { bestValue = val.GetScore(); bestMove = move; } if (bestValue > alpha) { alpha = bestValue; } } } return(new Result(bestMove, bestValue)); } else { bestValue = int.MaxValue; for (int move = 0; move <= 5 && alpha < beta; move++) //bottom row { if (b.legalMove(move)) { Board b1 = new Board(b); b1.makeMove(move, false); Result val = minimaxVal(b1, d - 1, alpha, beta); if (val.GetScore() < bestValue) { bestValue = val.GetScore(); bestMove = move; } if (bestValue < beta) { beta = bestValue; } } } } return(new Result(bestMove, bestValue)); }
/* miniMaxVal implements the minimax search of a board for a given depth * @param: board, the Board whose child boards will be evaluated * @param: depth, how many generations will be analyzed * @return: a Result that is the optimal move and its value */ private Result miniMaxVal(Board board, int depth) { int bestMove = -1; // dummy value int bestVal = 0; // dummy value if (board.gameOver() || (depth == 0)) { return(new Result(0, evaluate(board))); } if (board.whoseMove() == Position.Top) // max { bestVal = -9999999; // impossible to get less than this for (int move = 7; move <= 12; move++) { if (board.legalMove(move) && !timeUp) // stop if the timer has finished { Board boardCopy = new Board(board); boardCopy.makeMove(move, false); Result moveResult = miniMaxVal(boardCopy, depth - 1); if (moveResult.value > bestVal) { bestVal = moveResult.value; bestMove = move; } } } } else // BOTTOM'S MOVE (min) { bestVal = 9999999; // impossible to get more than this for (int move = 0; move <= 5; move++) { if (board.legalMove(move) && !timeUp) // stop if the timer has finished { Board boardCopy = new Board(board); boardCopy.makeMove(move, false); Result moveResult = miniMaxVal(boardCopy, depth - 1); if (moveResult.value < bestVal) { bestVal = moveResult.value; bestMove = move; } } } } return(new Result(bestMove, bestVal)); }
public override int chooseMove(Board b) { int move = -1; string moveString; while (!b.legalMove(move)) { Console.Write("Your move: "); moveString = Console.ReadLine(); if (!int.TryParse(moveString, out move) || !b.legalMove(move)) { Console.WriteLine("Illegal move. Try again."); } } return(move); }
/// <summary> /// MiniMax algorithm for mankalah. Uses the moveResult class, probably doesn't need to and /// could use it much more efficiently, but for times sake... /// This method finds returns the best move based on its rating. /// </summary> /// <param name="b"></param> which mankalah board /// <param name="d"></param> depth of which algotithm will recurse /// <returns></returns> private moveResult miniMax(Board b, int d) { moveResult moveVal = new moveResult(0, 0); //uses result class at bottom moveResult bestMoveVal = new moveResult(0, 0); // ^^ if (b.gameOver() || d == 0) { return(new moveResult(0, evaluate(b))); //evaluate function is simple. Bad thing? } if (b.whoseMove() == Position.Bottom) { bestMoveVal.val = 999; for (int move = 0; move <= 5; move++) //for all possible moves, { if (b.legalMove(move) && myWatch.ElapsedMilliseconds < timePerMove) /*and time not expired*/ { Board b1 = new Board(b); //dup board b b1.makeMove(move, false); //make move moveVal = miniMax(b1, d - 1); //recurse and return value if (moveVal.val < bestMoveVal.val) { bestMoveVal = moveVal; bestMoveVal.move = move; } //overwrite if better move } } return(bestMoveVal); //return best move found. } else //similar comments as above... { bestMoveVal.val = -999; for (int move = 7; move <= 12; move++) { if (b.legalMove(move) && myWatch.ElapsedMilliseconds < timePerMove) /*and time not expired*/ { Board b1 = new Board(b); //dup board b b1.makeMove(move, false); moveVal = miniMax(b1, d - 1); if (moveVal.val > bestMoveVal.val) { bestMoveVal = moveVal; bestMoveVal.move = move; } } } return(bestMoveVal); } }
public override int chooseMove(Board b) { int tL = 4; Timer timer = new Timer(tL); timeOut = false; timer.Elapsed += timeOutTrigger; timer.Enabled = true; timer.AutoReset = false; timer.Start(); List <int> choices = new List <int>(); int choice = 0; int startDepth = 11; //Pass in timer to minimax? //If the elapsed time matches or exceeds the time limit, break the loop while (true) { if (timeOut || b.gameOver()) { break; } Console.WriteLine("Depth: " + startDepth); if (startDepth > 20) { Console.WriteLine("We might have a problem"); } //If the value of choice is not 0, add it to the list of choices. moveResult choiceResult = new moveResult(0, 0); if (!timeOut) { choiceResult = miniMax(b, startDepth, tL, 1, timer); } if (choiceResult.getScore() != 0 && b.legalMove(choiceResult.getMove())) { //TODO: Adding stuff to a list seems to not work choices.Add(choiceResult.getMove()); } //choice = miniMax(b, startDepth, tL).getScore(); //TODO: Modify timer and Stop, store and print time elapsed //update depth. startDepth += 1; if (timeOut == true) { timer.Stop(); } } //Close the timer and return the move from the last item in the list of choices timer.Close(); return(choices.Last()); }
public override int chooseMove(Board b) { int move; Random rnd = new Random(); while (true) { move = rnd.Next(13); if (b.legalMove(move)) { return(move); } } }
//Minimax function. Note that the Max is for the bottom play, It just made more sense to me that way. returns best score and best move. private int[] prunedminimax(Board b, int depth, Stopwatch timer, int lastbestscore, Position lastplayer, int playsinarow) { int[] value = new int[2]; int bestscore; if (b.whoseMove() == Position.Top) //set the infinity max or infinity min depending on whose turn it is. { bestscore = 1111111; } else { bestscore = -1111111; } int bestmove = -1; //returns this number if DFS doesnt finish int[] tempvalue = new int[2]; //temporary value that will be used to find the best score and value if ((depth > 0 && !b.gameOver())) //as long as game isnt over, or you reached the depth { bool firstturn = true; //used to keep track of the first turn for (int i = 0; i < 6; i++) { if (b.whoseMove() == Position.Top) { if (b.legalMove(i + 7)) { Board currentBoard = new Board(b); currentBoard.makeMove(i + 7, false); if (lastplayer == Position.Top)//this is used to keep track of who has had the most turns { tempvalue = prunedminimax(currentBoard, depth - 1, timer, bestscore, Position.Top, playsinarow - 1); } else { tempvalue = prunedminimax(currentBoard, depth - 1, timer, bestscore, Position.Top, playsinarow); } if (firstturn) { bestscore = tempvalue[0]; bestmove = i + 7; firstturn = false;//no longer first turn so set to false } //for non-first turns, check to see if tempvalue is lower then best score. else if (tempvalue[0] < bestscore) { bestscore = tempvalue[0]; bestmove = i + 7; } if ((lastplayer == Position.Bottom) && (bestscore < lastbestscore)) { break; //prunes the branches if necesary. } } } else { if (b.legalMove(i)) { Board currentBoard = new Board(b); currentBoard.makeMove(i, false); if (lastplayer == Position.Bottom) { tempvalue = prunedminimax(currentBoard, depth - 1, timer, bestscore, Position.Bottom, playsinarow + 1); } else { tempvalue = prunedminimax(currentBoard, depth - 1, timer, bestscore, Position.Bottom, playsinarow); } if (firstturn) { bestscore = tempvalue[0]; bestmove = i; firstturn = false; } else if (tempvalue[0] > bestscore) { bestscore = tempvalue[0]; bestmove = i; } if ((lastplayer == Position.Top) && (bestscore > lastbestscore)) { break; } } } if (!(timer.ElapsedMilliseconds < getTimePerMove() - 10))//if there are only 10 ms till the turn is up, return -1 for the best move { value[1] = -1; return(value); } } } else //reaches this if it is a node. { bestscore = evaluate(b, playsinarow); } value[0] = bestscore; value[1] = bestmove; return(value); }
public Result miniMax(Board b, int d, int alpha, int beta) { if (cancellationToken.IsCancellationRequested) { throw new OperationCanceledException(); } int bestMove = first; int bestVal = 0; Result res; Position opp; if (b.gameOver() || d == 0) { return(new Result(0, evaluate(b))); } if (b.whoseMove() == p) { //top is max bestVal = -int.MaxValue; for (int move = first; move <= last; move++) { if (b.legalMove(move)) { Board b1 = new Board(b); //duplicate board b1.makeMove(move, false); //make the move res = miniMax(b1, d - 1, alpha, beta); //find its value alpha = Math.Max(alpha, res.val); if (res.val > bestVal) { bestVal = res.val; bestMove = move; } if (alpha >= beta) { break; } } } } else { // similarly for bottom’s move bestVal = int.MaxValue; for (int move = p2first; move <= p2last; move++) { if (b.legalMove(move)) { Board b1 = new Board(b); //duplicate board b1.makeMove(move, false); //make the move res = miniMax(b1, d - 1, alpha, beta); //find its value beta = Math.Min(beta, res.val); if (res.val < bestVal) //remember if best { bestVal = res.val; bestMove = move; } if (alpha >= beta) { break; } } } } return(new Result(bestMove, bestVal)); }
public int[] minmaxVal(Board b, int depth, float alpha, float beta, ref Stopwatch sw) { if (depth == 0) { return new int[] { 0, evaluate(b) } } ; if (b.gameOver()) { maxDepth = depth; return(new int[] { 0, endGameEval(b) }); } int[] bestMove = { 0, int.MinValue }; //our turn -> maximize if (b.whoseMove() == us) { bestMove = new int[] { 0, int.MinValue }; for (int i = 0; i < 13; i++) { if (b.legalMove(i)) { if (sw.ElapsedMilliseconds >= timeLimit - 100) { //return new int[] { 0, int.MinValue }; return new int[] { i, evaluate(b) } } ; Board modified = SimulateBoard(b, i); int[] newMove = minmaxVal(modified, depth - 1, alpha, beta, ref sw); if (newMove[1] > bestMove[1]) { bestMove[0] = i; bestMove[1] = newMove[1]; //Console.WriteLine($"Changed bestMove in max to move {i} with value {bestMove[1]}"); } alpha = Math.Max(alpha, bestMove[1]); if (beta <= alpha) { break; } } } } //Their turn -> minimize else { bestMove = new int[] { 0, int.MaxValue }; for (int i = 0; i < 13; i++) { if (b.legalMove(i)) { if (sw.ElapsedMilliseconds >= timeLimit - 100) { //return new int[] { 0, int.MaxValue }; return new int[] { i, evaluate(b) } } ; Board modified = SimulateBoard(b, i); int[] newMove = minmaxVal(modified, depth - 1, alpha, beta, ref sw); if (newMove[1] < bestMove[1]) { bestMove[0] = i; bestMove[1] = newMove[1]; //Console.WriteLine($"Changed bestMove in min to move {i} with value {bestMove[1]}"); } beta = Math.Min(beta, bestMove[1]); if (beta <= alpha) { break; } } } } if (maxDepth != 50) { maxDepth = depth; } return(bestMove); }
public int[] minmaxVal(Board b, int d, float alpha, float beta, ref Stopwatch sw) //d is depth { if (depth == 0 || b.gameOver()) { return new int[] { 0, evaluate(b) } } ; int[] bestMove = { 0, int.MinValue }; //our turn -> maximize if (b.whoseMove() == us) { bestMove = new int[] { 0, int.MinValue }; for (int i = 0; i < 13; i++) { if (b.legalMove(i)) { if (sw.ElapsedMilliseconds >= timeLimit - 500) { return new int[] { 0, int.MinValue } } ; Board modified = SimulateBoard(b, i); int[] newMove = minmaxVal(modified, depth - 1, alpha, beta, ref sw); if (newMove[1] > bestMove[1]) { bestMove[0] = i; bestMove[1] = newMove[1]; } alpha = Math.Max(alpha, bestMove[1]); if (beta <= alpha) { break; } } } } //Their turn -> minimize else { bestMove = new int[] { 0, int.MaxValue }; for (int i = 0; i < 13; i++) { if (!b.legalMove(i)) { if (sw.ElapsedMilliseconds >= timeLimit - 500) { return new int[] { 0, int.MaxValue } } ; Board modified = SimulateBoard(b, i); int[] newMove = minmaxVal(modified, depth - 1, alpha, beta, ref sw); if (newMove[1] > bestMove[1]) { bestMove[0] = i; bestMove[1] = newMove; } beta = Math.Min(beta, bestMove[1]); if (beta <= alpha) { break; } } } } return(bestMove); } }
// b = current board state, d = depth, w = clock, alpha and beta to keep track of max/min values for pruning private Result minimax(Board b, int d, Stopwatch w, int alpha, int beta) { // throw exception if time limit has reached if (w.ElapsedMilliseconds > getTimePerMove()) { throw new MoveTimedOutException(); } // initialize variables int bestMove = 0; int bestVal; bool gameCompleted = false; if (b.gameOver() || d == 0) { return(new Result(0, evaluate(b), b.gameOver())); } // if it's my move, maximize if (b.whoseMove() == mypos) // TOP is MAX { bestVal = Int32.MinValue; // set bestVal to lowest possible number to update later on for (int move = myfirst; move <= mylast; move++) // loop through all possible moves for this player { if (b.legalMove(move)) // if it's a legal move, make that move, look at board and see if it is best move { Board b1 = new Board(b); // duplicate board b1.makeMove(move, false); // make the move Result val = minimax(b1, d - 1, w, alpha, beta); // find its value if (val.getScore() > bestVal) // remember if best maximum { bestVal = val.getScore(); // update best move, value, and game state after this move bestMove = move; gameCompleted = val.isEndGame(); } // update alpha if (bestVal > alpha) { alpha = bestVal; } } } } // else minimize else { bestVal = Int32.MaxValue; // set bestVal to highest possible number to update later on for (int move = myfirstOP; move <= mylastOP; move++) // loop through all possible moves for this player { if (b.legalMove(move)) // if it's a legal move, make that move, look at board and see if it is best move { Board b1 = new Board(b); // duplicate board b1.makeMove(move, false); // make the move Result val = minimax(b1, d - 1, w, alpha, beta); // find its value if (val.getScore() < bestVal) // remember if best minimum { bestVal = val.getScore(); // update best move, value, and game state after this move bestMove = move; gameCompleted = val.isEndGame(); } // update beta if (bestVal < beta) { beta = bestVal; } } } } // return the Result set with best move, score, and game status return(new Result(bestMove, bestVal, gameCompleted)); }
// The function minimax() calculates the best possible move that Chappie can make by // recursing as far as it can within the time limit and keeping track of what the best move and // score are as it recurses. It is also implemented with AB pruning, meaning that if it // starts to go down a path where the outcome will inevitable be worse that our best values, // it prunes off that path, therefore saving time to go down a better path. private MoveResult minimax(Board b, int d, Stopwatch w, int alpha, int beta) { // check to see if the time limit is up if (w.ElapsedMilliseconds > getTimePerMove()) { throw new MoveTimedOutException(); } // base case if (b.gameOver() || d == 0) { return(new MoveResult(0, evaluate(b), b.gameOver())); } // initialization of trackers int bestMove = 0; int bestVal; bool gameCompleted = false; // check all the the moves that top could make, and act as if it is the MAX in minimax if (b.whoseMove() == Position.Top) // TOP is MAX { // smallest possible value so that it can only get better bestVal = Int32.MinValue; for (int move = 7; move <= 12 && alpha < beta; move++) { if (b.legalMove(move)) { Board b1 = new Board(b); // duplicate board b1.makeMove(move, false); // make the move MoveResult val = minimax(b1, d - 1, w, alpha, beta); // find its value if (val.getScore() > bestVal) // remember if best { bestVal = val.getScore(); bestMove = move; // track the current condition of the game gameCompleted = val.isEndGame(); } // prune if (bestVal > alpha) { alpha = bestVal; } } } } // check all the the moves that bottom could make, and act as if it is the MIN in minimax else // BOTTOM is MIN { // lergest possible value so that it can only get better bestVal = Int32.MaxValue; for (int move = 0; move <= 5 && alpha < beta; move++) { if (b.legalMove(move)) { Board b1 = new Board(b); // duplicate board b1.makeMove(move, false); // make the move MoveResult val = minimax(b1, d - 1, w, alpha, beta); // find its value if (val.getScore() < bestVal) // remember if best { bestVal = val.getScore(); bestMove = move; // track the current condition of the game gameCompleted = val.isEndGame(); } // prune if (bestVal < beta) { beta = bestVal; } } } } return(new MoveResult(bestMove, bestVal, gameCompleted)); }
/* minimaxVal with Alpha-Beta Pruning * returns evaluation if it reaches maxDepth, else calculates min or max if it is opponent's turn or my turn respectively * */ public DataWrapper minimaxVal(Board b, int d, int alpha, int beta) { //when time runs out, this evaluates to true //when the cancelled execption is thrown, the last best move will be returned in the chooseMove() try->catch statement if (cancellationToken.IsCancellationRequested) { throw new OperationCanceledException(); } //return if reached gameover or max depth if (b.gameOver() || d == 0) { return(new DataWrapper(0, evaluate(b), 0, 0)); } DataWrapper data; //look through right positions for moves int start = 0; int end = 5; if (b.whoseMove() == Position.Top) { start = 7; end = 12; } //initialize variables int bestMove = -1; int secondBestMove = -1; int bestValue = int.MinValue; int secondBestValue = int.MinValue; //loop through all possible moves for (int move = start; move <= end; move++) { //if it is a legal move, check the value of it if (b.legalMove(move)) { //create copy of board, make move, and evaluate it by recursing Board newBoard = new Board(b); newBoard.makeMove(move, false); data = minimaxVal(newBoard, d - 1, alpha, beta); //if value, move pair is best or worst, set bestValue and bestMove to it //also set second best value, move pair to previous value if (isBetterMove(b.whoseMove(), bestValue, data.getValue(), d)) { secondBestValue = bestValue; bestValue = data.getValue(); secondBestMove = bestMove; bestMove = move; //alpha beta pruning if (b.whoseMove() == this.position) { alpha = Math.Max(alpha, bestValue); } else { beta = Math.Min(beta, bestValue); } } //if alpha is greater than or equal to beta, we can skip other moves (pruning part of alpha beta pruning) if (alpha >= beta) { break; } } } //return move pairs return(new DataWrapper(bestMove, bestValue, secondBestMove, secondBestValue)); }
private Result minimaxVal(Board b, int d, Stopwatch w, int alpha, int beta) { if (w.ElapsedMilliseconds > getTimePerMove()) { throw new MoveTimedOutException(); } int bestMove = 0; int bestVal; bool gameCompleted = false; if (b.gameOver() || d == 0) { return(new Result(0, evaluate(b), b.gameOver())); } if (b.whoseMove() == Position.Top) { bestVal = Int32.MinValue; for (int move = 7; move <= 12; move++) { if (b.legalMove(move)) { Board b1 = new Board(b); b1.makeMove(move, false); Result val = minimaxVal(b1, d - 1, w, alpha, beta); if (val.getScore() > bestVal) { bestVal = val.getScore(); bestMove = move; gameCompleted = val.isEndGame(); } if (bestVal > alpha) { alpha = bestVal; } } } } else { bestVal = Int32.MaxValue; for (int move = 0; move <= 5; move++) { if (b.legalMove(move)) { Board b1 = new Board(b); b1.makeMove(move, false); Result val = minimaxVal(b1, d - 1, w, alpha, beta); if (val.getScore() < bestVal) { bestVal = val.getScore(); bestMove = move; gameCompleted = val.isEndGame(); } if (bestVal < beta) { beta = bestVal; } } } } return(new Result(bestMove, bestVal, gameCompleted)); }
//int d is depth of miniMax search. int max should be 1 for getting the max result, -1 for min. Should return moveResult object public moveResult miniMax(Board b, int d, double timeLimit, int max, Timer timer) { //Set up variables int bestVal = int.MinValue; int bestMove = 0; moveResult bestMR = new moveResult(bestMove, bestVal); //Base case: depth is 0, time is up or game is over. Returns a moveResult with the best score value and 0 move value if (d == 0 || timeOut || b.gameOver()) { bestVal = evaluate(b); //Console.WriteLine("Best score found to be " + bestVal); moveResult bestMoveResult = new moveResult(bestMove, bestVal); return(bestMoveResult); } if (b.whoseMove() == Position.Top) { for (int move = 7; move <= 12; move++) { //Console.WriteLine(""); //Recurse if the move is legal, time hasn't expired and game isn't over int val = 0; if (b.legalMove(move) && !timeOut && !b.gameOver()) { Board b1 = new Board(b); b1.makeMove(move, true); int newDepth = d - 1; //Switch the value of max to be the opposite for the recursion int mnOrMx = max * -1; //Console.WriteLine("Recursing from " + d + " to " + newDepth + "..."); val = miniMax(b1, newDepth, timeLimit, mnOrMx, timer).getScore(); //If at "max" level, prioritize and return maximum value if (max == 1) { //If there's a new max, update bestValue and bestMove if (val > bestVal) { bestVal = val; bestMove = move; } } //If at "min" level, prioritize and return minimum value if (max == -1) { //If there's a new min, update bestValue and bestMove if (val < bestVal || val != int.MinValue) { bestVal = val; bestMove = move; } } } } bestMR = new moveResult(bestMove, bestVal); return(bestMR); } else { for (int move = 0; move <= 5; move++) { //Console.WriteLine(""); //Recurse if the move is legal, time hasn't expired and game isn't over if (b.legalMove(move) && !timeOut && !b.gameOver()) { Board b1 = new Board(b); b1.makeMove(move, true); int newDepth = d - 1; //Switch the value of max to be the opposite for the recursion int mnOrMx = max * -1; // Console.WriteLine("Recursing from " + d + " to " + newDepth + "..."); int val = miniMax(b1, newDepth, timeLimit, mnOrMx, timer).getScore(); // Console.WriteLine("New Value: " + val); //If at "max" level, prioritize and return maximum value if (max == 1) { //If there's a new max, update bestValue and bestMove if (val > bestVal) { bestVal = val; bestMove = move; } } //If at "min" level, prioritize and return minimum value if (max == -1) { //If there's a new min, update bestValue and bestMove if (val < bestVal || val != int.MinValue) { bestVal = val; bestMove = move; } } } } bestMR = new moveResult(bestMove, bestVal); return(bestMR); } //Console.WriteLine("Best move: " + bestMove + " Best score: " + bestVal); bestMR = new moveResult(bestMove, bestVal); return(bestMR); }