def _reset(self): self.board = Board(self.board_shape, max_per_cell=1) self.phase = self.game_phases[0] self.state = SeegaState(board=self.board, next_player=self.first_player, boring_limit=self.just_stop, game_phase=self.phase) self.current_player = self.first_player
def _reset(self): self.done = False self.rewarding_move = False self.board = BoardGUI(self.board_shape) self.state = SeegaState(board=self.board.get_board_state(), next_player=self.first_player, boring_limit=self.just_stop) self.trace = Trace(self.state, players={-1: self.players[-1].name, 1: self.players[1].name}) self.current_player = self.first_player
def _reset(self): self.done = False self.board = Board(self.board_shape) self.state = SeegaState(board=self.board, next_player=self.player_color, boring_limit=self.just_stop) # self.trace = Trace( # self.state, players={-1: self.players[-1].name, 1: self.players[1].name} # ) self.current_player = self.player_color self._fill_board()
def _reset_for_new_game(self): self.board.reset_board() self.board.score = {-1: 0, 1: 0} self.done = False self.board.enable_all_squares() self.panel.reset_panel_player() self.board.current_player = -1 self.current_player = self.first_player self.panel.update_current_player(self.current_player) self.state = SeegaState(board=self.board.get_board_state(), next_player=self.first_player, boring_limit=self.just_stop) self.board.set_default_colors() for key in self.players.keys(): self.players[key].reset_player_informations()
class SeegaGUI(QMainWindow): depth_to_cover = 9 automatic_save_game = False def __init__(self, app, shape, players, allowed_time=120.0, sleep_time=.500, first_player=-1, boring_limit=200, parent=None): super(SeegaGUI, self).__init__(parent) self.app = app self.saved = True self.board_shape = shape self.players = players self.allowed_time = allowed_time self.sleep_time = sleep_time self.first_player = first_player self.just_stop = boring_limit self.setWindowTitle("[*] MAIC 2018 - Seega Game") self.statusBar() self.setWindowIcon(QtGui.QIcon("assets/icon.png")) layout = QHBoxLayout() layout.addStretch() self.board_gui = BoardGUI(self.board_shape) layout.addWidget(self.board_gui) layout.addSpacing(15) self.panel = Panel([players[-1].name, players[1].name]) layout.addWidget(self.panel) layout.addStretch() content = QWidget() content.setLayout(layout) self.setCentralWidget(content) self.create_menu() self._reset() # self.trace = Trace(self.board.get_board_array()) # self.random_player = AI(self.board.currentPlayer, self.board_size) def _reset(self): self.done = False self.rewarding_move = False self.board = BoardGUI(self.board_shape) self.state = SeegaState(board=self.board.get_board_state(), next_player=self.first_player, boring_limit=self.just_stop) self.trace = Trace(self.state, players={ -1: self.players[-1].name, 1: self.players[1].name }) self.current_player = self.first_player def reset(self): self._reset() def create_menu(self): menu = self.menuBar() # Game Menu game_menu = menu.addMenu("Game") # New Game Submenu new_game_action = QAction( QtGui.QIcon.fromTheme("document-new", QtGui.QIcon("../assets/New file.png")), 'New Game', self) new_game_action.setShortcut(QtGui.QKeySequence.New) new_game_action.setStatusTip("New game Luncher") new_game_action.triggered.connect(self.new_game_trigger) game_menu.addAction(new_game_action) game_menu.addSeparator() # Load Game Submenu load_game_action = QAction( QtGui.QIcon.fromTheme("document-new", QtGui.QIcon("../assets/Open file.png")), 'Load Game', self) load_game_action.setShortcut(QtGui.QKeySequence.Open) load_game_action.setStatusTip("Load a previous game") load_game_action.triggered.connect(self.load_game_trigger) game_menu.addAction(load_game_action) # Save Game save_game_action = QAction( QtGui.QIcon.fromTheme("document-new", QtGui.QIcon("pieces/Save.png")), 'Save Game', self) save_game_action.setShortcut(QtGui.QKeySequence.Save) save_game_action.setStatusTip("Save current game") save_game_action.triggered.connect(self.save_game_trigger) game_menu.addAction(save_game_action) game_menu.addSeparator() # Exit and close game exit_game_action = QAction( QtGui.QIcon.fromTheme("document-new", QtGui.QIcon("pieces/Close.png")), 'Exit Game', self) exit_game_action.setShortcut(QtGui.QKeySequence.Quit) exit_game_action.setMenuRole(QAction.QuitRole) exit_game_action.setStatusTip("Exit and close window") exit_game_action.triggered.connect(self.exit_game_trigger) game_menu.addAction(exit_game_action) menu.addSeparator() # Help Menu help_menu = menu.addMenu("Help") # Rules game_rules_action = QAction( QtGui.QIcon.fromTheme("document-new", QtGui.QIcon("pieces/Help.png")), 'Rules', self) game_rules_action.setMenuRole(QAction.AboutRole) game_rules_action.triggered.connect(self.game_rules_trigger) help_menu.addAction(game_rules_action) help_menu.addSeparator() # About about_action = QAction('About', self) about_action.setMenuRole(QAction.AboutRole) about_action.triggered.connect(self.about_trigger) help_menu.addAction(about_action) def new_game_trigger(self): new_game = QMessageBox.question(self, 'New Game', "You're about to start a new Game.", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if new_game == QMessageBox.Yes: self._reset_for_new_game() self.app.processEvents() self.play_game() else: pass def _reset_for_new_game(self): self.board.reset_board() self.board.score = {-1: 0, 1: 0} self.done = False self.board.enable_all_squares() self.panel.reset_panel_player() self.board.current_player = -1 self.current_player = self.first_player self.panel.update_current_player(self.current_player) self.state = SeegaState(board=self.board.get_board_state(), next_player=self.first_player, boring_limit=self.just_stop) self.board.set_default_colors() for key in self.players.keys(): self.players[key].reset_player_informations() def step(self, action): """Plays one step of the game. Takes an action and perform in the environment. Args: action (Action): An action containing the move from a player. Returns: bool: Dependent on the validity of the action will return True if the was was performed False if not. """ assert isinstance( action, SeegaAction), "action has to be an Action class object" result = SeegaRules.act(self.state, action, self.current_player) if isinstance(result, bool): return False else: self.state, self.done = result self.current_player = self.state.get_next_player() return True def play_game(self): hit = 0 timer_first_player = Timer("first_player", total_time=self.allowed_time, logger=None) timer_second_player = Timer("second_player", total_time=self.allowed_time, logger=None) turn = self.first_player while not self.done: hit += 1 time.sleep(self.sleep_time) state = deepcopy(self.state) remain_time = timer_first_player.remain_time( ) if turn == -1 else timer_second_player.remain_time() remain_time_copy = deepcopy(remain_time) if SeegaRules.is_player_stuck(state, turn): state.set_next_player(turn * -1) self.state.set_next_player(turn * -1) turn = turn * -1 self.current_player = state.get_next_player() self._update_gui() if remain_time > 0: timer_first_player.start( ) if turn == -1 else timer_second_player.start() action = self.players[turn].play(state, remain_time_copy) elapsed_time = timer_first_player.stop( ) if turn == -1 else timer_second_player.stop() remain_time = timer_first_player.remain_time( ) if turn == -1 else timer_second_player.remain_time() if self.step(action): print('Action performed successfully by', turn, ' in', str(elapsed_time), ' rest ', remain_time) else: print( "An illegal move were given. Performing a random move") print(f"Lunching a random move for {turn}") action = SeegaRules.random_play( state, turn) # TODO: Should we use the original state? else: print("Not remain time for ", turn, " Performing a random move") print(f"Lunching a random move for {turn}") action = SeegaRules.random_play( state, turn) # TODO: Should we use the original state? self._update_gui() self.trace.add(self.state) self.players[turn].update_player_infos(self.get_player_info(turn)) turn = self.state.get_next_player() self._update_gui() self._results() self.save_game_trigger() self.board_gui.set_default_colors() print("\nIt's over.") def _update_gui(self): action = self.state.get_latest_move() self.app.processEvents() if action['action_type'] == 'ADD': # app.processEvents() to = action['action']['to'] self.board_gui.squares[to[0]][to[1]].set_background_color("blue") self.board_gui.add_piece(to, self.state.get_latest_player()) self.app.processEvents() elif action['action_type'] == 'MOVE': to = action['action']['to'] at = action['action']['at'] self.app.processEvents() self.board_gui.squares[at[0]][at[1]].set_background_color("blue") self.app.processEvents() time.sleep(self.sleep_time / 2) self.board_gui.set_default_colors() self.board_gui.squares[to[0]][to[1]].set_background_color("green") self.app.processEvents() time.sleep(self.sleep_time / 2) self.board_gui.move_piece(at, to, self.state.get_latest_player()) self.board_gui.set_default_colors() time.sleep(self.sleep_time / 2) if self.state.captured is not None: for p in self.state.captured: i, j = p self.board_gui.squares[i][j].set_background_color("red") self.app.processEvents() self.board_gui.remove_piece(p) time.sleep(self.sleep_time / 2) self.app.processEvents() self.panel.update_score(self.state.score, self.state.in_hand) self.board_gui.set_default_colors() self.panel.update_current_player(self.state.get_next_player()) def get_player_info(self, player): return self.state.get_player_info(player) def is_end_game(self): return self.done def _results(self): if self.done: self.trace.done = self.done results = SeegaRules.get_results(self.state) if not results['tie']: end = QMessageBox.information( self, "End", f"{self.players[results['winner']].name} wins.") else: end = QMessageBox.information(self, "End", "No winners.") def load_battle(self, states, delay=0.5, done=True): hit = 0 self.board.set_default_colors() self.state = states[0] for state in states[1:]: action = state.get_latest_move() self.state = state self._update_gui() time.sleep(delay) self.done = done self._results() print("It's over.") def load_game_trigger(self): self.board.set_default_colors() name = QtWidgets.QFileDialog.getOpenFileName( self, 'Load Game', options=QFileDialog.DontUseNativeDialog) print(name[0]) trace = self.trace.load(name[0]) print(trace.players) self._reset_for_new_game() actions = trace.get_actions() delay, ok = QInputDialog.getDouble(self, 'Enter the delay', '') players_name = trace.players self.panel.update_players_name(players_name) self.load_battle(actions, delay, trace.done) def save_game_trigger(self): if self.done: if self.automatic_save_game: self.trace.write(self.players[-1].name + "-" + self.players[1].name) else: name = QtWidgets.QFileDialog.getSaveFileName( self, 'Save Game', options=QFileDialog.DontUseNativeDialog) if name[0] == "": pass else: self.trace.write(name[0]) else: warning = QMessageBox.warning(self, "Warning", "No game ongoing") def exit_game_trigger(self): sys.exit(self.app.exec_()) def game_rules_trigger(self): rules = "Yoté Rules \n " \ "The game is played on a 5×6 board, which is empty at the beginning of the game. Each player has twelve pieces in hand. Players alternate turns, with White(or green) moving first. In a move, a player may either: \n" \ "-Place a piece in hand on any empty cell of the board. \n" \ "-Move one of their pieces already on the board orthogonally to an empty adjacent cell. \n" \ "-Capture an opponent's piece if it is orthogonally adjacent to a player's piece, by jumping to the empty cell immediately beyond it. The captured piece is removed from the board, and the capturing player removes another of the opponent's pieces of his choosing from the board. \n" \ "The player who captures all the opponent's pieces is the winner. The game can end in a draw if both players are left with three or fewer pieces. \n" \ "For more informations : https://en.wikipedia.org/wiki/Yot%C3%A9" box = QMessageBox() box.about(self, "Rules", rules) def about_trigger(self): about = "MAIC 2018 Seega Game by MIFY and AAAI Benin" box = QMessageBox() box.about(self, "About", about) def closeEvent(self, a0: QtGui.QCloseEvent): if self.exit_game_trigger() == True: a0.accept() else: a0.ignore()
class SeegaEnv(Env): player_color = Color.black.value # player using the env oponent_color = Color.green.value metadata = {"render.modes": ["log"]} _color_to_int = np.vectorize(lambda color: color.value) def __init__( self, shape, oponent, n_turn=300, allowed_time=120.0, boring_limit=200, render_mode="log", ): super(SeegaEnv, self).__init__() assert isinstance( oponent, Player), "The oponent needs to be an instance of Player" self.nrow, self.ncol = self.board_shape = np.array(shape) self.oponent = oponent self.turn = 0 self.n_turn = n_turn self.allowed_time = allowed_time self.just_stop = boring_limit self.done = False self.oponent_timer = Timer("oponent_time", total_time=self.allowed_time, logger=None) self.observation_space = gym.spaces.Box( -1, 1, shape=self.board_shape ) # -1 = black (player), 0 = empty, 1 = green (oponent) # self.action_space = gym.spaces.Dict( # { # str(SeegaActionType.ADD.value): gym.spaces.Box( # 0, # np.array([self.ncol, self.nrow]), # shape=np.array([2]), # dtype=np.uint8, # ), # str(SeegaActionType.MOVE.value): gym.spaces.Box( # 0, # np.array([self.ncol, self.nrow, 3]), # shape=np.array([3]), # dtype=np.uint8, # ), # 0 = left, 1 = up, 2 = right, 3 = down # } # ) # self.action_space = gym.spaces.Box( # 0, np.array([self.ncol, self.nrow, 3]), shape=np.array([3]), dtype=np.uint8 # ) # 0 = left, 1 = up, 2 = right, 3 = down self.action_space = gym.spaces.Discrete(self.ncol * self.nrow * 4) self._reset() # def _log_timer(fun): # def inner(self, *args, **kwargs): # self.timer.start() # results = fun(self, *args, **kwargs) # self.timer.stop() # return results # return inner def _state_to_ndarray(self, state): return self._color_to_int(state.board.get_board_state()) def _action_from_3D_to_1D(self, x: int, y: int, z: int): return (z * self.nrow * self.ncol) + (y * self.nrow) + x def _action_from_1D_to_3D(self, index: int): z = index // (self.nrow * self.ncol) index -= z * self.nrow * self.ncol y = index // self.nrow x = index % self.nrow return x, y, z def _reset(self): self.done = False self.board = Board(self.board_shape) self.state = SeegaState(board=self.board, next_player=self.player_color, boring_limit=self.just_stop) # self.trace = Trace( # self.state, players={-1: self.players[-1].name, 1: self.players[1].name} # ) self.current_player = self.player_color self._fill_board() def _fill_board(self): turn = self.player_color while self.state.phase == 1: self.state.set_next_player(turn) action = SeegaRules.random_play(self.state, turn) result = SeegaRules.act(self.state, action, turn) if not isinstance(result, bool): self.state, _ = result turn *= -1 def reset(self): self._reset() state = self._state_to_ndarray(self.state) return state def step(self, action): self.turn += 1 init_state = deepcopy(self.state) reward = 0.0 # Our turn self.state.set_next_player(self.player_color) if not isinstance(action, Iterable): action = self._action_from_1D_to_3D(action) *at, move = action dx = Action.get_dx(move) at = tuple(at) to = tuple(map(operator.add, at, dx)) action = SeegaAction(SeegaActionType.MOVE, at=at, to=to) result = SeegaRules.act(self.state, action, self.player_color) # Not legal move if isinstance(result, bool): reward += Reward.ILLEGAL_MOVE.value else: self.state, self.done = result # Oponent turn self.state.set_next_player(self.oponent_color) if not SeegaRules.is_player_stuck(self.state, self.oponent_color): oponent_remaining_time = self.oponent_timer.remain_time() self.oponent_timer.start() try: oponent_action = self.oponent.play(self.state, oponent_remaining_time) except Exception as e: print(e) oponent_action = None self.oponent_timer.stop() if isinstance(oponent_action, SeegaAction): oponent_result = SeegaRules.act(self.state, oponent_action, self.oponent_color) if not isinstance(oponent_result, bool): self.state, self.done = oponent_result reward += Reward.PLAYER_PART.value * ( init_state.score[self.player_color] - self.state.score[self.player_color]) reward += Reward.OPONENT_PART.value * ( init_state.score[self.oponent_color] - self.state.score[self.oponent_color]) next_state = self._state_to_ndarray(self.state) done = self.done and self.turn < self.n_turn info = dict(**SeegaRules.get_results(self.state)) return next_state, reward, self.done, info @classmethod def as_TF(cls, *args, **kwargs): from tf_agents.environments import tf_py_environment from tf_agents.environments.gym_wrapper import GymWrapper env = SeegaEnv(*args, **kwargs) suite_gym = GymWrapper(env) return tf_py_environment.TFPyEnvironment(suite_gym)
class SeegaEnv(BoardEnv): def __init__(self, board_shape, players, allowed_time, first_player=-1, boring_limit=200): # TODO: Remove player object self.players = players self.board_shape = board_shape self.allowed_time = allowed_time self.game_phases = [1, 2] self.rewarding_move = False self.done = False self.first_player = first_player self.just_stop = boring_limit self._reset() def reset(self): self._reset() def _reset(self): self.board = Board(self.board_shape, max_per_cell=1) self.phase = self.game_phases[0] self.state = SeegaState(board=self.board, next_player=self.first_player, boring_limit=self.just_stop, game_phase=self.phase) self.current_player = self.first_player def step(self, action): """Plays one step of the game. Takes an action and perform in the environment. Args: action (Action): An action containing the move from a player. Returns: bool: Dependent on the validity of the action will return True if the was was performed False if not. """ assert isinstance( action, SeegaAction), "action has to be an Action class object" result = SeegaRules.act(self.state, action, self.current_player) if isinstance(result, bool): return False else: self.state, self.done = result self.current_player = self.state.get_next_player() return True def render(self): """Gives the current state of the environnement Returns: (state, done): The state and the game status """ return self.state, self.done def get_player_info(self, player): return self.state.get_player_info(player) def get_state(self): return self.state def is_end_game(self): return self.done