def traverse_tiles(self, x, y, should_visit, visited=set()): """Traverse all selected tiles starting from a given tile. A given method is used to determine which of the surrounding tiles will be visited next during traversal. Traversal ends when none of the surrounding tiles have been selected to be visited next. Parameters: x: X coord of starting tile y: Y coord of starting tile should_visit: function which accepts (x, y, field) Returns a boolean of whether given tile should be visited. visited: Already visited tiles; used for recursion. Returns: A list of all tiles visited during traversal. """ # This implementation uses DFS traversal. visited.add((x, y)) all_surrounding = utility.surrounding_tiles(x, y, True) tiles_to_visit = [(x, y) for (x, y) in all_surrounding if should_visit(x, y, self)] tiles_to_visit = [t for t in tiles_to_visit if t not in visited] # Tiles that lay underneath this level of the "tree" tiles_below = {(x, y)} for (adj_x, adj_y) in tiles_to_visit: tiles_below_adj = self.traverse_tiles(adj_x, adj_y, should_visit, visited) tiles_below.update(tiles_below_adj) return tiles_below
def hint_for_tile(tile_x, tile_y, mines): """Return the hint for the given tile. Parameters: tile_x: X coord of tile tile_y: Y coord of tile mines (list of two-tuples): list of mine coords Returns: Number of mines in surrounding tiles (hint) for the given tile, or -1 if tile being checked has a mine. """ if (tile_x, tile_y) in mines: return -1 surrounding_tiles = utility.surrounding_tiles(tile_x, tile_y) # No need to worry about edge cases caused by -ve tile coords in # surrounding_tiles as the mines list simply won't have the -ve # coords and those coords will register as False, as desired surrounding_tiles_have_mine = [(x, y) in mines for (x, y) in surrounding_tiles] return surrounding_tiles_have_mine.count(True)
def _open_adjacent_zero_hint_tiles(self, x, y): def should_visit(x, y, field): return field.hints.get((x, y)) == 0 adj_zero_hint_tiles = self.traverse_tiles(x, y, should_visit) # We've found zero-hint tiles above. These zero-hint tiles are arranged # contiguously on the minefield and form an area. Lastly, we need to # also open the tiles surrounding the tiles on the edge of this area. # Instead of finding the edge tiles, we can find and open the # surrounding tiles of all tiles within the area to have the same effect. all_surrounding_tiles = set() for (x, y) in adj_zero_hint_tiles: all_surrounding_tiles.update(utility.surrounding_tiles(x, y, True)) valid_surrounding_tiles = {(x, y) for (x, y) in all_surrounding_tiles if self.are_coords_valid(x, y)} self.open_coords.update(adj_zero_hint_tiles) self.open_coords.update(valid_surrounding_tiles)
def nine_tiles(self, middle_x, middle_y): nine_tiles = utility.surrounding_tiles(middle_x, middle_y, True) + [(middle_x, middle_y)] return {(x, y): self.tile(x, y) for (x, y) in nine_tiles}
def test_surrounding_tiles(self): actual = utility.surrounding_tiles(4, 2) expected = [(3, 3), (4, 3), (5, 3), (3, 2), (5, 2), (3, 1), (4, 1), (5, 1)] self.assertCountEqual(actual, expected)
def test_surrounding_tiles_remove_outside_tiles(self): actual = utility.surrounding_tiles(0, 1, True) expected = [(0, 0), (0, 2), (1, 0), (1, 1), (1, 2)] self.assertCountEqual(actual, expected)