def simulate_lr(self, color): # simulate one time # record all X features to feature_matrix # update the y value accordingly print("entering simulations") newboard = Board(self.col, self.row, self.p) newboard.initialize_game() feature_list_b = [] feature_list_w = [] win = 0 ### TODO: Fixing Current move in a new board curr_turn = self.opponent[color] for turn in range(50): if newboard.is_win(color) == color: win = 1 break elif newboard.is_win(self.opponent[color]) == self.opponent[color]: break move = self.minimax_move(newboard.get_all_possible_moves(curr_turn)) newboard.make_move(move, curr_turn) b, w = self.get_X(self.board) feature_list_b.append(b) feature_list_w.append(w) self.feature_matrix = np.append(self.feature_matrix, np.array([b, w]), axis=0) print(self.feature_matrix) curr_turn = self.opponent[curr_turn] else: win = 0.5 # matrix = np.array([feature_list_b, feature_list_w]) # feature_matrix = np.hstack((matrix, np.zeros((matrix.shape[0], 1)))) # TODO: Fixing y value update if win == 1 and color == 1: for fb in feature_list_b: index = np.where(fb in self.feature_matrix[:, 0:self.feature_size]) if index == []: self.feature_matrix = np.append(self.feature_matrix, np.array([b, w]), axis=0) self.feature_matrix[index, self.feature_size] += 1 elif win == 0 and color == 1: for fw in feature_list_w: index = np.where(fw in self.feature_matrix[:, 0:self.feature_size]) if index == []: self.feature_matrix = np.append(self.feature_matrix, np.array([b, w]), axis=0) self.feature_matrix[index, self.feature_size] += 1 return win
def train_one_episode(self): new_board = Board() new_board.initialize_game() turn = '' while True: if new_board.is_win(self.color): break elif new_board.is_win(self.opponent[self.color]): break action = self.explore(new_board, self.color) state = new_board new_state = new_board.make_move(action, turn) self.Q_table[state, action] = self.Q_table[state, action] + self.lr * \ (self.reward(state, action) + self.gamma * np.max(self.Q_tableQ[new_state, :])\ - self.Q_table[state, action]) state = new_state
class StudentAI(): def __init__(self, col, row, p): self.col = col self.row = row self.p = p self.board = Board(col, row, p) self.board.initialize_game() self.color = '' self.opponent = {1: 2, 2: 1} self.color = 2 self.root = Node(self.color, -1) self.start = None def flatten(self, ini_list) -> list: return sum(ini_list, []) def isTimeLeft(self): time = datetime.datetime.now() if (time - self.start).seconds < turnTimer: return True return False def select( self ) -> Node: #REMINDER: moves is the flattened list of all available moves maxNode = self.root maxUct = -1 ptr = self.root uct = None found = False while len(ptr.children) != 0: #Node is not a leaf node moves = self.flatten(self.board.get_all_possible_moves(ptr.color)) for m in moves: found = False for c in ptr.children: if not found and m == c.move: uct = c.UCT() if uct > maxUct: maxUct = uct maxNode = c found = True if not found: return ptr #Node is a leaf node, return parent to expand later if maxNode.move != -1: self.board.make_move(maxNode.move, ptr.color) ptr = maxNode # Node is leaf node return ptr #Same thing as line 135 def expand(self, node) -> Node: moves = self.flatten(self.board.get_all_possible_moves(node.color)) toMove = moves[0] childrenMoves = [] for c in node.children: childrenMoves.append(c.move.seq) for m in moves: if childrenMoves.count( m.seq ) == 0: #Get all available moves for node, then find the leaf node to expand toMove = m break child = Node(self.opponent[node.color], toMove, node) node.children.append(child) return child def simulate(self, child): players = {1: "B", 2: "W"} winner = None counter = 0 color = child.color while self.board.is_win(players[color]) == 0: moves = self.flatten(self.board.get_all_possible_moves(color)) if len(moves) != 0: #player has moves i = randint(0, len(moves) - 1) self.board.make_move(moves[i], color) color = self.opponent[color] counter += 1 else: #player doesnt have moves, but game hasn't ended yet color = self.opponent[color] winner = self.board.is_win(players[color]) while counter != 0: self.board.undo() counter -= 1 return winner def backProp(self, result, child): while child is not None: child.upSims() if result != child.color: child.upWins() child = child.parent def MCTS(self, moves) -> Move: while (self.isTimeLeft()): parent = self.select() expand = self.expand(parent) #TODO check if expand() returns None result = self.simulate(expand) self.backProp(result, expand) bestMove = None # self.root.children[i].move if len(self.root.children) == 0: index = randint(0, len(moves) - 1) bestMove = moves[index] else: bestWR = -1 i = 0 while i != len(self.root.children): if self.root.children[i].getWinRate() > bestWR: bestWR = self.root.children[i].getWinRate() bestMove = self.root.children[i].move i += 1 return bestMove def get_move(self, move): if len(move) != 0: self.board.make_move(move, self.opponent[self.color]) if self.root.parent is None: # len(self.root.children) == 0: #what if the root.children doesnt contain the one move we wanted? # FIX: checking len of self.root.children to moves of self.root self.root.move = move else: i = 0 while i != len(self.root.children): if self.root.children[i].move == move: break i += 1 if i != len(self.root.children): self.root = self.root.children[i] else: #no child node: add it new_root = Node(self.color, move, self.root) self.root.children.append(new_root) self.root = new_root else: self.color = 1 self.root.color = 1 self.start = datetime.datetime.now() moves = self.flatten(self.board.get_all_possible_moves( self.root.color)) move = self.MCTS(moves) self.board.make_move(move, self.root.color) # PROBLEM LINE: color mismatch # update root to move just picked from MCTS i = 0 while i != len(self.root.children): if self.root.children[i].move == move: break i += 1 self.root = self.root.children[i] return move
class StudentAI(): def __init__(self, col, row, p): self.col = col self.row = row self.p = p self.board = Board(col, row, p) self.board.initialize_game() self.color = '' self.opponent = {1: 2, 2: 1} self.color = 2 self.search_lim = 5 self.current_node = TreeNode(None, self.color) def get_move(self, move): if len(move) != 0: # print("|" + str(move) + "|") self.board.make_move(move, self.opponent[self.color]) #print("Player", self.opponent[self.color], "make move", move) if len(self.current_node.child_node) != 0: for child in self.current_node.child_node: if str(child.move) == str(move): self.current_node = child else: self.color = 1 self.current_node.player = self.color for i in range(NS): self.mcts(self.current_node) #self.board.show_board() #print("mcts counter:", i) move = self.current_node.child_node[0] for child in self.current_node.child_node: if move.uct() < child.uct(): move = child self.board.make_move(move.move, self.color) # print("Player", self.color, "make move", move.move, "with a winrate of", move.winrate(), "simulated", move.simulation) self.current_node = move return move.move def mcts(self, node): if node.simulation >= minVisit: #print("depth:", depth) node.simulation += 1 if not len(node.child_node): moves = self.board.get_all_possible_moves(node.player) for move in moves: for eachmove in move: node.child_node.append( TreeNode(eachmove, self.opponent[node.player], node)) # proceed next = self.mcts_selection(node) self.board.make_move(next.move, node.player) result = self.board.is_win(node.player) if result: if result == self.opponent[node.player]: node.win += 1 elif result == node.player: next.win += 1 next.simulation += 1 self.board.undo() return result #self.board.show_board() result = self.mcts(next) self.board.undo() # propagate up if result == self.opponent[node.player]: node.win += 1 return result else: result = self.simulate(node.player) node.simulation += 1 if result == self.opponent[node.player]: node.win += 1 #print("simulating", result) return result def mcts_selection(self, node): # Select optimal UCB node current = node.child_node[0] for child in node.child_node: #print(current.uct()) if current.uct() < child.uct(): current = child #print("player", node.player, "pick", current.move) return current def simulate(self, player): win = 0 counter = 0 fake_board = Board(self.col, self.row, self.p) self.copy_board(fake_board) # print("DIT ME DIEN") # fake_board.show_board() # totaltime = 0 while win == 0: moves = fake_board.get_all_possible_moves(player) if len(moves) == 1: index = 0 elif len(moves) == 0: win = self.opponent[player] break else: index = randint(0, len(moves) - 1) if len(moves[index]) == 1: inner_index = 0 else: inner_index = randint(0, len(moves[index]) - 1) move = moves[index][inner_index] fake_board.make_move(move, player) counter += 1 # bt = time.time() if fake_board.tie_counter >= fake_board.tie_max: win = -1 # totaltime += time.time() - bt # print("self.board.is_win():", time.time() - bt) player = self.opponent[player] # #print("total time is_win:", totaltime) # #bt = time.time() # for i in range(counter): # self.board.undo() # #rint("total time undo:", time.time() - bt) # fake_board.show_board() return win def copy_board(self, board): """ EZ game :return: ez board """ board.tie_counter = self.board.tie_counter board.tie_max = self.board.tie_max board.board = copy.deepcopy(self.board.board) board.saved_move = copy.deepcopy(self.board.saved_move) board.black_count = self.board.black_count board.white_count = self.board.white_count
def alpha_beta_negamax(self, board: Board, depth: int, max_depth: int, alpha: int, beta: int, start_time: int) -> MoveWithAnalysis: if time.time() - start_time > TIME_LIMIT: # print("Depth: {}".format(depth)) return None if board.is_win() or depth > max_depth: # print("Depth: {}".format(depth)) if depth % 2 == 0: heuristic = self.evaluate_board(board, self.player_number) current_move = MoveWithAnalysis(None, None, heuristic) return current_move else: heuristic = self.evaluate_board(board, self.opponent_number) current_move = MoveWithAnalysis(None, None, -heuristic) return current_move best_move = None if self.valid_moves.empty() and not self.moves_generated: children = self.expand_node(board) for child in children: result_board = copy.deepcopy(board) result_board = result_board.make_move(child, self.player_number) current_move = MoveWithAnalysis(child.col, child.row, 0) current_move.heuristic = self.evaluate_board(result_board, self.player_number) self.valid_moves.put(current_move) self.moves_generated = True # self.valid_moves.sort(reverse=True) if depth == 0: temp_queue = PriorityQueue() while not self.valid_moves.empty(): valid_move = self.valid_moves.get() result_board = copy.deepcopy(board) result_board = result_board.make_move(valid_move, self.player_number) current_move = self.alpha_beta_negamax(result_board, depth + 1, max_depth, -beta, -alpha, start_time) if current_move is None: return None current_move.col = valid_move.col current_move.row = valid_move.row current_move.heuristic = -current_move.heuristic valid_move.heuristic = current_move.heuristic temp_queue.put(valid_move) # print("({}, {}): {}".format(valid_move.col, valid_move.row, valid_move.heuristic)) if best_move is None or current_move.heuristic > best_move.heuristic: best_move = current_move if current_move.heuristic > alpha: alpha = current_move.heuristic if alpha >= beta: # print("PRUNED") return best_move self.valid_moves = temp_queue else: children = self.expand_node(board) for child in children: result_board = copy.deepcopy(board) if depth % 2 == 0: result_board = result_board.make_move(child, self.player_number) else: result_board = result_board.make_move(child, self.opponent_number) current_move = self.alpha_beta_negamax(result_board, depth + 1, max_depth, -beta, -alpha, start_time) if current_move is None: return None current_move.col = child.col current_move.row = child.row current_move.heuristic = -current_move.heuristic if best_move is None or current_move.heuristic > best_move.heuristic: best_move = current_move if current_move.heuristic > alpha: alpha = current_move.heuristic if alpha >= beta: # print("PRUNED") return best_move return best_move
class StudentAI(): def __init__(self,col,row,p): self.col = col self.row = row self.p = p self.board = Board(col,row,p) self.board.initialize_game() self.color = '' self.opponent = {1:2,2:1} self.color = 2 def get_move(self,move): if len(move) != 0: self.board.make_move(move,self.opponent[self.color]) else: self.color = 1 bestVal = -999 bestMove = None # if there is only one move to make, just make the move without evaluating possible_moves = self.board.get_all_possible_moves(self.color) if len(possible_moves) == 1 and len(possible_moves[0]) == 1: self.board.make_move(possible_moves[0][0], self.color) return possible_moves[0][0] for moves in possible_moves: for move in moves: self.board.make_move(move, self.color) val = self.search(1, StudentAI.switchColors(self.color), MIN, MAX) self.board.undo() if val > bestVal: bestVal = val bestMove = move self.board.make_move(bestMove, self.color) return bestMove def search(self, depth, currentColor, alpha, beta): if depth == 4 or self.board.is_win('B') or self.board.is_win('W'): return self.evaluate(currentColor) best = MIN if currentColor == self.color else MAX for moves in self.board.get_all_possible_moves(currentColor): for move in moves: self.board.make_move(move, currentColor) val = self.search(depth+1, StudentAI.switchColors(currentColor), alpha, beta) self.board.undo() if currentColor == self.color: best = max(best, val) alpha = max(alpha, best) elif currentColor != self.color: best = min(best, val) beta = min(beta, best) if beta <= alpha: return best return best def piece_differential(self, currentColor): if currentColor == 'B': return self.board.black_count - self.board.white_count return self.board.white_count - self.board.black_count def evaluate(self, currentColor): currentColor = 'B' if currentColor == 1 else 'W' oppColor = 'W' if currentColor == 'B' else 'B' # if we win in this game state, prefer to choose this path # if the opponent wins in this game state, stay away from this path if self.board.is_win(currentColor): return 500 elif self.board.is_win(oppColor): return -500 piece_location, kings = 0, 0 for i in range(self.board.row): for j in range(self.board.col): if (self.board.board[i][j].color == currentColor): if self.board.board[i][j].is_king: kings += 1 # we prefer the king to be in the middle of the board if i <= self.row / 2: piece_location += 7 + i else: piece_location += 7 + (self.board.row - i - 1) else: # we prefer the pawns to go to the opponent's side of the board if self.board.board[i][j].color == 'B': piece_location += 5 + i else: piece_location += 5 + (self.board.row - i - 1) elif (self.board.board[i][j].color == oppColor): if self.board.board[i][j].is_king: kings -= 1 # we prefer the opponent's king to not be in the middle of the board if i <= self.row / 2: piece_location -= 7 + i else: piece_location -= 7 + (self.board.row - i - 1) else: # we prefer the opponent's pawns to not be on our side of the board if self.board.board[i][j].color == 'B': piece_location -= 5 + i else: piece_location -= 5 + (self.board.row - i - 1) # if we have more kings, we prefer to play more aggressive if kings > 0: return piece_location + self.board.row * self.piece_differential(currentColor) else: return piece_location + self.piece_differential(currentColor) @staticmethod def switchColors(color): if color == 1: return 2 return 1
class StudentAI(): def __init__(self, col, row, p): self.col = col self.row = row self.p = p self.board = Board(col, row, p) self.board.initialize_game() self.number_of_move = 0 self.EARLY_GAME = 10 self.MID_GAME = 20 self.END_GAME = 30 self.run_time_depth = 5 self.opponent = {1: 2, 2: 1} self.color = 2 def get_move(self, move): if len(move) != 0: self.board.make_move(move, self.opponent[self.color]) else: self.color = 1 move = self.best_move() if self.board.row == self.board.col: self.run_time_depth = self.get_depth(True) if self.board.row != self.board.col: self.run_time_depth = self.get_depth(False) self.board.make_move(move, self.color) self.number_of_move += 1 return move # ALPHA BETA PRUNE STARTS HERE def best_move(self) -> Move: moves = self.board.get_all_possible_moves(self.color) smart_move = Move([]) alpha = -math.inf beta = math.inf for checkers in moves: for move in checkers: self.board.make_move(move, self.color) heuristic = self.alpha_beta_prune(1, self.opponent[self.color], alpha, beta) self.board.undo() if heuristic > alpha: alpha = heuristic smart_move = Move(move) return smart_move def alpha_beta_prune(self, depth, player, alpha, beta) -> float: all_moves = self.board.get_all_possible_moves(player) if depth is self.run_time_depth: return self.evaluate() if not all_moves: winplayer = self.board.is_win(self.opponent[player]) if winplayer == self.color: return 100000 elif winplayer == self.opponent[self.color]: return -100000 else: return 0 if player is self.color: current_score = -math.inf for checker in all_moves: for move in checker: self.board.make_move(move, player) heuristic = self.alpha_beta_prune(depth + 1, self.opponent[player], alpha, beta) self.board.undo() current_score = max(heuristic, current_score) alpha = max(current_score, alpha) if alpha >= beta: break return current_score else: current_score = math.inf for checker in all_moves: for move in checker: self.board.make_move(move, player) heuristic = self.alpha_beta_prune(depth + 1, self.opponent[player], alpha, beta) self.board.undo() current_score = min(heuristic, current_score) beta = min(current_score, beta) if alpha >= beta: break return current_score # make new function to evaluate king def evaluate(self) -> float: white_king = 0 white_chess = 0 black_king = 0 black_chess = 0 white_king_list = list() black_king_list = list() white_chess_list = list() black_chess_list = list() for all_checkers in self.board.board: for checker in all_checkers: if checker.is_king: if checker.color == "W": white_king += 1 white_king_list.append(checker) if checker.color == "B": black_king += 1 black_king_list.append(checker) else: if checker.color == "W": white_chess += 2 white_chess_list.append(checker) if checker.color == "B": black_chess += 2 black_chess_list.append(checker) white_chess, black_chess = self.get_score( checker, white_chess, black_chess) king_dis = 1 if self.color == 1: score = self.board.black_count - self.board.white_count + ( black_king * 8 + black_chess) - (white_chess + white_king * 5) for checker in black_king_list: for opponent in white_chess_list: king_dis += self.calculate_distance( checker.row, checker.col, opponent.row, opponent.col) else: score = 1 + self.board.white_count - self.board.black_count + ( white_king * 8 + white_chess) - (black_chess + black_king * 5) for checker in white_king_list: for opponent in black_chess_list: king_dis += self.calculate_distance( checker.row, checker.col, opponent.row, opponent.col) return score / king_dis def calculate_distance(self, first_row, first_col, second_row, second_col) -> float: a = abs(first_row - second_row) b = abs(first_col - second_col) return max(a, b) def get_depth(self, is_equal): if self.number_of_move != 0: if is_equal: if self.number_of_move <= 5: return 3 if self.number_of_move <= self.EARLY_GAME: return 5 if self.number_of_move <= self.END_GAME: return 7 return 3 else: if 1 <= self.number_of_move <= 5: return 3 if 6 <= self.number_of_move <= 10: return 5 if self.number_of_move % 2 == 0: return 5 return 3 return 3 def get_score(self, checker, white_chess, black_chess): if checker.col == 0 or checker.col == self.col - 1: if checker.color == "W": white_chess += 1 if checker.color == "B": black_chess += 1 if checker.col - 1 > 0 and checker.row - 1 > 0: if self.board.board[checker.row - 1][checker.col - 1].color == "W": white_chess += 0.5 if self.board.board[checker.row - 1][checker.col - 1].color == "B": black_chess += 0.5 if checker.col - 1 > 0 and checker.row + 1 <= self.row - 1: if self.board.board[checker.row + 1][checker.col - 1].color == "W": white_chess += 0.5 if self.board.board[checker.row + 1][checker.col - 1].color == "B": black_chess += 0.5 if checker.col + 1 <= self.col - 1 and checker.row - 1 > 0: if self.board.is_in_board(checker.row - 1, checker.col + 1): if self.board.board[checker.row - 1][checker.col + 1].color == "W": white_chess += 0.5 if self.board.board[checker.row - 1][checker.col + 1].color == "B": black_chess += 0.5 if checker.col + 1 < self.col - 1 and checker.row + 1 <= self.row - 1: if self.board.is_in_board(checker.row + 1, checker.col + 1): if self.board.board[checker.row + 1][checker.col + 1] == "W": white_chess += 0.5 if self.board.board[checker.row + 1][checker.col + 1] == "B": black_chess += 0.5 return white_chess, black_chess
class StudentAI(): def __init__(self, col, row, p): self.col = col self.row = row self.p = p self.board = Board(col, row, p) self.board.initialize_game() self.color = '' self.opponent = {1: 2, 2: 1} self.color = 2 self.search_depth = 5 self.debug = True self.time_used = 0 self.transposition_table = dict() def get_move(self, move): if self.debug: current_move_elapsed = time.time() if len(move) != 0: self.board.make_move(move, self.opponent[self.color]) else: self.color = 1 moves = self.board.get_all_possible_moves(self.color) # index = randint(0,len(moves)-1) # inner_index = randint(0,len(moves[index])-1) # move = moves[index][inner_index] how_many_moves = 0 for outer_index in range(len(moves)): how_many_moves += len(moves[outer_index]) if how_many_moves == 1: if self.debug: self.time_used += (time.time() - current_move_elapsed) print("Total elapsed time (in seconds):", self.time_used) self.board.make_move(moves[0][0], self.color) return moves[0][0] depth = round((4 / how_many_moves) + self.search_depth) if self.debug: print(how_many_moves, "possible moves") print("Depth:", depth) best_move = None best_move_score = -math.inf for outer_index in range(len(moves)): for inner_index in range(len(moves[outer_index])): self.board.make_move(moves[outer_index][inner_index], self.color) move_score = self.search(depth, moves[outer_index][inner_index], self.color, -math.inf, math.inf) self.board.undo() if move_score > best_move_score: best_move_score = move_score best_move = moves[outer_index][inner_index] self.board.make_move(best_move, self.color) if self.debug: self.time_used += (time.time() - current_move_elapsed) print("Total elapsed time (in seconds):", self.time_used) return best_move def search(self, depth, move, turn, alpha, beta): current_key = self.get_key() if current_key in self.transposition_table.keys( ) and depth == self.transposition_table[current_key].depth: return self.transposition_table[current_key].value winner = self.board.is_win(turn) win_return = 1000 + depth if winner != 0: if winner == -1: self.transposition_table[current_key] = TTEntry(0, depth) return 0 if self.color == winner: self.transposition_table[current_key] = TTEntry( win_return, depth) return win_return self.transposition_table[current_key] = TTEntry(-win_return, depth) return -win_return if depth == 0: black = 0 white = 0 for x in range(self.board.row): for y in range(self.board.col): if self.board.board[x][y].color == "W": white += 5 if self.board.board[x][y].is_king: white += self.row + 2 else: white += x if self.board.board[x][y].color == "B": black += 5 if self.board.board[x][y].is_king: black += self.row + 2 else: black += (self.row - x - 1) score = black - white if self.color == 1: # 1 = black self.transposition_table[current_key] = TTEntry(score, depth) return score self.transposition_table[current_key] = TTEntry(-score, depth) return -score # 2 = white if turn == self.color: # min worst = math.inf possible_moves = self.board.get_all_possible_moves( self.opponent[self.color]) for x in range(len(possible_moves)): for y in range(len(possible_moves[x])): self.board.make_move(possible_moves[x][y], self.opponent[self.color]) current = self.search(depth - 1, possible_moves[x][y], self.opponent[self.color], alpha, beta) self.board.undo() if current < worst: worst = current if current < beta: beta = current if beta <= alpha: break else: continue break self.transposition_table[current_key] = TTEntry(worst, depth) return worst else: # max best = -math.inf possible_moves = self.board.get_all_possible_moves(self.color) for x in range(len(possible_moves)): for y in range(len(possible_moves[x])): self.board.make_move(possible_moves[x][y], self.color) current = self.search(depth - 1, possible_moves[x][y], self.color, alpha, beta) self.board.undo() if current > best: best = current if current > alpha: alpha = current if beta <= alpha: break else: continue break self.transposition_table[current_key] = TTEntry(best, depth) return best def get_key(self): key = "" for x in range(self.board.row): for y in range(self.board.col): if self.board.board[x][y].color == "B": key += "1" elif self.board.board[x][y].color == "W": key += "2" else: key += "0" return key
class StudentAI(): def __init__(self, col, row, p): self.col = col self.row = row self.p = p self.board = Board(col, row, p) self.board.initialize_game() self.color = '' self.opponent = {1: 2, 2: 1} self.color = 2 def get_move(self, move): # make opponents move if len(move) != 0: self.board.make_move(move, self.opponent[self.color]) # switch turn else: self.color = 1 # find player 1 next move moves = self.board.get_all_possible_moves(self.color) alpha = -INFINITY beta = INFINITY result = self.move_ordering(self.color) for move in moves: for m in move: limit = 0 self.board.make_move(m, self.color) val = self.min_value(limit + 1, alpha, beta) if val > alpha: alpha = val result = m self.board.undo() self.board.make_move(result, self.color) return result def max_value(self, limit, alpha, beta): if limit == MINIMAX_DEPTH or self.board.is_win( self.color) == self.color: return self.heuristic() #alpha = -INFINITY # result = -infinity # move = self.move_ordering(self.color) # if not move: # return alpha # self.board.make_move(move,self.color) # v = self.min_value(limit+1,alpha,beta) # self.board.undo() # if v >= beta: # return INFINITY # alpha = max(alpha,v) val = -INFINITY moves = self.board.get_all_possible_moves(self.color) for move in moves: for m in move: self.board.make_move(m, self.color) val = max(val, self.min_value(limit + 1, alpha, beta)) self.board.undo() alpha = max(alpha, val) if alpha >= beta: return val return val def min_value(self, limit, alpha, beta): if limit == MINIMAX_DEPTH or self.board.is_win( self.color) == self.opponent[self.color]: return self.heuristic() #beta = INFINITY # result = infinity # move = self.move_ordering(self.opponent[self.color]) # if not move: # return beta # self.board.make_move(move,self.opponent[self.color]) # v = self.max_value(limit+1,alpha,beta) # self.board.undo() # if alpha >= v: # return -INFINITY # beta = min(beta,v) # return beta val = INFINITY moves = self.board.get_all_possible_moves(self.opponent[self.color]) for move in moves: for m in move: self.board.make_move(m, self.opponent[self.color]) val = min(val, self.max_value(limit + 1, alpha, beta)) self.board.undo() beta = min(beta, val) if alpha >= beta: # pruning - go to next move (?) return val return val def heuristic(self): black = 0 white = 0 #if (self.board.black_count+self.board.white_count) > (0.4* self.board.p * self.board.col): # Decide between early game and mid,end game for row in range(self.board.row): for col in range(self.board.col): if self.board.board[row][col].color == "B": if self.board.board[row][col].is_king: # King = 10 black += self.board.row else: black += (5 + self.board.board[row][col].row - (0.5 * self.board.row) ) # reg piece = 5 + rows on oponent side elif self.board.board[row][col].color == "W": if self.board.board[row][col].is_king: # King = 10 white += self.board.row else: white += (5 + (self.board.row * 0.5) - self.board.board[row][col].row ) # reg piece = 5 + rows on oponent s if self.color == 1: return black - white else: return white - black def move_ordering(self, player): best_move_value = -INFINITY if (player == self.color) else INFINITY moves = self.board.get_all_possible_moves(player) if moves: best_move = moves[0][0] else: return False for move in moves: for m in move: self.board.make_move(m, player) v = self.heuristic() if v > best_move_value if ( player == self.color) else v < best_move_value: best_move_value = v best_move = m self.board.undo() return best_move
class StudentAI(): def __init__(self, col, row, p): self.col = col self.row = row self.p = p self.board = Board(col, row, p) self.board.initialize_game() self.color = '' self.opponent = {1: 2, 2: 1} self.color = 2 self.f = open("debug.txt", "w") def heuristic_black(self): count_b = 0 count_w = 0 for i in range(int(len(self.board.board) / 2)): for j in range(len(self.board.board[i])): if self.board.board[i][j].color == 1: if self.board.board[i][j].is_king == True: count_b += 10 else: count_b += 5 else: if self.board.board[i][j].is_king == True: count_w += 10 else: count_w += 7 for i in range(int(len(self.board.board) / 2), len(self.board.board)): for j in range(len(self.board.board[i])): if self.board.board[i][j].color == 1: if self.board.board[i][j].is_king == True: count_b += 10 else: count_b += 7 else: if self.board.board[i][j].is_king == True: count_w += 10 else: count_w += 5 # for i in self.board.board: # for j in i: # # if j.color == 1: # if j.is_king == True: # count_b += 7 + self.row # else: # count_b += 5 + (self.row - j.row) # elif j.color == 2: # if j.is_king == True: # count_w += 7 + self.row # else: # count_w += 5 + j.row return count_b - count_w def get_move(self, move): if len(move) != 0: self.board.make_move(move, self.opponent[self.color]) else: self.color = 1 moves = self.board.get_all_possible_moves(self.color) self.f.write("Curr Moves: " + str(moves) + '\n') if len(moves) == 1 and len(moves[0]) == 1: move = moves[0][0] self.board.make_move(move, self.color) return move move = self.minimax(moves) self.f.write("Chosen Move: " + str(move) + '\n') # index = randint(0,len(moves)-1) # inner_index = randint(0,len(moves[index])-1) # move = moves[index][inner_index] self.board.make_move(move, self.color) return move def minimax(self, moves): dic_l1 = dict() for peice in range(len(moves)): for i in range(len(moves[peice])): move = moves[peice][i] self.board.make_move(move, self.color) if self.board.is_win(self.color) == self.color: self.board.undo() return moves[peice][i] l2_moves = self.board.get_all_possible_moves( self.opponent[self.color]) # print("Opponent Moves: \n peice: ",peice, "\n dir: ",i, "\nMoves\n", l2_moves) dic_l2 = dict() for opp_peice in range(len(l2_moves)): for j in range(len(l2_moves[opp_peice])): move = l2_moves[opp_peice][j] self.board.make_move(move, self.opponent[self.color]) l3_moves = self.board.get_all_possible_moves( self.color) dic_l3 = dict() # print("L3 ",l3_moves) for my_peice in range(len(l3_moves)): flag = 0 for k in range(len(l3_moves[my_peice])): move = l3_moves[my_peice][k] self.board.make_move(move, self.color) value = -1 if self.color == 1: value = (self.board.black_count / (self.board.black_count + self.board.white_count)) * 100 else: value = (self.board.white_count / (self.board.black_count + self.board.white_count)) * 100 key = str(my_peice) + ' ' + str(k) # print(key, ' ', value) dic_l3[key] = value self.board.undo() if self.board.is_win(self.color) == self.color: flag = 1 break if flag == 1: break if len(dic_l3) == 0: key = str(opp_peice) + ' ' + str(j) dic_l2[key] = int(0x40000) self.board.undo() else: inverse = [(value, key) for key, value in dic_l3.items()] l2_value = max(inverse)[0] key = str(opp_peice) + ' ' + str(j) dic_l2[key] = l2_value self.board.undo() if len(dic_l2) == 0: key = str(peice) + ' ' + str(i) dic_l1[key] = int(-0x40000) self.board.undo() else: inverse = [(value, key) for key, value in dic_l2.items()] l1_value = min(inverse)[0] key = str(peice) + ' ' + str(i) dic_l1[key] = l1_value self.board.undo() inverse = [(value, key) for key, value in dic_l1.items()] l0_value = max(inverse)[1] # print(dic_l1) # print(l0_value) x, y = l0_value.split(' ') return moves[int(x)][int(y)]