def put_stone(self, log: List[Stone]) -> Stone: turn = turn_check(log, self.p, self.q) if len(log) == 0: return Stone(str(10), str(10), turn) if len(log) == 1: next_x = int(log[0].x) + choice([-1, 1]) next_y = int(log[0].y) + choice([-1, 1]) return Stone(str(next_x), str(next_y), turn) log_x = [int(stone.x) for stone in log] log_y = [int(stone.y) for stone in log] left_end = max(min(log_x) - self.k, 1) right_end = min(max(log_x) + self.k, self.m) upper_end = max(min(log_y) - self.k, 1) lower_end = min(max(log_y) + self.k, self.n) width = right_end - left_end + 1 height = lower_end - upper_end + 1 focus_area = np.zeros((height, width), dtype=int) for stone in log: normalize_row_index = int(stone.y) - upper_end normalize_column_index = int(stone.x) - left_end focus_area[ normalize_row_index, normalize_column_index] = 1 if stone.color == "b" else -1 horizontal = self.find_connection(focus_area, Direction.HORIZONTAL, left_end, upper_end) vertical = self.find_connection(focus_area, Direction.VERTICAL, left_end, upper_end) negative_diagonal = self.find_connection(focus_area, Direction.NEGATIVE_DIAGONAL, left_end, upper_end) positive_diagonal = self.find_connection(focus_area, Direction.POSITIVE_DIAGONAL, left_end, upper_end) candidates = horizontal + vertical + negative_diagonal + positive_diagonal if len(candidates) == 0: random_empty_spot = choice(self.empty_spots(log)) return Stone(random_empty_spot.x, random_empty_spot.y, turn) max_stone = max( [self.stone_sum(candidate) for candidate in candidates]) if max_stone >= self.k: return Stone("1", "1", turn) max_stone_candidates = [ candidate for candidate in candidates if self.stone_sum(candidate) == max_stone ] max_stone_candidate = choice(max_stone_candidates) window_index = (sorted( [i for i, x in enumerate(max_stone_candidate.pattern) if x == 0], key=lambda x: abs(x - self.k / 2), )[0]) position = max_stone_candidate.position[window_index] return Stone(str(position[0]), str(position[1]), turn)
def put_stone(self, log: List[Stone]) -> Stone: turn = turn_check(log, self.p, self.q) if len(log) == 0: x = randint(1, self.n) y = randint(1, self.m) return Stone(str(x), str(y), turn) position = choice(self.suggest_positions(log)) return Stone(position.x, position.y, turn)
def move_stone(stone: Stone, direction: str, stride: int = 1) -> Stone: x = int(stone.x) y = int(stone.y) if direction == Direction.LEFT: x = x - stride elif direction == Direction.RIGHT: x = x + stride elif direction == Direction.UP: y = y - stride elif direction == Direction.DOWN: y = y + stride elif direction == Direction.UP_LEFT: y = y - stride x = x - stride elif direction == Direction.UP_RIGHT: y = y - stride x = x + stride elif direction == Direction.DOWN_LEFT: y = y + stride x = x - stride else: # direction == Direction.DOWN_RIGHT: y = y + stride x = x + stride return Stone(str(x), str(y), stone.color)
def empty_spots(self, log: List[Stone]) -> List[Stone]: full_area = np.zeros((self.n, self.m), dtype=int) for item in log: full_area[int(item.y) - 1, int(item.x) - 1] = 1 empty_spot_index = np.where(full_area == 0) empty_spot_list = [] for coordinate in list(zip(empty_spot_index[0], empty_spot_index[1])): empty_spot_list.append( Stone(str(coordinate[1] + 1), str(coordinate[0] + 1), "empty")) return empty_spot_list
def check_diagonal_by_direction(current_stone: Stone, stone_history: List[Stone], radius: int, directions, ) -> bool: direction_list = [Stone(current_stone.x, current_stone.y, current_stone.color)] for direction in directions: current_x, current_y = int(current_stone.x), int(current_stone.y) for i in range(radius - 1): new_x, new_y = direction(current_x, current_y) direction_list.append(Stone(str(new_x), str(new_y), current_stone.color)) current_x, current_y = new_x, new_y in_position = [] for item in sorted(direction_list, key=lambda s: int(s.x)): if item in stone_history: in_position.append("1") else: in_position.append("0") in_position_concat = "".join(in_position) return "1" * radius in in_position_concat
def suggest_positions(self, log: List[Stone], lower: int = 1, upper: int = 19) -> List[Stone]: suggestions = [] for d in Direction.ALL_DIRECTIONS: position = list(map(lambda x: self.move_stone(x, d, 1), log)) position = list( filter( lambda x: lower <= int(x.x) <= upper and lower <= int(x.y) <= upper, position)) suggestions = suggestions + position suggestions = set(map(lambda x: x.x + " " + x.y, suggestions)) suggestions = list(map(lambda x: x.split(" "), suggestions)) suggestions = list(map(lambda z: Stone(z[0], z[1], "s"), suggestions)) stone_array = self.stone_to_array(log) suggestions = self.stone_to_array(suggestions) suggestions = np.clip(stone_array + suggestions, -1, 0) suggestions = self.array_to_stone(suggestions, "s") return suggestions
def search(self, board, net, simulate_num, T, add_dirichlet_noise): logger.info("Search start!") for i in range(simulate_num): logger.info("simulate %s" % i) cp_board = copy.deepcopy(board) logger.info("root %s" % cp_board) # move to leaf node = self.root is_done, winner = None, None while not node.is_leaf(): node, action = node.select() logger.info("select action: %s, select node info: %s" % (action, node)) pos = (action // conf.board_size, action % conf.board_size) is_done, winner = cp_board.step(Stone(pos, cp_board.turn)) logger.info("board %s" % cp_board) if is_done: if winner is None: v = 0 else: v = winner logger.info("Get done leaf, v: %s" % v) else: ps, v = net.predict(np.array([cp_board.get_feature()])) logger.info("Get leaf, v: %s" % v) if add_dirichlet_noise and i == 0: ps = self.dirichlet_noise(ps) for idx in cp_board.illegal_idx: ps[idx] = 0 ps /= sum(ps) node.expand(ps=ps, player=cp_board.turn) node.backup(v) ret = [0] * conf.board_size**2 for idx, child in self.root.children.items(): ret[idx] = child.N return np.array(ret)**(1.0 / T) / sum(np.array(ret)**(1.0 / T))
def play(): x = request.args.get("x") y = request.args.get("y") color = request.args.get("color") if regex_digit.match(x) is None: return {"code": 400, "message": "illegal input in x"}, 400 if regex_digit.match(y) is None: return {"code": 400, "message": "illegal input in y"}, 400 if regex_color.match(color) is None: return {"code": 400, "message": "illegal input in stone"}, 400 if color != util.turn_check(board.log, board.config.each_move, board.config.first_move): board.print_illegal_turn() board.save_figure() return render_template("board.html") stone = Stone(x, y, color) if not referee.valid_check(stone, board.log): board.print_illegal_stone() board.save_figure() return render_template("board.html") board.put_stone(stone) end_check = referee.end_check(board.log, board.config) if end_check.is_end: winner = "no one" if end_check.is_tie else color board.print_winner(winner) board.save_figure() return render_template("board.html") board.print_on_playing() board.save_figure() return render_template("board.html")
def __init__(self, *args, **kwargs): super(StrategicBotTest, self).__init__(*args, **kwargs) self.test_config = BoardConfig(19, 19, 6, 2, 1) self.vertical_test_log = [ Stone("3", "2", "b"), Stone("2", "1", "w"), Stone("2", "2", "w"), Stone("1", "2", "b"), Stone("1", "3", "b"), Stone("2", "3", "w"), Stone("2", "4", "w"), Stone("1", "4", "b"), Stone("1", "5", "b"), Stone("2", "5", "w"), Stone("2", "8", "w"), Stone("1", "10", "b"), Stone("1", "11", "b"), Stone("2", "9", "w"), ] self.diagonal_test_log = [ Stone("1", "2", "b"), Stone("1", "1", "w"), Stone("2", "2", "w"), Stone("1", "3", "b"), Stone("1", "4", "b"), Stone("3", "3", "w"), Stone("4", "4", "w"), Stone("1", "5", "b"), Stone("1", "8", "b"), Stone("5", "5", "w"), Stone("8", "4", "w"), Stone("7", "10", "b"), Stone("8", "10", "b"), Stone("9", "11", "w"), Stone("6", "7", "w"), Stone("4", "10", "b"), Stone("5", "10", "b"), Stone("7", "5", "w"), ] self.sb = StrategicBot(self.test_config)
suggestions = self.array_to_stone(suggestions, "s") return suggestions def put_stone(self, log: List[Stone]) -> Stone: turn = turn_check(log, self.p, self.q) if len(log) == 0: x = randint(1, self.n) y = randint(1, self.m) return Stone(str(x), str(y), turn) position = choice(self.suggest_positions(log)) return Stone(position.x, position.y, turn) if __name__ == "__main__": diagonal_test_log = [ Stone("1", "2", "b"), Stone("1", "1", "w"), Stone("2", "2", "w"), Stone("1", "3", "b"), Stone("1", "4", "b"), Stone("3", "3", "w"), Stone("4", "4", "w"), Stone("1", "5", "b"), Stone("1", "6", "b"), Stone("5", "5", "w"), Stone("6", "5", "w"), Stone("10", "11", "b"), Stone("11", "11", "b"), Stone("6", "6", "w"), ]
def play_a_agme(self, net, paint=False): logger.info("New game start!") steps = 0 board = Board() mcts = MCTS() data = [] ps = [] while True: feature = board.get_feature() p = mcts.search( board=board, net=net, simulate_num=conf.simulate_num, T=1 if steps < conf.explore_steps else 0.5, add_dirichlet_noise=True, ) debug_ps, debug_v = net.predict(np.array([feature])) logger.info("V: %s" % debug_v) info = '' info += "NetWork predict probs:\n" for i in range(1, len(debug_ps) + 1): info += "%.3f" % debug_ps[i - 1] + ' ' if i % conf.board_size == 0: info += '\n' logger.info(info) info = '' info += "MCTS search probs:\n" for i in range(1, len(p) + 1): info += "%.3f" % p[i - 1] + ' ' if i % conf.board_size == 0: info += '\n' logger.info(info) data.append(feature) ps.append(p) idx = np.random.choice(conf.board_size ** 2, p=p) pos = (idx // conf.board_size, idx % conf.board_size) mcts.change_root(idx) stone = Stone(pos, board.turn) is_done, winner = board.step(stone) steps += 1 if paint: logger.info(board) if is_done: if paint: if winner == Player.O: logger.info("O WIN!") elif winner == Player.X: logger.info("X WIN!") else: logger.info("NO WINNER!") if winner == Player.O: vs = [Player.O] * len(data) elif winner == Player.X: vs = [Player.X] * len(data) else: vs = [0] * len(data) return self.data_augmentation( zip(data, ps, vs) )
def empty_spots(self, log: List[Stone]) -> List[Stone]: full_area = np.zeros((self.n, self.m), dtype=int) for item in log: full_area[int(item.y) - 1, int(item.x) - 1] = 1 empty_spot_index = np.where(full_area == 0) empty_spot_list = [] for coordinate in list(zip(empty_spot_index[0], empty_spot_index[1])): empty_spot_list.append( Stone(str(coordinate[1] + 1), str(coordinate[0] + 1), "empty")) return empty_spot_list if __name__ == "__main__": vertical_test_log = [ Stone("3", "2", "b"), Stone("2", "1", "w"), Stone("2", "2", "w"), Stone("1", "2", "b"), Stone("1", "3", "b"), Stone("2", "3", "w"), Stone("2", "4", "w"), Stone("1", "4", "b"), Stone("1", "5", "b"), Stone("2", "5", "w"), Stone("2", "8", "w"), Stone("1", "10", "b"), Stone("1", "11", "b"), Stone("2", "9", "w"), ] diagonal_test_log = [
def player_input(color: str) -> Stone: x = input("x: ") y = input("y: ") return Stone(x, y, color)
if len(log) == 0: x = randint(1, self.n) y = randint(1, self.m) return Stone(str(x), str(y), turn) elif len(self.suggest_positions(log)) > 0: position = choice(self.suggest_positions(log)) else: x = randint(1, self.n) y = randint(1, self.m) return Stone(str(x), str(y), turn) return Stone(position.x, position.y, turn) if __name__ == "__main__": diagonal_test_log = [ Stone("1", "2", "b"), Stone("1", "1", "w"), Stone("2", "2", "w"), Stone("1", "3", "b"), Stone("1", "4", "b"), Stone("3", "3", "w"), Stone("4", "4", "w"), Stone("1", "5", "b"), Stone("1", "6", "b"), Stone("5", "5", "w"), Stone("7", "5", "w"), Stone("10", "11", "b"), Stone("11", "11", "b"), Stone("6", "6", "w"), ]
direction_list.append(Stone(str(new_x), str(new_y), current_stone.color)) current_x, current_y = new_x, new_y in_position = [] for item in sorted(direction_list, key=lambda s: int(s.x)): if item in stone_history: in_position.append("1") else: in_position.append("0") in_position_concat = "".join(in_position) return "1" * radius in in_position_concat if __name__ == "__main__": test_board_config = BoardConfig(19, 19, 6, 2, 1) test_log = [ Stone("1", "1", "b"), Stone("2", "1", "w"), Stone("2", "2", "w"), Stone("1", "2", "b"), Stone("1", "3", "b"), Stone("2", "3", "w"), Stone("2", "4", "w"), Stone("1", "4", "b"), Stone("1", "5", "b"), Stone("2", "5", "w"), Stone("2", "8", "w"), Stone("1", "10", "b"), Stone("1", "11", "b"), Stone("2", "9", "w"), Stone("2", "6", "w"), ]
def random_bot(self, color: str) -> Stone: x = randint(1, self.config.column) y = randint(1, self.config.row) return Stone(str(x), str(y), color)