def get_input(self, piece_type, previous_board, board): """ Get one input. :param piece_type: 1('X') or 2('O'). :param previous_board: board int :param board: current board int :return: (row, column) coordinate of input. """ board_int = GameBoard.encode_board(board) previous_board_int = GameBoard.encode_board(previous_board) self.previous_board = previous_board_int self.board = board_int self.piece_type = piece_type if piece_type == 1 and board_int == 0: return 2, 2 if self.debug: print("=====player debug=====") print("{}'s move".format(self.piece_type)) score, action = self._greedy(previous_board_int, board_int, "move") if self.debug: print(GameBoard.visualize_evaluation(board, piece_type)) print("minmax player make action {} with score {}".format( action, score)) print("=====player debug=====") return action
def get_input(self, piece_type, previous_board, board): """ Get one input. :param piece_type: 1('X') or 2('O'). :param previous_board: board :param board: current board :return: (row, column) coordinate of input. """ board_int = GameBoard.encode_board(board) previous_board_int = GameBoard.encode_board(previous_board) self.previous_board = previous_board_int self.board = board_int self.piece_type = piece_type # First piece if piece_type == 1 and board_int == 0: # TODO: write something to storage return 2, 2 # self._setup_depth(board) if self.debug: print("=====player debug=====") print("{}'s move, d={}".format(self.piece_type, self.depth)) score, action = self._max(previous_board_int, board_int, "move") if self.debug: print(GameBoard.visualize_evaluation(board_int, piece_type)) print("minmax player make action {} with score {}".format( action, score)) print("=====player debug=====") # TODO: write something to storage return action
def _max(self, previous_board_int, board_int, previous_action): valid_moves = self._get_valid_moves(previous_board_int, board_int, self.piece_type) if not valid_moves: return 0, "pass" best_value = float("-inf") action = None for i, j in valid_moves: new_previous_board_int = board_int # impossible to be unsuccessful new_board_int, success = GameBoard.place_chess( previous_board_int, board_int, i, j, self.piece_type) score = self._minmax(False, new_previous_board_int, new_board_int, "move", self.depth - 1, float("-inf"), float("inf"), debug=False) if self.debug: print( GameBoard.visualize_evaluation(board_int, self.piece_type)) print(" {},{} with score {}".format(str(i), str(j), score)) if score > best_value: best_value = score action = (i, j) return best_value, action
def test_get_board_piece(self): board = [[0, 1, 0, 0, 0], [0, 0, 2, 1, 0], [0, 0, 1, 0, 1], [0, 0, 0, 0, 0], [0, 0, 1, 0, 2]] h = GameBoard.encode_board(board) self.assertEqual(GameBoard.get_board_piece(h, 0, 1), 1) self.assertEqual(GameBoard.get_board_piece(h, 4, 4), 2) self.assertEqual(GameBoard.get_board_piece(h, 1, 2), 2)
def test_compute_hash(self): board = [[0, 1, 0, 0, 0], [0, 0, 2, 1, 0], [0, 0, 1, 0, 1], [0, 0, 0, 0, 0], [0, 0, 1, 0, 2]] hash = GameBoard.encode_board(board) print("hash is: {}".format(hash)) res = GameBoard.decode_board(hash) print(GameBoard.visualize_board_list(res)) self.assertTrue(GameBoard.compare_board(board, res))
def test_standarize_board(self): board = [[0, 1, 1, 0, 0], [0, 1, 2, 1, 0], [0, 0, 1, 0, 1], [0, 0, 0, 0, 0], [0, 0, 1, 0, 2]] board_int = GameBoard.encode_board(board) new_board_int = GameBoard.standarize_board(board_int, WHITE) print(GameBoard.visualize_board(new_board_int)) res_board = [[0, 2, 2, 0, 0], [0, 2, 1, 2, 0], [0, 0, 2, 0, 2], [0, 0, 0, 0, 0], [0, 0, 2, 0, 1]] res_board_int = GameBoard.encode_board(res_board) self.assertEqual(new_board_int, res_board_int)
def test_evaluate3(self): # piece_type: 1('X')black or 2('O')white. piece_type = 1 player = GreedyPlayer() board = [ [0, 2, 0, 0, 0], [0, 0, 1, 1, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 2, 0, 2, 2] ] board_int = GameBoard.encode_board(board) print(GameBoard.visualize_evaluation(board_int, piece_type))
def test_evaluation(self): verbose = True q_table = FileHandler.read_q_table(path="../QLearner/QTable.pkl") my_player = QLearningPlayer(q_table=q_table, debug=False) previous_board = [[0, 0, 0, 0, 0], [0, 0, 0, 2, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]] previous_board_int = GameBoard.encode_board(previous_board) board = [[0, 0, 0, 0, 0], [0, 0, 1, 2, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]] board_int = GameBoard.encode_board(board) valid_moves = GameBoard.get_valid_moves(previous_board_int, board_int, 2) print(my_player._check_q_table(board_int, valid_moves)) print(my_player.get_input(2, previous_board, board))
def test_evaluate2(self): # piece_type: 1('X')black or 2('O')white. piece_type = 1 player = GreedyPlayer() board = [ [0, 0, 0, 0, 0], [0, 0, 2, 1, 0], [0, 0, 1, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0] ] board_int = GameBoard.encode_board(board) print(GameBoard.visualize_evaluation(board_int, piece_type)) move = (2, 2) print(GameBoard.evaluate_move(board_int, piece_type, move, debug=True))
def _greedy(self, previous_board_int, board_int, previous_action): valid_moves = self._get_valid_moves(previous_board_int, board_int, self.piece_type) if not valid_moves: # TODO: handle no valid move, or pass return 0, "PASS" # check q table check = self._check_q_table(board_int, valid_moves) if check: print("find") return check # check history table # encoded_board = board_int # check = self._check_encoded_state(encoded_board, self.piece_type) # if check: # return check best_value, action = float("-inf"), None for move in valid_moves: value = GameBoard.evaluate_move(board_int, self.piece_type, move, params=self.params) if value > best_value: best_value, action = value, move if best_value < 0: return 0, "PASS" # write to history dictionary # self._store_encoded_state(encoded_board, self.piece_type, best_value, action) return best_value, action
def _get_valid_moves(self, previous_board_int, board_int, piece_type): # state = self._encode_state(board) # if state in self.valid_moves: # if piece_type in self.valid_moves[state]: # return self.valid_moves[state][piece_type] moves = GameBoard.get_valid_moves(previous_board_int, board_int, piece_type) # self.valid_moves[state] = {piece_type: moves} return moves
def _check_q_table(self, board_int, valid_moves): # standarize board state = GameBoard.standarize_board(board_int, self.piece_type) # direct find if state in self.q_table: # print("find") return self._find_max(self.q_table[state], valid_moves) # transform and search for r in range(3): new_state = GameBoard.rotate_board(state) if new_state in self.q_table: q_values = deepcopy(self.q_table[new_state]) # rotate the q values table back r_back_times = 4 - r for _ in range(r_back_times): GameBoard.rotate(q_values) return self._find_max(q_values, valid_moves) return False
def test_new_board2(self): board = [[0, 1, 0, 0, 0], [0, 0, 2, 1, 0], [0, 0, 1, 0, 1], [0, 0, 0, 0, 0], [0, 0, 1, 0, 2]] h = GameBoard.encode_board(board) new_b = [[0, 1, 0, 0, 0], [0, 0, 0, 1, 0], [0, 0, 1, 0, 1], [0, 0, 0, 0, 0], [0, 0, 1, 0, 2]] print(GameBoard.visualize_board_list(board)) print(GameBoard.visualize_board_list(new_b)) new_hash = GameBoard.new_board(h, 1, 2, 0) res = GameBoard.decode_board(new_hash) print(GameBoard.visualize_board_list(res)) self.assertTrue(GameBoard.compare_board(res, new_b))
def _setup_depth(self, board_int): """ set up depth depending on number of moves """ empty_space = GameBoard.count_empty(board_int) if empty_space <= 8: self.depth = 3 elif 8 < empty_space <= 12: self.depth = 4 elif 12 < empty_space <= 16: self.depth = 3 elif 16 < empty_space <= 20: self.depth = 2 else: self.depth = 2
def test_remove_died_pieces(self): board = [[0, 1, 1, 0, 0], [0, 1, 2, 1, 0], [0, 0, 1, 0, 1], [0, 0, 0, 0, 0], [0, 0, 1, 0, 2]] new_b = [[0, 1, 1, 0, 0], [0, 1, 0, 1, 0], [0, 0, 1, 0, 1], [0, 0, 0, 0, 0], [0, 0, 1, 0, 2]] board_int = GameBoard.encode_board(board) pieces, board_int = GameBoard.remove_died_pieces(board_int, 2) print(pieces) print(GameBoard.visualize_board(board_int)) self.assertEqual( GameBoard.compare_board(new_b, GameBoard.decode_board(board_int)), True) self.assertEqual(GameBoard.encode_board(new_b), board_int)
def _greedy(self, previous_board_int, board_int, previous_action): # check history table encoded_board = board_int check = self._check_encoded_state(encoded_board, self.piece_type) if check: return check valid_moves = self._get_valid_moves(previous_board_int, board_int, self.piece_type) best_value, action = float("-inf"), None for move in valid_moves: value = GameBoard.evaluate_move(board_int, self.piece_type, move) if value > best_value: best_value, action = value, move if not valid_moves: # TODO: handle no valid move, or pass return 0, "PASS" # write to history dictionary self._store_encoded_state(encoded_board, self.piece_type, best_value, action) return best_value, action
def test_be_killed_score(self): piece_type = 2 move = (2, 3) board = [[0, 0, 0, 0, 0], [0, 0, 2, 1, 0], [0, 0, 1, 0, 1], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]] board_int = GameBoard.encode_board(board) result = GameBoard.be_killed_score(board_int, piece_type, move) self.assertEqual(result, -1) piece_type = 2 move = (4, 2) board = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 2, 2, 0, 0], [0, 0, 1, 1, 0], [0, 1, 0, 2, 0]] board_int = GameBoard.encode_board(board) result = GameBoard.be_killed_score(board_int, piece_type, move) self.assertEqual(result, -1) piece_type = 2 move = (1, 1) board = [[0, 0, 0, 0, 0], [0, 0, 2, 1, 0], [0, 0, 1, 0, 1], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]] board_int = GameBoard.encode_board(board) result = GameBoard.be_killed_score(board_int, piece_type, move) self.assertEqual(result, 0)
def read_stage2_log(path, win_table, lose_table, champion_only=True): with open(path, "r") as f: lines = f.readlines() i = 0 previous_board_int = 0 board_int = 0 black_board_list = [] white_board_list = [] champion_black_board_list = [] champion_white_board_list = [] winner = None start_play = False champion_player = False while i < len(lines): line = lines[i].strip() if "ERROR" in line or "not found or invalid format" in line: break if "Invalid" in line: print("found invalid") break if "championship_player" in line: champion_player = True if "=====Round" in line: # new round # read who is black, who is white, may not use i += 1 player_line = lines[i] player_line_list = player_line.strip().split(" ") # print(player_line_list) start_play = True i += 1 # rest to default previous_board_int = 0 board_int = 0 black_board_list = [] white_board_list = [] winner = None continue if start_play: if "The winner is" in line: # figure out winner winner_str = line[-1] if winner_str == "O": # white wins winner = WHITE # print("white wins") elif winner_str == "X": winner = BLACK # print("black wins") else: raise ValueError # record board list if winner == WHITE: if champion_only: win_table.extend(champion_white_board_list) lose_table.extend(champion_black_board_list) else: win_table.extend(white_board_list) lose_table.extend(black_board_list) elif winner == BLACK: if champion_only: win_table.extend(champion_black_board_list) lose_table.extend(champion_white_board_list) else: win_table.extend(black_board_list) lose_table.extend(white_board_list) winner = None start_play = False champion_player = False if ("Black" in line or "White" in line) and "PASS" not in line: move_list = line.split(" ")[1].split(",") move_i = int(move_list[0]) move_j = int(move_list[1]) # store state and move if "Black" in line: piece_type = BLACK black_board_list.append([ GameBoard.standarize_board(board_int, piece_type), (move_i, move_j) ]) if champion_player: champion_black_board_list.append([ GameBoard.standarize_board( board_int, piece_type), (move_i, move_j) ]) else: piece_type = WHITE white_board_list.append([ GameBoard.standarize_board(board_int, piece_type), (move_i, move_j) ]) if champion_player: champion_white_board_list.append([ GameBoard.standarize_board( board_int, piece_type), (move_i, move_j) ]) temp_board_int, success = GameBoard.place_chess( previous_board_int, board_int, move_i, move_j, piece_type) previous_board_int = board_int d, board_int = GameBoard.remove_died_pieces( temp_board_int, 3 - piece_type) # print("piece{} i: {}, j: {}".format(piece_type, move_i, move_j)) # print(GameBoard.visualize_board(board_int)) # read who wins i += 1
def test_detect_neighbor_all(self): print(GameBoard.detect_neighbor_all(0, 4, 4))
def _get_valid_moves(self, previous_board_int, board_int, piece_type): moves = GameBoard.get_valid_moves(previous_board_int, board_int, piece_type) return moves
def _minmax(self, is_max, previous_board_int, board_int, previous_action, depth, alpha, beta, debug=False): if is_max: piece_type = self.piece_type else: piece_type = 3 - self.piece_type # TODO: check if end of game (both don't have valid moves), return +inf or -inf # check history table encoded_board = board_int check = self._check_encoded_state(encoded_board, piece_type) if check: return check valid_moves = self._get_valid_moves(previous_board_int, board_int, piece_type) if not valid_moves: # TODO: handle no valid move return 0 best_value = float("-inf") if is_max else float("inf") if depth < 1: for move in self._get_valid_moves(previous_board_int, board_int, self.piece_type): score = GameBoard.evaluate_move(board_int, self.piece_type, move) if is_max: best_value = max(score, best_value) else: best_value = min(score, best_value) if debug: print(" in {} end".format("max" if is_max else "min")) print( GameBoard.visualize_evaluation(board_int, self.piece_type)) print(" give {} with score {}".format( "max" if is_max else "min", best_value)) return best_value for i, j in valid_moves: new_previous_board_int = board_int # impossible to be unsuccessful new_board_int, success = GameBoard.place_chess( previous_board_int, board_int, i, j, piece_type) score = self._minmax(not is_max, new_previous_board_int, new_board_int, previous_action, depth - 1, alpha, beta) if is_max: best_value = max(score, best_value) alpha = max(alpha, best_value) else: best_value = min(score, best_value) beta = min(best_value, beta) if beta <= alpha: break if debug: print(" in {}".format("max" if is_max else "min")) print(GameBoard.visualize_evaluation(board_int, self.piece_type)) print(" give {} with score {}".format( "max" if is_max else "min", best_value)) # write to history dictionary self._store_encoded_state(encoded_board, piece_type, best_value) return best_value