def minimax(board,currentDepth,isOdd): # Note: bool isOdd basically tells us we want the max #checking this here REALLY boosts efficiency (due to getLegalMoves getting skipped) if currentDepth == self.maxDepth: return super(MinimaxPlayer,self).h1(board,self.symbol) moves = None if isOdd: moves = game_rules.getLegalMoves(board,self.symbol) else: symbol = 'x' if self.symbol == 'o' else 'o' moves = game_rules.getLegalMoves(board,symbol) # check for end state if len(moves) == 0: return super(MinimaxPlayer,self).h1(board,self.symbol) # want max if isOdd: optimalEval = NEG_INF for move in moves: newBoard = game_rules.makeMove(board,move) optimalEval = max(optimalEval,minimax(newBoard,currentDepth+1,False)) return optimalEval # want min else: optimalEval = POS_INF for move in moves: newBoard = game_rules.makeMove(board,move) optimalEval = min(optimalEval,minimax(newBoard,currentDepth+1,True)) return optimalEval
def minimax(self, symbol, board, depth): legalMoves = game_rules.getLegalMoves(board, symbol) next_move = Move() if depth == 0 or len(legalMoves) == 0: next_move.cost = self.h1(board, symbol) return next_move if symbol == "x": new_symbol = "o" else: new_symbol = "x" if symbol == self.symbol: next_move.cost = NEG_INF for move in legalMoves: val = self.minimax(new_symbol, game_rules.makeMove(board, move), depth - 1) if val.cost > next_move.cost: next_move.cost = val.cost next_move.move = move return next_move else: next_move.cost = POS_INF for move in legalMoves: val = self.minimax(new_symbol, game_rules.makeMove(board, move), depth - 1) if val.cost < next_move.cost: next_move.cost = val.cost next_move.move = move return next_move
def _handleTurnO(self, playerBoard, board, move_pair): move = move_pair if isinstance( self.p2, HumanPlayer) else self.p2.getMove(playerBoard) if not move: self.state = X_VICTORY elif game_rules.isLegalMove(board, 'o', move, False): self.board = game_rules.makeMove(board, move) self.state = X_TURN
def _handleTurnO(self, playerBoard, board): self.state = X_TURN move = self.p2.getMove(playerBoard) if game_rules.isLegalMove(board, 'o', move, False): self.board = game_rules.makeMove(board, move) else: self.state = X_VICTORY
def max_value(self, board, player, curr_depth): #check if the max depth is reached - then return the utility function if curr_depth == 0: new_utility = self.h1(board, player) new_utility_move = [new_utility, None] return new_utility_move curr_depth = curr_depth - 1 available_moves = game_rules.getLegalMoves(board, player) #check if it is a leaf node -> return utility function if len(available_moves) == 0: new_utility = self.h1(board, player) new_utility_move = [new_utility, None] return new_utility_move check_utility = [NEG_INF, None] for move in available_moves: new_player = self.change_player(player) new_board = game_rules.makeMove(board, move) new_utility = self.min_value(new_board, new_player, curr_depth) #check if the utility returned is greater than the current utility #update the utility and the move associated with that if new_utility[0] > check_utility[0]: check_utility[0] = new_utility[0] check_utility[1] = move return check_utility
def min_value(self, board, player, curr_depth): if curr_depth == 0: new_utility = self.h1(board, player) new_utility_move = [new_utility, None] return new_utility_move curr_depth = curr_depth - 1 available_moves = game_rules.getLegalMoves(board, player) if len(available_moves) == 0: new_utility = self.h1(board, player) new_utility_move = [new_utility, None] return new_utility_move check_utility = [POS_INF, None] for move in available_moves: new_player = self.change_player(player) new_board = game_rules.makeMove(board, move) new_utility = self.max_value(new_board, new_player, curr_depth) if new_utility[0] < check_utility[0]: check_utility[0] = new_utility[0] check_utility[1] = move return check_utility
def min_valuealpha_beta(self, board, player, curr_depth, alpha, beta): if curr_depth == 0: new_utility = self.h1(board, player) new_utility_move = [new_utility, None] return new_utility_move curr_depth = curr_depth - 1 available_moves = game_rules.getLegalMoves(board, player) if len(available_moves) == 0: new_utility = self.h1(board, player) new_utility_move = [new_utility, None] return new_utility_move check_utility = [POS_INF, None] for move in available_moves: new_player = self.change_player(player) new_board = game_rules.makeMove(board, move) new_utility = self.max_value_alpha_beta(new_board, new_player, curr_depth, alpha, beta) if new_utility[0] < check_utility[0]: check_utility[0] = new_utility[0] check_utility[1] = move beta = min(beta, new_utility[0]) if alpha >= beta: break return check_utility
def Max_Value(self, board, a, b, depth, symbol): # set initial max value to minus infinity #val = -1000000000 # get legalmoves legalMoves = game_rules.getLegalMoves(board,symbol) best = (-1000000000, None) # return utility when no more legalmoves if (len(legalMoves) == 0 or depth == 0): return (self.h1(board, symbol), None) for i in range(len(legalMoves)): nextBoard = game_rules.makeMove(board, legalMoves[i]) #nextBoard = game_rules.makeMove(board, legalMoves[i]) # when meet depth limit, then use heuristic function to replace the val Min_Value if symbol == 'x': val = self.Min_Value(nextBoard, a, b, depth - 1, 'o')[0] else: val = self.Min_Value(nextBoard, a, b, depth - 1, 'x')[0] if best[0] < val: best = (val,legalMoves[i]) if (best[0] >= b): return best if (a < best[0]): a = best[0] return best
def _handleTurnX(self, playerBoard, board, move_pair): #move = move_pair if isinstance(self.p1, HumanPlayer) else self.p1.getMove(playerBoard) move = move_pair if move_pair is not None else self.p1.getMove( playerBoard) if not move: self.state = O_VICTORY elif game_rules.isLegalMove(board, 'x', move, False): self.log.write(str(move) + '\n') self.board = game_rules.makeMove(board, move) self.state = O_TURN
def _minValue(self, board, depth, symbol): legalMoves = game_rules.getLegalMoves(board, symbol) if depth == 0 or len(legalMoves) == 0: return (self._assessBoard(board, symbol), None) best = (1000000000, None) for move in legalMoves: child = game_rules.makeMove(board, move) (score, _) = self._minValue(child, depth-1, 'o' if symbol == 'x' else 'x') best = min(best, (score, move)) return best
def minimax_recur(depth, board, turn, currsymbol): # print('**minimax_recur board: ', board) # print('**current player: ', currsymbol) legalMoves = game_rules.getLegalMoves(board, currsymbol) #self.symbol) # print('**all legal moves: ', legalMoves) if len(legalMoves) == 0 or depth == 0: # print('**case1') # print('**heuristic: ', self.h1(board, currsymbol)) return None, self.h1(board, currsymbol) val = (POS_INF, NEG_INF)[turn] # print('**val = ', val) move = None tmpmove = (None, None) for eachmove in legalMoves: # print('**now move: ', eachmove) if tmpmove[0] != None: board = self.originalboard(board, tmpmove[0], tmpmove[1], currsymbol) # print('board: ', board) tmpmove = (eachmove[0], eachmove[len(eachmove) - 1] ) #start -> end # print('**tmpmove: ', tmpmove) board = game_rules.makeMove(board, eachmove) # print('**nowboard: ', board) succmove, succval = minimax_recur(depth - 1, board, not turn, self.changeturn(currsymbol)) # print('*****now val:', succval) # print('current move: ', eachmove) # print('bestval: ', val) # print('bestmove: ', move) a, b = (((move, val), (eachmove, succval))[succval < val], ((move, val), (eachmove, succval))[succval > val])[turn] move = a val = b # print('**bestmove: ', move) # print('**bestval: ', val) board = self.originalboard(board, tmpmove[0], tmpmove[1], currsymbol) # print('then return bestmove: ', move) # print('then return bestval: ', val) return move, val
def decision(board,moves): cloneBoard = deepcopy(board) optimalMove = moves[0] optimalEval = NEG_INF for move in moves: newBoard = game_rules.makeMove(cloneBoard,move) val = minimax(newBoard,1,False) #send with depth 1, as this is depth 0, the root if val > optimalEval: #final max check optimalMove = move optimalEval = val return optimalMove
def decision(board,moves): cloneBoard = deepcopy(board) # clone used for simulation optimalMove = moves[0] alpha = NEG_INF beta = POS_INF for move in moves: newBoard = game_rules.makeMove(cloneBoard,move) val = alphabeta(newBoard,1,False,alpha,beta) #send with depth 1, as this is depth 0, the root if val > alpha: #final max check optimalMove = move alpha = val return optimalMove
def alphabeta(board,currentDepth,isOdd,alpha,beta): # Note: bool isOdd basically tells us we want the max #checking this here REALLY boosts efficiency (due to getLegalMoves getting skipped) if currentDepth == self.maxDepth: return super(AlphaBetaPlayer,self).h1(board,self.symbol) moves = None symbol = None if isOdd: moves = game_rules.getLegalMoves(board,self.symbol) else: symbol = 'x' if self.symbol == 'o' else 'o' moves = game_rules.getLegalMoves(board,symbol) # check for end state if len(moves) == 0: # so actually, I ran this using self.h1 and super(...).h1, and super gave me quicker test results... weird return super(AlphaBetaPlayer,self).h1(board,self.symbol) # want max if isOdd: loc_alpha = alpha for move in moves: # check if b <= a; if so exit loop if beta <= loc_alpha: return loc_alpha newBoard = game_rules.makeMove(board,move) loc_alpha = max(loc_alpha,alphabeta(newBoard,currentDepth+1,False,loc_alpha,beta)) return loc_alpha # want min else: loc_beta = beta for move in moves: # check if b <= a; if so exit loop if loc_beta <= alpha: return loc_beta newBoard = game_rules.makeMove(board,move) loc_beta = min(loc_beta,alphabeta(newBoard,currentDepth+1,True,alpha,loc_beta)) return loc_beta
def ab_pruning(self, symbol, board, alpha, beta, depth): legalMoves = game_rules.getLegalMoves(board, symbol) next_move = Move() if depth == 0 or len(legalMoves) == 0: next_move.cost = self.h1(board, symbol) return next_move if symbol == "x": new_symbol = "o" else: new_symbol = "x" if symbol == self.symbol: next_move.cost = NEG_INF for move in legalMoves: val = self.ab_pruning(new_symbol, game_rules.makeMove(board, move), alpha, beta, depth - 1) if val.cost > next_move.cost: next_move.cost = val.cost next_move.move = move alpha = max(alpha, val.cost) if beta <= alpha: break return next_move else: next_move.cost = POS_INF for move in legalMoves: val = self.ab_pruning(new_symbol, game_rules.makeMove(board, move), alpha, beta, depth - 1) if val.cost < next_move.cost: next_move.cost = val.cost next_move.move = move beta = min(beta, val.cost) if beta <= alpha: break return next_move
def Min_Value(self, board, depth, symbol): legalMoves = game_rules.getLegalMoves(board, symbol) if depth == 0 or len(legalMoves) == 0: return (self.h1(board, symbol), None) best = (POS_INF, None) for i in range(len(legalMoves)): nextBoard = game_rules.makeMove(board, legalMoves[i]) if symbol == 'x': val = self.Max_Value(nextBoard, depth - 1, 'o')[0] else: val = self.Max_Value(nextBoard, depth - 1, 'x')[0] if best[0] > val: best = (val, legalMoves[i]) return best
def get_min(self, board, symbol, depth): legal_moves = game_rules.getLegalMoves(board, symbol) if depth == 0 or len(legal_moves) == 0: result = [self.h1(board, symbol), None] return result else: our_move = None min_val = float('inf') for move in legal_moves: new_board = game_rules.makeMove(board, move) val = self.get_max(new_board, self.opposite_symbol(symbol), depth - 1)[0] if val < min_val: min_val = val our_move = move result = [min_val, our_move] return result
def get_max(self, board, symbol, depth, alpha, beta): legal_moves = game_rules.getLegalMoves(board, symbol) if depth == 0 or len(legal_moves) == 0: result = [self.h1(board, symbol), None] return result else: our_move = None max_val = float('-inf') for move in legal_moves: new_board = game_rules.makeMove(board, move) val = self.get_min(new_board, self.opposite_symbol(symbol), depth - 1, alpha, beta)[0] if val > max_val: max_val = val our_move = move if val > alpha: alpha = val if alpha >= beta: break result = [max_val, our_move] return result
def alphabeta_recur(depth, board, turn, currsymbol, alpha, beta): # print('** now board: ', board) # print('** now player: ', currsymbol) legalMoves = game_rules.getLegalMoves(board, currsymbol) # print('all legal moves: ', legalMoves) if len(legalMoves) == 0 or depth == 0: # print('case1') # print('h1: ', self.h1(board, currsymbol)) # only return heuristic # self.printCurrentInfo(depth, self.heuristic(board, self), None) return None, self.h1(board, currsymbol) # print('turn: ', turn) val = (POS_INF, NEG_INF)[turn] # print('val: ', val) move = None tmpmove = (None, None) # judge every nodes possible, select the biggest/smallest one for eachmove in legalMoves: # print('now eachmove: ', eachmove) if tmpmove[0] != None: board = self.originalboard(board, tmpmove[0], tmpmove[1], currsymbol) tmpmove = (eachmove[0], eachmove[len(eachmove) - 1]) # print('new move: ', tmpmove) board = game_rules.makeMove(board, eachmove) # print('board: ', board) succmove, succval = alphabeta_recur( depth - 1, board, not turn, self.changeturn(currsymbol), alpha, beta) # print('now succval: ', succval) # print('check a,b: ') # print('succval: ', succval) # print('val: ', val) # print('eachmove: ', eachmove) # print('move: ', move) # print('turn: ', turn) a, b = (((move, val), (eachmove, succval))[succval < val], ((move, val), (eachmove, succval))[succval > val])[turn] move = a val = b # print('move: ', move) # print('val: ', val) if turn: alpha = (alpha, val)[alpha <= val] # print('alpha: ', alpha) else: beta = (beta, val)[beta >= val] # print('beta: ', beta) if beta <= alpha: # print('beta < alpha, break', beta, alpha) break board = self.originalboard(board, tmpmove[0], tmpmove[1], currsymbol) # print('then return move: ', move) # print('then return bestval: ', val) return move, val