Пример #1
0
def canonical_form(state):
    state = np.copy(state)
    if turn(state) == govars.WHITE:
        channels = np.arange(govars.NUM_CHNLS)
        channels[govars.BLACK] = govars.WHITE
        channels[govars.WHITE] = govars.BLACK
        state = state[channels]
        state_utils.set_turn(state)
    return state
Пример #2
0
def next_state(state, action1d, canonical=False):
    # Deep copy the state to modify
    state = np.copy(state)

    # Initialize basic variables
    board_shape = state.shape[1:]
    pass_idx = np.prod(board_shape)
    passed = action1d == pass_idx
    action2d = action1d // board_shape[0], action1d % board_shape[1]

    player = turn(state)
    previously_passed = prev_player_passed(state)
    ko_protect = None

    if passed:
        # We passed
        state[govars.PASS_CHNL] = 1
        if previously_passed:
            # Game ended
            state[govars.DONE_CHNL] = 1
    else:
        # Move was not pass
        state[govars.PASS_CHNL] = 0

        # Assert move is valid
        assert state[govars.INVD_CHNL, action2d[0],
                     action2d[1]] == 0, ("Invalid move", action2d)

        # Add piece
        state[player, action2d[0], action2d[1]] = 1

        # Get adjacent location and check whether the piece will be surrounded by opponent's piece
        adj_locs, surrounded = state_utils.adj_data(state, action2d, player)

        # Update pieces
        killed_groups = state_utils.update_pieces(state, adj_locs, player)

        # If only killed one group, and that one group was one piece, and piece set is surrounded,
        # activate ko protection
        if len(killed_groups) == 1 and surrounded:
            killed_group = killed_groups[0]
            if len(killed_group) == 1:
                ko_protect = killed_group[0]

    # Update invalid moves
    state[govars.INVD_CHNL] = state_utils.compute_invalid_moves(
        state, player, ko_protect)

    # Switch turn
    state_utils.set_turn(state)

    if canonical:
        # Set canonical form
        state = canonical_form(state)

    return state
Пример #3
0
    def get_canonical_form(state):
        """
        The returned state is a shallow copy of the given state
        :param state:
        :param player:
        :return:
        """

        player = GoGame.get_turn(state)
        if player == govars.BLACK:
            return state
        else:
            assert player == govars.WHITE
            num_channels = state.shape[0]
            channels = np.arange(num_channels)
            channels[govars.BLACK] = govars.WHITE
            channels[govars.WHITE] = govars.BLACK
            can_state = state[channels]
            state_utils.set_turn(can_state)
            return can_state
Пример #4
0
    def get_canonical_form(state):
        """
        The returned state is a seperate copy of the given state
        :param state:
        :param player:
        :return:
        """
        state = np.copy(state)

        player = GoGame.get_turn(state)
        if player == BLACK:
            return state
        else:
            assert player == WHITE
            num_channels = state.shape[0]
            channels = np.arange(num_channels)
            channels[BLACK] = WHITE
            channels[WHITE] = BLACK
            state = state[channels]
            state_utils.set_turn(state)
            return state
Пример #5
0
    def get_next_state(state, action, group_map=None, inplace=False):
        """
        Does not change the given state
        :param state:
        :param action:
        :return: The next state
        """

        # check if game is already over
        if GoGame.get_game_ended(state) != 0:
            raise Exception('Attempt to step at {} after game is over'.format(action))

        state = np.copy(state)
        single_kill = None
        empty_adjacents_before_kill = None

        if group_map is None:
            group_map = state_utils.get_all_groups(state)

        # if the current player passes
        if action == GoGame.get_action_size(state) - 1:
            # if two consecutive passes, game is over
            if GoGame.get_prev_player_passed(state):
                state_utils.set_game_ended(state)
            else:
                state_utils.set_prev_player_passed(state)

        else:
            # This move was not a pass
            state_utils.set_prev_player_passed(state, 0)

            player = state_utils.get_turn(state)
            opponent = 1 - player
            m, n = state_utils.get_board_size(state)

            # convert the move to 2d
            action = (action // m, action % n)

            # Check move is valid
            if not state_utils.is_within_bounds(state, action):
                raise Exception("{} Not Within bounds".format(action))
            elif state[INVD_CHNL, action[0], action[1]] > 0:
                raise Exception("Invalid Move", action, state)

            # Get all adjacent information
            adjacent_locations = state_utils.get_adjacent_locations(state, action)
            adj_own_groups, adj_opp_groups = state_utils.get_adjacent_groups(state, group_map, adjacent_locations, player)

            if not inplace:
                # Start new group map
                group_map = np.copy(group_map)

            # Go through opponent groups
            killed_groups = set()
            empty_adjacents_before_kill = adjacent_locations.copy()
            for group in adj_opp_groups:
                assert action in group.liberties, (action, group, state[[BLACK, WHITE]])
                empty_adjacents_before_kill.difference_update(group.locations)
                if len(group.liberties) <= 1:
                    # Killed group
                    killed_groups.add(group)

                    # Remove group in board and group map
                    for loc in group.locations:
                        group_map[loc] = None
                        state[opponent, loc[0], loc[1]] = 0

                    # Metric for ko-protection
                    if len(group.locations) <= 1:
                        if single_kill is not None:
                            single_kill = None
                        else:
                            single_kill = next(iter(group.locations))
            adj_opp_groups.difference_update(killed_groups)

            # Add the piece!
            state[player, action[0], action[1]] = 1

            # Update surviving adjacent opponent groups by removing liberties by the new action
            for opp_group in adj_opp_groups:
                assert action in opp_group.liberties, (action, opp_group, adj_opp_groups)

                if not inplace:
                    # New group copy
                    opp_group = opp_group.copy()
                    for loc in opp_group.locations:
                        group_map[loc] = opp_group

                opp_group.liberties.remove(action)

            # Update adjacent own groups that are merged with the action
            if len(adj_own_groups) > 0:
                merged_group = adj_own_groups.pop()
                if not inplace:
                    merged_group = merged_group.copy()
                    for loc in merged_group.locations:
                        group_map[loc] = merged_group
            else:
                merged_group = Group()

            # Locations from action and adjacent groups
            merged_group.locations.add(action)
            group_map[action] = merged_group

            for own_group in adj_own_groups:
                for loc in own_group.locations:
                    group_map[loc] = merged_group
                    merged_group.locations.add(loc)
                merged_group.liberties.update(own_group.liberties)

            # Liberties from action
            for adj_loc in adjacent_locations:
                if np.count_nonzero(state[[BLACK, WHITE], adj_loc[0], adj_loc[1]]) == 0:
                    merged_group.liberties.add(adj_loc)

            if action in merged_group.liberties:
                merged_group.liberties.remove(action)

            # More work to do if we killed
            if len(killed_groups) > 0:
                killed_map = np.zeros(state.shape[1:])
                for group in killed_groups:
                    for loc in group.locations:
                        killed_map[loc] = 1
                # Update own groups adjacent to opponent groups that we just killed
                killed_liberties = ndimage.binary_dilation(killed_map)
                affected_group_matrix = state[player] * killed_liberties
                groups_to_update = set(group_map[np.nonzero(affected_group_matrix)])
                all_pieces = np.sum(state[[BLACK, WHITE]], axis=0)
                empties = (1 - all_pieces)
                for group in groups_to_update:
                    group_matrix = group_map == group
                    additional_liberties = ndimage.binary_dilation(group_matrix) * empties * killed_map
                    additional_liberties = np.argwhere(additional_liberties)

                    if not inplace:
                        group = group.copy()
                        for loc in group.locations:
                            group_map[loc] = group

                    for liberty in additional_liberties:
                        group.liberties.add(tuple(liberty))

        # Update illegal moves
        state_utils.set_invalid_moves(state, group_map)

        # If group was one piece, and location is surrounded by opponents,
        # activate ko protection
        if single_kill is not None and len(empty_adjacents_before_kill) <= 0:
            state[INVD_CHNL, single_kill[0], single_kill[1]] = 1

        # Switch turn
        state_utils.set_turn(state)

        return state, group_map
Пример #6
0
 def get_init_board(size, black_first=True):
     # return initial board (numpy board)
     state = np.zeros((6, size, size))
     if not black_first:
         state_utils.set_turn(state)
     return state
Пример #7
0
    def get_next_state(state, action):
        """
        Does not change the given state
        :param state:
        :param action:
        :return: The next state
        """

        # check if game is already over
        if GoGame.get_game_ended(state) != 0:
            raise Exception(
                'Attempt to step at {} after game is over'.format(action))

        state = np.copy(state)

        # if the current player passes
        if action == GoGame.get_action_size(state) - 1:
            # if two consecutive passes, game is over
            if GoGame.get_prev_player_passed(state):
                state_utils.set_game_ended(state)
            else:
                state_utils.set_prev_player_passed(state)

            # Update invalid channel
            state_utils.reset_invalid_moves(state)
            state_utils.add_invalid_moves(state)

            # Switch turn
            state_utils.set_turn(state)

            # Return event
            return state

        player = state_utils.get_turn(state)
        m, n = state_utils.get_board_size(state)

        # convert the move to 2d
        action = (action // m, action % n)

        # Check move is valid
        if not state_utils.is_within_bounds(state, action):
            raise Exception("{} Not Within bounds".format(action))
        elif state[INVD_CHNL][action] > 0:
            raise Exception("Invalid Move", action, state)

        state_utils.reset_invalid_moves(state)

        # Get all adjacent groups
        _, opponent_groups = state_utils.get_adjacent_groups(state, action)

        # Go through opponent groups
        killed_single_piece = None
        empty_adjacents_before_kill = state_utils.get_adjacent_locations(
            state, action)
        for group in opponent_groups:
            empty_adjacents_before_kill = empty_adjacents_before_kill - group.locations
            if len(group.liberties) <= 1:
                assert action in group.liberties

                # Remove group in board
                for loc in group.locations:
                    # TODO: Hardcoded other player. Make more generic
                    state[1 - player][loc] = 0

                # Metric for ko-protection
                if len(group.locations) <= 1:
                    if killed_single_piece is not None:
                        killed_single_piece = None
                    else:
                        killed_single_piece = group.locations.pop()

        # If group was one piece, and location is surrounded by opponents,
        # activate ko protection
        if killed_single_piece is not None and len(
                empty_adjacents_before_kill) <= 0:
            state[INVD_CHNL][killed_single_piece] = 1

        # Add the piece!
        state[player][action] = 1

        # Update illegal moves
        state_utils.add_invalid_moves(state)

        # This move was not a pass
        state_utils.set_prev_player_passed(state, 0)

        # Switch turn
        state_utils.set_turn(state)

        return state