def main(): board = HexBoard(2) num_of_cells = board.get_board_size() * board.get_board_size() for nc in range(int(num_of_cells / 2)): ## Just a small heuristic for opening strategy, you can test this if you want. But then you have to comment the move_blue below out too # if board.size % 2 != 0 and len(board.get_move_list()) == len(board.get_all_vertices()): # If it's the first move and the board is uneven # move_blue = (board.size // 2, board.size // 2) # Always place the first move in the middle # else: # move_blue = ab.alphabeta_move(board, depth=2, is_max=True) move_blue = ab.alphabeta_move(board, depth=4, is_max=True) #move_blue = ab.alphabeta_move_Id(board, is_max=True, show_AI=True) board = ab._update_board(board, move_blue, is_max=True) board.print() if board.is_game_over( ): # TODO: add condition for game over without no winning (board full) print("==== BLUE WINS ====") board.print() # break return "blue" move_red = ab.alphabeta_move(board, depth=2, is_max=True) #move_red = ab.alphabeta_move_Id(board, is_max=True, show_AI=True) board = ab._update_board( board, move_red, is_max=False ) # Using false here and true for the alphabeta is a bit confusing, but we need it to make moves for red here. board.print() if board.is_game_over( ): # TODO: add condition for game over without no winning (board full) print("==== RED WINS ====") board.print() # break return "red"
def mcts_mcts(cp1, N1, cp2, N2, size, print_all=False, first=True): #mcts plays with mcts Game = HexBoard(size) A1_color = 1 A2_color = 2 root = Tree(Game, color=A2_color, parent=None, coordinate=None) if print_all: if first == True: print('First move (blue) is mcts') print('Second move (red) is mcts') else: print('First move (blue) is mcts') print('Second move (red) is mcts') while not Game.is_game_over(): if first == True: #mcts moves first A1_move = monte_carlo_tree_search(root, cp=cp1, N=N1) else: A1_move = monte_carlo_tree_search(root, cp=cp2, N=N2) Game.place(coordinates=A1_move.location, color=A1_color) if Game.is_game_over(): if print_all: Game.print() if first == True: #if method1 win, return True return Game.check_win(A1_color) else: #if method1 win, return True return Game.check_win(A2_color) else: root = Tree(Game, color=A1_color, parent=None, coordinate=A1_move.location) if first == True: A2_move = monte_carlo_tree_search(root, cp=cp2, N=N2) else: A2_move = monte_carlo_tree_search(root, cp=cp1, N=N1) Game.place(coordinates=A2_move.location, color=A2_move.color) root = Tree(Game, color=A2_color, parent=None, coordinate=A2_move.location) if print_all: Game.print() if first == True: #if method1 win or not return Game.check_win(A1_color) else: return Game.check_win(A2_color)
def alphabeta_Id(board: HexBoard, depth: int, alpha: float, beta: float, is_max: bool) -> float: # board.print() print("in alphabeta_Id000000000") try: (hit, g, ttbm) = transposition_table.lookup(board, board.get_board_size(), depth) print("in alphabeta_Id", hit, g, ttbm) except Exception as e: # print('Exception in running lookup function: ' + str(e)) if hit(): return g if depth == 0 or board.is_game_over(): g = dijkstra_eval(board) bm = () legals = board.get_move_list() if legals: if is_max: g: float = -_INF for move in ttbm + legals: updated_board: HexBoard = _update_board( board, move, is_max) # y do we make the move first? gc = alphabeta_Id(updated_board, depth - 1, alpha, beta, is_max) if gc > g: bm = updated_board g = gc alpha = max(alpha, g) if beta <= alpha: break else: # if is_max False g: float = _INF for move in ttbm + legals: updated_board: HexBoard = _update_board(board, move, is_max) gc = alphabeta_Id(updated_board, depth - 1, alpha, beta, is_max) if gc < g: bm = updated_board g = gc beta = min(beta, g) if beta <= alpha: break transposition_table.store(updated_board, updated_board.get_board_size(), g, depth, bm) return g else: print("NO MORE LEGAL MOVES LEFT") return dijkstra_eval(board)
def alphabeta(board: HexBoard, depth: int, alpha: float, beta: float, is_max: bool) -> float: # board.print() if depth == 0 or board.is_game_over(): return dijkstra_eval(board) legals = board.get_move_list() if legals: if is_max: g: float = -_INF for move in legals: updated_board: HexBoard = _update_board(board, move, is_max) g = max( g, alphabeta(updated_board, depth - 1, alpha, beta, is_max=False)) alpha = max(alpha, g) if beta <= alpha: break else: g: float = _INF for move in legals: updated_board: HexBoard = _update_board(board, move, is_max) g = min( g, alphabeta(updated_board, depth - 1, alpha, beta, is_max=True)) beta = min(beta, g) if beta <= alpha: break return g else: print("NO MORE LEGAL MOVES LEFT") return dijkstra_eval(board)
def minimax(board: HexBoard, depth: int, is_max: bool) -> float: if depth == 0 or board.is_game_over(): board.print() return dijkstra_eval(board) legals = board.get_move_list() if legals: if is_max: g: float = -_INF for move in legals: updated_board: HexBoard = _update_board(board, move, is_max) g = max(g, minimax(updated_board, depth - 1, not is_max)) else: g: float = _INF for move in legals: updated_board: HexBoard = _update_board(board, move, is_max) g = min(g, minimax(updated_board, depth - 1, not is_max)) return g
def human_compu(algor, method='random', depth=3): """A function that human play with computer, user can choose their prefered board size(3,4 recommanded), color, want to take first move""" global flag, INF, n_nodes, cutoff, Game, size print('Choose a board size:') size = int(input()) Game = HexBoard(size) print('Choose a color: 1(BLUE) or 2(RED)') print('Blue: from left to right; Red: from top to bottom') opp_color = int(input()) my_color = Game.get_opposite_color(opp_color) print('Do you want to start first? Yes(y) or No(n)') first = input() print('Game start!') # human first move do or not if first == 'y' or first == 'Yes': Game.print() x, y = xy_read(Game) Game.place(coordinates=(x, y), color=opp_color) Game.print() root = Tree(Game, color=opp_color, parent=None, coordinate=(x, y), my_color=my_color) else: first_color = my_color last_color = opp_color root = Tree(Game, color=opp_color, parent=None, coordinate=None, my_color=my_color) INF = 99999 # sufficient large number # human and computer play the game until one of them win while not Game.is_game_over(): if algor == 'alphabeta': # varibales intialization n_nodes = 0 cutoff = 0 flag = 0 my_move = alphabeta(n=root, a=-INF, b=INF, d=depth, method=method, depth=depth, my_color=my_color, opp_color=opp_color) print('n_nodes=', n_nodes, '\n cutoff=', cutoff) elif algor == 'idtt': flag = 0 transpositiontable = [] n_nodes = 0 cutoff = 0 my_move = iterativedeepening(n=root, a=-INF, b=INF, DEPTH_stop=5, time_limit=5, my_color=my_color, opp_color=opp_color) print('n_nodes=', n_nodes, '\n cutoff=', cutoff) elif algor == "mcts": my_move = monte_carlo_tree_search(root, cp=1, N=1000) # retunred variable "my_move" is a node and contains info about computer's next step Game.place(coordinates=my_move.location, color=my_move.color) Game.print() if Game.is_game_over(): break else: # read human's next move x, y = xy_read(Game) Game.place(coordinates=(x, y), color=opp_color) Game.print() root = Tree(Game, color=opp_color, parent=None, coordinate=(x, y), my_color=my_color) if Game.check_win(opp_color): print('Game over! You win :-)') else: print('Game over! You lose :-(')
def mcts_alphabeta(cp=1, N=500, method='dijkstra', depth=3, size=3, print_all=False, first=True, time_limit=5): #mcts plays with method #method='dijkstra' or 'idtt' global flag, user_color, unuse_color, INF, n_nodes, cutoff Game = HexBoard(size) A1_color = 1 A2_color = 2 root = Tree(Game, color=A2_color, parent=None, coordinate=None, my_color=A1_color) if print_all: if first == True: print('First move (blue) is mcts') print('Second move (red) is ' + method) else: print('First move (blue) is ' + method) print('Second move (red) is mcts') while not Game.is_game_over(): INF = 99999 flag = 0 n_nodes = 0 cutoff = 0 if first == True: #mcts moves first A1_move = monte_carlo_tree_search(root, cp=cp, N=N) else: #method moves first if method == 'dijkstra': A1_move = alphabeta(n=root, a=-INF, b=INF, d=depth, method=method, depth=depth, my_color=A1_color, opp_color=A2_color) elif method == 'idtt': A1_move = iterativedeepening(n=root, a=-INF, b=INF, DEPTH_stop=depth, time_limit=time_limit, my_color=A1_color, opp_color=A2_color) Game.place(coordinates=A1_move.location, color=A1_color) if Game.is_game_over(): if print_all: Game.print() if first == True: #if method1 win, return True return Game.check_win(A1_color) else: #if method1 win, return True return Game.check_win(A2_color) else: root = Tree(Game, color=A1_color, parent=None, coordinate=A1_move.location, my_color=A2_color) flag = 0 n_nodes = 0 cutoff = 0 if first == True: if method == 'idtt': A2_move = iterativedeepening(n=root, a=-INF, b=INF, DEPTH_stop=depth, time_limit=time_limit, my_color=A2_color, opp_color=A1_color) elif method == 'dijkstra': A2_move = alphabeta(n=root, a=-INF, b=INF, d=depth, method=method, depth=depth, my_color=A2_color, opp_color=A1_color) else: A2_move = monte_carlo_tree_search(root, cp=cp, N=N) Game.place(coordinates=A2_move.location, color=A2_move.color) root = Tree(Game, color=A2_color, parent=None, coordinate=A2_move.location, my_color=A1_color) if print_all: Game.print() if first == True: #if method1 win or not return Game.check_win(A1_color) else: return Game.check_win(A2_color)
def idtt_alphabeta(method='random', idtt_depth=3, depth2=3, size=3, print_all=False, first=True, time_limit=5): #idtt against alphabeta (random or dijkstra) #idtt_depth is idtt's depth; depth2 is method's deptth #first determins which moves first global flag, INF, n_nodes, cutoff Game = HexBoard(size) #firt move color=A1_color: blue A1_color = 1 #second move color=A1_color: red A2_color = 2 root = Tree(Game, color=A2_color, parent=None, coordinate=None, my_color=A1_color) if print_all: if first == True: print('First move (blue) is idtt') print('Second move (red) is ' + method) else: print('First move (blue) is ' + method) print('Second move (red) is idtt') while not Game.is_game_over(): INF = 99999 flag = 0 n_nodes = 0 cutoff = 0 if first == True: #idtt moves first A1_move = iterativedeepening(n=root, a=-INF, b=INF, DEPTH_stop=idtt_depth, time_limit=time_limit, my_color=A1_color, opp_color=A2_color) else: #method2 moves first A1_move = alphabeta(n=root, a=-INF, b=INF, d=depth2, method=method, depth=depth2, my_color=A1_color, opp_color=A2_color) Game.place(coordinates=A1_move.location, color=A1_color) if Game.is_game_over(): if print_all: Game.print() if first == True: #if idtt win, return True return Game.check_win(A1_color) else: #if idtt win, return True return Game.check_win(A2_color) else: root = Tree(Game, color=A1_color, parent=None, coordinate=A1_move.location, my_color=A2_color) n_nodes = 0 cutoff = 0 flag = 0 if first == True: A2_move = alphabeta(n=root, a=-INF, b=INF, d=depth2, method=method, depth=depth2, my_color=A2_color, opp_color=A1_color) else: A2_move = iterativedeepening(n=root, a=-INF, b=INF, DEPTH_stop=idtt_depth, time_limit=time_limit, my_color=A2_color, opp_color=A1_color) Game.place(coordinates=A2_move.location, color=A2_move.color) root = Tree(Game, color=A2_color, parent=None, coordinate=A2_move.location, my_color=A1_color) if print_all: Game.print() if first == True: #if method1 win or not return Game.check_win(A1_color) else: return Game.check_win(A2_color)
def alphabeta_randomVSdijkstra(method1='random', method2='dijkstra', depth1=3, depth2=3, size=3, print_all=False, first=True): #alphabeta: method1 and method2 can choose 'random' or 'dijkstra' #first==True: method1 moves first #first determins which moves first global flag, user_color, unuse_color, INF, n_nodes, cutoff Game = HexBoard(size) #firt move color=A1_color: blue A1_color = 1 #second move color=A1_color: red A2_color = 2 root = Tree(Game, color=A2_color, parent=None, coordinate=None, my_color=A1_color) if print_all: if first == True: print('First move (blue) is ' + method1) print('Second move (red) is ' + method2) else: print('First move (blue) is ' + method2) print('Second move (red) is ' + method1) while not Game.is_game_over(): INF = 99999 flag = 0 n_nodes = 0 cutoff = 0 if first == True: #method1 moves first A1_move = alphabeta(n=root, a=-INF, b=INF, d=depth1, method=method1, depth=depth1, my_color=A1_color, opp_color=A2_color) else: #method2 moves first A1_move = alphabeta(n=root, a=-INF, b=INF, d=depth2, method=method2, depth=depth2, my_color=A1_color, opp_color=A2_color) Game.place(coordinates=A1_move.location, color=A1_color) if Game.is_game_over(): if print_all: Game.print() if first == True: #if method1 win, return True return Game.check_win(A1_color) else: #if method1 win, return True return Game.check_win(A2_color) else: root = Tree(Game, color=A1_color, parent=None, coordinate=A1_move.location, my_color=A2_color) n_nodes = 0 cutoff = 0 flag = 0 if first == True: A2_move = alphabeta(n=root, a=-INF, b=INF, d=depth2, method=method2, depth=depth2, my_color=A2_color, opp_color=A1_color) else: A2_move = alphabeta(n=root, a=-INF, b=INF, d=depth1, method=method1, depth=depth1, my_color=A2_color, opp_color=A1_color) Game.place(coordinates=A2_move.location, color=A2_move.color) root = Tree(Game, color=A2_color, parent=None, coordinate=A2_move.location, my_color=A1_color) if print_all: Game.print() if first == True: #if method1 win or not return Game.check_win(A1_color) else: return Game.check_win(A2_color)