Exemplo n.º 1
0
def _verify_find_matches_with_stop_after(board, expected, stop_after):
    matches = find_matches(board, stop_after=stop_after)
    eq_(stop_after, len(matches))
    for match in matches:
        # we can't do a simple in, since we're preventing combining by doing a
        # stop_after.
        ok_(any(m.contains_match(match) for m in expected))
Exemplo n.º 2
0
def _ap(from_sq, to_sq, matches, colors, board):
    """
    Return a list, the same length as `colors`, with each element being the
    number of ap in that color earned by `match`.
    """
    ap = [0] * len(colors)

    # later, do prob. ev of tiles that fall

    board = board.copy()
    board.swap(from_sq[0], from_sq[1], to_sq[0], to_sq[1])

    while find_matches(board):
        new_board, destroyed_sqs = destroy_tiles(board)
        for s in destroyed_sqs:
            sq_ap = board.at(s[0], s[1]).ap()
            if sq_ap and sq_ap[0] in colors:
                ap[colors.index(sq_ap[0])] += sq_ap[1]
        for match in matches:
            crit = calc_critical_square(match)
            if crit:
                new_board.set_at(crit[0], crit[1], CriticalTile())
        board, _ = apply_gravity(new_board)

    return ap
Exemplo n.º 3
0
def _ap(from_sq, to_sq, matches, colors, board):
    """
    Return a list, the same length as `colors`, with each element being the
    number of ap in that color earned by `match`.
    """
    ap = [0] * len(colors)

    # later, do prob. ev of tiles that fall

    board = board.copy()
    board.swap(from_sq[0], from_sq[1], to_sq[0], to_sq[1])

    while find_matches(board):
        new_board, destroyed_sqs = destroy_tiles(board)
        for s in destroyed_sqs:
            sq_ap = board.at(s[0], s[1]).ap()
            if sq_ap and sq_ap[0] in colors:
                ap[colors.index(sq_ap[0])] += sq_ap[1]
        for match in matches:
            crit = calc_critical_square(match)
            if crit:
                new_board.set_at(crit[0], crit[1], CriticalTile())
        board, _ = apply_gravity(new_board)

    return ap
Exemplo n.º 4
0
def _verify_rand_stable_board(board):
    eq_([], find_matches(board))
    ok_(find_moves(board))

    for row, col in board.squares_from_bottom_right():
        tile = board.at(row, col)
        ok_(isinstance(tile, (ColoredTile, TeamupTile)))
Exemplo n.º 5
0
def _verify_find_matches_with_stop_after(board, expected, stop_after):
    matches = find_matches(board, stop_after=stop_after)
    eq_(stop_after, len(matches))
    for match in matches:
        # we can't do a simple in, since we're preventing combining by doing a
        # stop_after.
        ok_(any(m.contains_match(match) for m in expected))
Exemplo n.º 6
0
def destroy_tiles(board):
    """
    Return a copy of `board` with matched tiles (and rows / cols with 4+
    matches) destroyed.

    Does not modify `board` (which is important so that the original board,
    along with the returned list of destroyed tiles, can be used to figure out
    AP, traps, etc.)

    Note that this function will have no effect if there are no matches on the
    board.  It's up to other code to e.g. enforce that a move creates at least
    one match.

    Returns:

      - a new copy of the board with EmptyTiles in place of destroyed tiles

      - a sorted list of the squares (as (row, col) tuples) that were replaced
        with empty tiles
    """
    new_board = board.copy()
    matches = find_matches(new_board)

    destroyed = set()

    for match in matches:
        for (row, col) in match.squares:
            new_board.set_at(row, col, EmptyTile())
            destroyed.add((row, col))

        extents = match.max_extents

        for (row, col) in _destroy_rows(new_board, extents['rows']):
            new_board.set_at(row, col, EmptyTile())
            destroyed.add((row, col))

        for (row, col) in _destroy_cols(new_board, extents['cols']):
            new_board.set_at(row, col, EmptyTile())
            destroyed.add((row, col))

    return new_board, sorted(list(destroyed))
Exemplo n.º 7
0
def destroy_tiles(board):
    """
    Return a copy of `board` with matched tiles (and rows / cols with 4+
    matches) destroyed.

    Does not modify `board` (which is important so that the original board,
    along with the returned list of destroyed tiles, can be used to figure out
    AP, traps, etc.)

    Note that this function will have no effect if there are no matches on the
    board.  It's up to other code to e.g. enforce that a move creates at least
    one match.

    Returns:

      - a new copy of the board with EmptyTiles in place of destroyed tiles

      - a sorted list of the squares (as (row, col) tuples) that were replaced
        with empty tiles
    """
    new_board = board.copy()
    matches = find_matches(new_board)

    destroyed = set()

    for match in matches:
        for (row, col) in match.squares:
            new_board.set_at(row, col, EmptyTile())
            destroyed.add((row, col))

        extents = match.max_extents

        for (row, col) in _destroy_rows(new_board, extents['rows']):
            new_board.set_at(row, col, EmptyTile())
            destroyed.add((row, col))

        for (row, col) in _destroy_cols(new_board, extents['cols']):
            new_board.set_at(row, col, EmptyTile())
            destroyed.add((row, col))

    return new_board, sorted(list(destroyed))
Exemplo n.º 8
0
def settle_board(board):
    """
    Useful to just get the board to a settled state, not caring about what
    happens in between (details of which tiles were destroyed etc.)

    Returns the stable board.
    """
    while True:
        matches = find_matches(board)

        if not matches:
            break

        new_board, destroyed_sqs = destroy_tiles(board)
        for match in matches:
            crit = calc_critical_square(match)
            if crit:
                new_board.set_at(crit[0], crit[1], CriticalTile())
        board, _ = apply_gravity(new_board)

    return board
Exemplo n.º 9
0
    def move(self):
        self.move_count += 1

        matched_five = False
        to_swap = self.to_move.pick_move(self._game_state())

        if to_swap:
            self._apply_swap(to_swap)

            while True:
                matches = find_matches(self.board)
                if not matches:
                    break
                matched_five = matched_five or _has_five_match(matches)
                self._destroy_tiles()
                self._place_criticals(matches)
                self._apply_gravity()
                self._fill_empty_squares()

        if not matched_five:
            self.to_move = next(self.players)
            if self.to_move == self.offense:
                self.turn_count += 1
Exemplo n.º 10
0
    def move(self):
        self.move_count += 1

        matched_five = False
        to_swap = self.to_move.pick_move(self._game_state())

        if to_swap:
            self._apply_swap(to_swap)

            while True:
                matches = find_matches(self.board)
                if not matches:
                    break
                matched_five = matched_five or _has_five_match(matches)
                self._destroy_tiles()
                self._place_criticals(matches)
                self._apply_gravity()
                self._fill_empty_squares()

        if not matched_five:
            self.to_move = next(self.players)
            if self.to_move == self.offense:
                self.turn_count += 1
Exemplo n.º 11
0
def find_moves(board, stop_after=None):
    """
    Return all legal swap moves on the board as a sorted list of
    MoveWithMatches.

    Note that normally for each move from one square to the other, there will
    be a corresponding reverse move, as tiles can be swapped with either one
    being the 'touched' tile (by convention, that being the first listed in the
    tuple).  This is not always the case if passing `stop_after.`

    If `stop_after` is supplied, stop after that many moves are found.
    """
    cached = board_aware_cache.get('find_moves', board, stop_after)
    if cached:
        return cached

    moves_with_matches = []

    for (row, col) in board.squares_from_bottom_right():
        for row_n, col_n in neighbors(row, col, board.side):
            nb = board.copy()
            nb.swap(row, col, row_n, col_n)
            matches = find_matches(nb)
            if matches:
                moves_with_matches.append(
                    MoveWithMatches(from_sq=sq(row, col),
                                    to_sq=sq(row_n, col_n),
                                    matches=matches))
                if stop_after and len(moves_with_matches) >= stop_after:
                    sorted_moves_with_matches = sorted(moves_with_matches)
                    board_aware_cache.set('find_moves', board, stop_after,
                                          sorted_moves_with_matches)
                    return sorted_moves_with_matches

    sorted_moves_with_matches = sorted(moves_with_matches)
    board_aware_cache.set('find_moves', board, None, sorted_moves_with_matches)
    return sorted_moves_with_matches
Exemplo n.º 12
0
def find_moves(board, stop_after=None):
    """
    Return all legal swap moves on the board as a sorted list of
    MoveWithMatches.

    Note that normally for each move from one square to the other, there will
    be a corresponding reverse move, as tiles can be swapped with either one
    being the 'touched' tile (by convention, that being the first listed in the
    tuple).  This is not always the case if passing `stop_after.`

    If `stop_after` is supplied, stop after that many moves are found.
    """
    cached = board_aware_cache.get('find_moves', board, stop_after)
    if cached:
        return cached

    moves_with_matches = []

    for (row, col) in board.squares_from_bottom_right():
        for row_n, col_n in neighbors(row, col, board.side):
            nb = board.copy()
            nb.swap(row, col, row_n, col_n)
            matches = find_matches(nb)
            if matches:
                moves_with_matches.append(
                    MoveWithMatches(from_sq=sq(row, col),
                                    to_sq=sq(row_n, col_n),
                                    matches=matches))
                if stop_after and len(moves_with_matches) >= stop_after:
                    sorted_moves_with_matches = sorted(moves_with_matches)
                    board_aware_cache.set('find_moves', board, stop_after,
                                          sorted_moves_with_matches)
                    return sorted_moves_with_matches

    sorted_moves_with_matches = sorted(moves_with_matches)
    board_aware_cache.set('find_moves', board, None, sorted_moves_with_matches)
    return sorted_moves_with_matches
Exemplo n.º 13
0
 def _ensure_playable_board(self):
     while not (find_moves(self.board, stop_after=1)
                and not find_matches(self.board, stop_after=1)):
         self._shuffle_board()
Exemplo n.º 14
0
def _verify_find_matches(board, expected):
    eq_(sorted(expected), find_matches(board))
Exemplo n.º 15
0
 def _ensure_playable_board(self):
     while not (find_moves(self.board, stop_after=1)
                and not find_matches(self.board, stop_after=1)):
         self._shuffle_board()
Exemplo n.º 16
0
def _verify_find_matches(board, expected):
    eq_(sorted(expected), find_matches(board))