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_helper(self, board, depth, max_player, symbol): if symbol == "x": symbol = "o" else: symbol = "x" if max_player: moves = game_rules.getLegalMoves(board, symbol) new_value = NEG_INF depth = depth - 1 if len(moves) == 0 or depth == 0: return self.h1(board, symbol) for move in moves: clone_board = game_rules.makePlayerMove(board, symbol, move) value = self.minimax_helper(clone_board, depth, False, symbol) if value > new_value: new_value = value return new_value else: moves = game_rules.getLegalMoves(board, symbol) new_value = POS_INF depth = depth - 1 if len(moves) == 0 or depth == 0: return self.h1(board, symbol) for move in moves: clone_board = game_rules.makePlayerMove(board, symbol, move) value = self.minimax_helper(clone_board, depth, True, symbol) if value < new_value: new_value = value return new_value
def getMove(self, board): legalMoves = game_rules.getLegalMoves(board, self.symbol) if len(legalMoves) > 0: return self.ab_pruning(self.symbol, board, NEG_INF, POS_INF, self.depth).move else: return None
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 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 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 _sanitizedMove(self, board): legalMoves = getLegalMoves(board, self.symbol) resultMove = self._parseMove(self._run(board)) if resultMove in legalMoves: return resultMove else: return ((1, 2), (3, 4))
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 getMove(self, board): legalMoves = game_rules.getLegalMoves(board, self.symbol) if len(legalMoves) > 0: return self.get_max(board, self.symbol, self.depth, float('-inf'), float('inf'))[1] else: return None
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 _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 getMove(self, board): # use super(MinimaxPlayer,self,board,self.symbol).h1 as evaluation function 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 # recursive function that simulates playing the max # (finds best move for self), or playing the min # (finds the best move for opponent) 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 legalMoves = game_rules.getLegalMoves(board, self.symbol) if len(legalMoves) > 0: return decision(board,legalMoves) else: return None
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 max_value(self, board, depth): depth -= 1 if depth == 0: return self.h1(board, self.symbol) legalMoves = game_rules.getLegalMoves(board, self.symbol) if len(legalMoves) == 0: return self.h1(board, self.symbol) v = NEG_INF for move in legalMoves: v = max(v, self.min_value(self.makeMove(board, move), depth)) return v
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 min_value(self, board, depth): depth -= 1 if depth == 0: return self.h1(board, self.symbol) opponent_symbol = self.get_opponent_symbol(self.symbol) legalMoves = game_rules.getLegalMoves(board, opponent_symbol) if len(legalMoves) == 0: return self.h1(board, self.symbol) v = POS_INF for move in legalMoves: v = min(v, self.max_value(self.makeMove(board, move), depth)) return v
def alphabeta_helper(self, board, depth, max_player, alpha, beta, symbol): if symbol == "x": symbol = "o" else: symbol = "x" if max_player: moves = game_rules.getLegalMoves(board, symbol) depth = depth - 1 if len(moves) == 0 or depth == 0: return self.h1(board, symbol) for move in moves: clone_board = game_rules.makePlayerMove(board, symbol, move) value = self.alphabeta_helper(clone_board, depth, False, alpha, beta, symbol) if value > alpha: alpha = value if beta <= alpha: return alpha return alpha else: moves = game_rules.getLegalMoves(board, symbol) depth = depth - 1 if len(moves) == 0 or depth == 0: return self.h1(board, symbol) for move in moves: clone_board = game_rules.makePlayerMove(board, symbol, move) value = self.alphabeta_helper(clone_board, depth, True, alpha, beta, symbol) if value < beta: beta = value if beta <= alpha: return beta return beta
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 _takeTurn(self, move_pair=None): playerBoard = deepcopy(self.board) old = self.state if len(game_rules.getLegalMoves(self.board, self.GetTurn())) < 1: if self.state == X_TURN: self.state = O_VICTORY if self.state == O_TURN: self.state = X_VICTORY return if self.state == AWAITING_INITIAL_X: self._handleInitialX(playerBoard, self.board, move_pair) elif self.state == AWAITING_INITIAL_O: self._handleInitialO(playerBoard, self.board, move_pair) elif self.state == X_TURN: self._handleTurnX(playerBoard, self.board, move_pair) elif self.state == O_TURN: self._handleTurnO(playerBoard, self.board, move_pair) if self.state != old: self.turn_number += 1
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 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 getMove(self, board): #legalMoves = game_rules.getLegalMoves(board, self.symbol) #if len(legalMoves) > 0: return legalMoves[0] #else: return None legal_moves = game_rules.getLegalMoves(board, self.symbol) top_move = legal_moves[0] new_value = NEG_INF alpha = NEG_INF beta = POS_INF for move in legal_moves: clone_board = game_rules.makePlayerMove(board, self.symbol, move) value = self.alphabeta_helper(clone_board, self.depth, False, alpha, beta, self.symbol) if value > new_value: top_move = move new_value = value if value > alpha: alpha = value if alpha >= beta: break return top_move
def getMove(self, board): #legalMoves = game_rules.getLegalMoves(board, self.symbol) #if len(legalMoves) > 0: return legalMoves[0] #else: return None #print("Self.symbol is: {}".format(self.symbol)) legal_moves = game_rules.getLegalMoves(board, self.symbol) #print("legal_moves are: {}".format(legal_moves)) if len(legal_moves) == 0: #print("No possible Moves") return None else: top_move = legal_moves[0] new_value = NEG_INF for move in legal_moves: clone_board = game_rules.makePlayerMove( board, self.symbol, move) value = self.minimax_helper(clone_board, self.depth, False, self.symbol) if value > new_value: top_move = move new_value = value return top_move
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 getMove(self, board): legalMoves = game_rules.getLegalMoves(board, self.symbol) return self.minimax_decision(legalMoves, board)
def h1(self, board, symbol): return -len( game_rules.getLegalMoves(board, 'o' if self.symbol == 'x' else 'x'))
def getMove(self, board): legalMoves = game_rules.getLegalMoves(board, self.symbol) if len(legalMoves) > 0: return legalMoves[0] else: return None
def getMove(self, board): legalMoves = game_rules.getLegalMoves(board, self.symbol) if len(legalMoves) > 0: return random.choice(legalMoves) else: return None
def getMove(self, board): legalMoves = game_rules.getLegalMoves(board, self.symbol) if len(legalMoves) > 0: return random.choice(legalMoves) else: return ((0, 1), (2, 3))
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
def getMove(self, board): legalMoves = game_rules.getLegalMoves(board, self.symbol) return self.alpha_beta_search(legalMoves, board)
def getMove(self, board): legalMoves = game_rules.getLegalMoves(board, self.symbol) if len(legalMoves) > 0: return self.minimax(self.symbol, board, self.depth).move else: return None
def getMove(self, board): # use super(MinimaxPlayer,self,board,self.symbol).h1 as evaluation function 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 # recursive function that simulates playing the max # (finds best move for self), or playing the min # (finds the best move for opponent) 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 legalMoves = game_rules.getLegalMoves(board, self.symbol) if len(legalMoves) > 0: return decision(board,legalMoves) else: return None