|
| 1 | +from random import choice |
| 2 | + |
| 3 | +from typing import cast, Optional # noqa: F401 |
| 4 | + |
| 5 | +from base.grid import Grid |
| 6 | +from base.cell import Cell # noqa: F401 |
| 7 | + |
| 8 | +""" |
| 9 | +Hunt-and-Kill algorithm picks a random starting cell and randomly walks. It cannot walk on an already visited cell, and |
| 10 | +if finds at a dead-end (no more unvisited cells around current one), "hunts" from the northwest corner the first cell |
| 11 | +that is unvisted and has at least one visited neighbor; then starts walking again. |
| 12 | +""" |
| 13 | + |
| 14 | + |
| 15 | +class HuntAndKill: |
| 16 | + |
| 17 | + @staticmethod |
| 18 | + def on(grid: Grid) -> Grid: |
| 19 | + current_cell = grid.random_cell() # type: Optional[Cell] |
| 20 | + |
| 21 | + while current_cell is not None: |
| 22 | + unvisited_neighbors = \ |
| 23 | + [neighbor for neighbor in current_cell.neighbors if len(neighbor.links) == 0] # type: ignore |
| 24 | + |
| 25 | + if len(unvisited_neighbors) > 0: |
| 26 | + # as long as there are unvisited paths, walk them |
| 27 | + neighbor = cast(Cell, choice(unvisited_neighbors)) |
| 28 | + current_cell.link(neighbor) |
| 29 | + current_cell = neighbor |
| 30 | + else: |
| 31 | + # enter hunt mode, find first unvisited cell near any visited cell |
| 32 | + current_cell = None |
| 33 | + for cell in grid.each_cell(): |
| 34 | + visited_neighbors = [neighbor for neighbor in cell.neighbors if len(neighbor.links) > 0] |
| 35 | + if len(cell.links) == 0 and len(visited_neighbors) > 0: |
| 36 | + current_cell = cast(Cell, cell) |
| 37 | + neighbor = choice(visited_neighbors) |
| 38 | + current_cell.link(neighbor) |
| 39 | + break |
| 40 | + |
| 41 | + return grid |
0 commit comments