Esempio n. 1
0
def find_chain(pawn, black_pawns, available_camps, camps_found=0, chain=set()):
    '''
    Find a chain of black pawns connecting two or more camps groups,
    starting from the given coordinates
    '''
    neighbors = TablutBoard.unique_full_k_neighbors(pawn, k=1)
    if not available_camps.isdisjoint(neighbors):
        chain.add(pawn)
        camps = available_camps.intersection(neighbors)
        camp = utils.get_rand(camps)
        camps.update(TablutBoard.unique_full_k_neighbors(camp, k=1),
                     TablutBoard.unique_full_k_neighbors(camp, k=2))
        available_camps.difference_update(camps)
        camps_found += 1
    good_neighbors = black_pawns.intersection(neighbors)
    new_camps_found = camps_found
    for neighbor in good_neighbors:
        if neighbor in black_pawns:
            black_pawns.remove(neighbor)
            chain, new_camps_found, _ = find_chain(neighbor, black_pawns,
                                                   available_camps,
                                                   new_camps_found, chain)
            if new_camps_found > camps_found:
                chain.add(pawn)
    return chain, new_camps_found, black_pawns
Esempio n. 2
0
def get_pawns(state, king=False):
    '''
    Return white and black pawns, with or without considering the king
    '''
    white_pawns = (TablutBoard.player_pawns(state.pawns, TPlayerType.WHITE)
                   if king else state.pawns[TPawnType.WHITE])
    return white_pawns, TablutBoard.player_pawns(state.pawns,
                                                 TPlayerType.BLACK)
Esempio n. 3
0
 def count_dead(moves, potential_killers, potential_victims):
     count = 0
     for _, to_move in moves:
         killables = TablutBoard.orthogonal_k_neighbors(to_move, k=1)
         killers = TablutBoard.orthogonal_k_neighbors(to_move, k=2)
         for victim, killer in zip(killables, killers):
             if victim in potential_victims and killer in potential_killers:
                 count += 1
     return count
Esempio n. 4
0
 def _compute_utility(self, pawns, player):
     '''
     Compute utility value for the given player, with the given pawns
     '''
     return (0 if not self._goal_state(pawns) else 1 if (
         (player == TablutPlayerType.WHITE and
          TablutBoard.king_position(pawns) in TablutBoard.WHITE_GOALS) or
         (player == TablutPlayerType.BLACK
          and TablutBoard.king_position(pawns) is None)) else -1)
Esempio n. 5
0
def compute_reachable_goals(state):
    '''
    Compute the goals that the king can reach
    '''
    king = TablutBoard.king_position(state.pawns)
    reachable_goals = set()
    for goal in TablutBoard.WHITE_GOALS:
        if TablutBoard.dfs(state.pawns, king, goal):
            reachable_goals.add(goal)
    return reachable_goals
Esempio n. 6
0
def blocked_chain_pawns(state, chain):
    '''
    Return the number of white pawns, black pawns and corners
    blocked from a chain of black pawns
    '''
    white_pawns, black_pawns = get_pawns(state, king=True)
    near_corners = find_near_corners(chain)
    whites_found = 0
    blacks_found = 0
    king_found = False
    for corner in near_corners:
        corner_whites = 0
        corner_blacks = 0
        neighbor = corner
        neighbors = TablutBoard.unique_orthogonal_k_neighbors(neighbor, k=1)
        visited_neighbors = set()
        while len(neighbors) > 0:
            visited_neighbors.add(neighbor)
            if neighbor not in chain:
                if neighbor in white_pawns:
                    if neighbor == TablutBoard.king_position(state.pawns):
                        king_found = True
                    corner_whites += 1
                elif neighbor in black_pawns:
                    corner_blacks += 1
                current_neighbors = TablutBoard.unique_orthogonal_k_neighbors(
                    neighbor, k=1)
                neighbors.update(
                    current_neighbors.difference(visited_neighbors,
                                                 TablutBoard.CAMPS))
            neighbor = neighbors.pop()
        if king_found:
            return corner_whites, corner_blacks, 0
        whites_found += corner_whites
        blacks_found += corner_blacks

    if len(near_corners) > 1:
        camps = set()
        for a_corner in near_corners:
            for b_corner in near_corners:
                if a_corner != b_corner:
                    camp = a_corner.middle_position(b_corner)
                    if camp is not None:
                        camps.add(camp)
                        camps.update(
                            TablutBoard.unique_orthogonal_k_neighbors(camp,
                                                                      k=1))
        for camp in camps:
            if camp in black_pawns:
                blacks_found += 1

    return whites_found, blacks_found, len(near_corners)
Esempio n. 7
0
def black_survival(state):
    '''
    Return a move that blocks white player winning situation
    '''
    king_moves = TablutBoard.legal_moves(
        state.pawns, TablutBoard.king_position(state.pawns))
    for white_position in TablutBoard.WHITE_GOALS:
        for king_to_move in king_moves:
            if white_position == king_to_move:
                for black_from_move, black_to_move in state.moves:
                    if king_to_move == black_to_move:
                        return (black_from_move, black_to_move)
    return None
Esempio n. 8
0
def compute_goals_distances(state):
    '''
    Compute king distances to goals
    '''
    king = TablutBoard.king_position(state.pawns)
    goals_distances = {}
    for goal in TablutBoard.WHITE_GOALS:
        goals_distances[goal] = TablutBoard.simulate_distance(
            state.pawns,
            king,
            goal,
            max_moves=MAX_KING_MOVES_GOALS,
            unwanted_positions=TablutBoard.WHITE_GOALS)
    return goals_distances
Esempio n. 9
0
def pawns_in_corners(state):
    '''
    Return a value representing the number of player and enemy pawns
    in the extreme corners, in range [-1, 1]
    '''
    value = 0.0
    player_pawns = TablutBoard.player_pawns(state.pawns,
                                            gutils.other_player(state.to_move))
    enemy_pawns = TablutBoard.player_pawns(state.pawns, state.to_move)
    for corner in CORNERS:
        if corner in player_pawns:
            value -= 1 / 20
        elif corner in enemy_pawns:
            value += 1 / 30
    return value
Esempio n. 10
0
 def will_king_be_dead(self, state):
     '''
     Check if the king will be dead in the next possible states
     '''
     return any([
         TablutBoard.king_position(new_state.pawns) is None
         for new_state in self.next_states(state)
     ])
Esempio n. 11
0
def king_killers(state):
    '''
    Return a value representing the number of black pawns,
    camps and castle around the king, in range [-1, 1]
    '''
    _, black_moves = get_moves(state)
    free_positions = []
    killer_positions = []
    killers, free_positions, killer_positions = (
        TablutBoard.potential_king_killers(state.pawns))
    possible_killers_count = _reachable_positions(killer_positions,
                                                  black_moves)
    occupable_free_positions = _reachable_positions(free_positions,
                                                    black_moves)
    white_neighbors = (4 -
                       (killers + len(free_positions) + len(killer_positions)))
    value = 0.0
    values = [killers, occupable_free_positions, possible_killers_count]
    weights = [0, 1 / 32, 0]
    if (TablutBoard.is_king_in_castle(state.pawns)
            or TablutBoard.is_king_near_castle(state.pawns)):
        if killers >= 3:
            value = 0.7
            if possible_killers_count != 0:
                value = 0.9
        elif killers == 2:
            weights = [1 / 6, 1 / 10, 1 / 10]
        elif killers == 1:
            weights = [1 / 8, 1 / 25, 1 / 10]
    else:
        if killers >= 1 and possible_killers_count != 0:
            value = 0.9
        elif killers >= 3:
            value = 0.7
        elif killers == 2:
            weights = [1 / 4, 1 / 10, 0]
        elif killers == 1:
            weights = [1 / 3, 1 / 10, 0]
    if value == 0.0:
        value = -white_neighbors * (3 / 40)
        for val, weight in zip(values, weights):
            value += (val * weight)
    return heuristic_pov(state, TPlayerType.BLACK, value)
Esempio n. 12
0
def compute_reachable_corners(pawn, pawns):
    '''
    Compute pawn distances to goals
    '''
    reachable_corners = {corner: False for corner in CORNERS}
    for corner in reachable_corners:
        if corner not in pawns[TPawnType.BLACK]:
            pawns[TPawnType.WHITE].discard(corner)
            reachable_corners[corner] = TablutBoard.dfs(pawns, pawn, corner)
    return reachable_corners
Esempio n. 13
0
 def player_moves(cls, pawns, player_type):
     '''
     Return a list of tuples of coordinates representing every possibile
     new position for each pawn of the given player
     '''
     moves = []
     pawn_types = gutils.from_player_to_pawn_types(player_type)
     for pawn_type in pawn_types:
         for pawn in pawns[pawn_type]:
             moves.extend(TablutBoard.moves(pawns, pawn))
     return moves
Esempio n. 14
0
def white_barriers(state):
    '''
    Return a value representing the number of corners reachable by the king
    and not by the black pawns, in range [-1, 1]
    '''
    value = 0.0
    king = TablutBoard.king_position(state.pawns)
    tmp_pawns = gutils.clone_pawns(state.pawns)
    tmp_pawns[TPawnType.WHITE].difference_update(CORNERS)
    reachable_corners = compute_reachable_corners(king, state.pawns)
    for corner, king_reach in reachable_corners.items():
        barrier = True
        if king_reach:
            for black_pawn in tmp_pawns[TPawnType.BLACK]:
                black_reach = TablutBoard.dfs(tmp_pawns, black_pawn, corner)
                if black_reach:
                    barrier = False
                    break
            if barrier:
                value = 0.99
                break
    return heuristic_pov(state, TPlayerType.WHITE, value)
Esempio n. 15
0
 def order_moves(state, initial_moves=None, depth=None):
     if initial_moves is None:
         initial_moves = list(state.moves)
     beam = len(initial_moves)
     if depth is None or depth % 2 != 0:
         beam = int(beam / 2)
     best_move = initial_moves[0]
     best_moves = initial_moves[1:beam]
     near_king_moves, best_moves = TablutBoard.near_king_moves(
         state.pawns, initial_moves, best_moves)
     if best_move in near_king_moves:
         near_king_moves.remove(best_move)
     return [best_move] + near_king_moves + best_moves
Esempio n. 16
0
def useful_chain(state, chain):
    '''
    Return if the given chain is useful in the sense that the king
    could reach the examined corner before the chain was present,
    and now it is blocked
    '''
    king = TablutBoard.king_position(state.pawns)
    tmp_pawns = gutils.clone_pawns(state.pawns)
    tmp_pawns[TPawnType.BLACK].difference_update(chain)
    reachable_corners = compute_reachable_corners(king, state.pawns)
    tmp_reachable_corners = compute_reachable_corners(king, tmp_pawns)
    for corner in CORNERS:
        if not reachable_corners[corner] and tmp_reachable_corners[corner]:
            return True
    return False
Esempio n. 17
0
 def result(self, state, move, compute_moves=True):
     '''
     Return the next state with the given move and
     compute the new state moves, if specified
     '''
     pawns = TablutBoard.move(state.pawns, state.to_move, move)
     to_move = gutils.other_player(state.to_move)
     res = TablutGameState(to_move=to_move,
                           utility=self._compute_utility(
                               pawns, state.to_move),
                           is_terminal=True,
                           pawns=pawns,
                           moves=[],
                           old_state=state)
     if not self.terminal_test(res):
         res.is_terminal = False
         if compute_moves:
             res.moves = self.player_moves(pawns, to_move)
     return res
Esempio n. 18
0
def blocked_goals(state):
    '''
    Return a value representing the number of blocked white goals
    for each corner, in range [-1, 1]
    '''
    value = 0.0
    white_pawns, black_pawns = get_pawns(state, king=False)
    free_goals = compute_reachable_goals(state)
    for pos in TablutBoard.OUTER_CORNERS:
        if pos in black_pawns:
            value -= (1 / 9)
            free_goals.difference_update(
                TablutBoard.unique_orthogonal_k_neighbors(pos))
        elif pos in white_pawns:
            value -= (1 / 16)

    for goal in free_goals:
        if goal in black_pawns:
            value -= (1 / 17)
        elif goal in white_pawns:
            value -= (1 / 20)

    return heuristic_pov(state, TPlayerType.WHITE, value)
Esempio n. 19
0
 def _goal_state(self, pawns):
     '''
     A state is a goal state if either the white or the black player wins
     '''
     return (TablutBoard.king_position(pawns) is None
             or TablutBoard.king_position(pawns) in TablutBoard.WHITE_GOALS)
Esempio n. 20
0
 def will_king_be_dead_by_move(self, state, move):
     '''
     Check if the king will be dead by applying the given move
     '''
     new_state = self.result(state, move)
     return TablutBoard.king_position(new_state.pawns) is None