def calculate_distance_field(game: Game, source: Pt, target: Pt):
    # Calculate and return a distance field from the target, over visited cells only
    sentinel = object()
    front = deque([source, sentinel])
    distfield = {source: 0}
    generation = 1
    found = False
    while front:
        p = front.popleft()
        if p == sentinel:
            if found:
                break
            assert front
            generation += 1
            front.append(sentinel)
            continue

        for d in Action.DIRS.keys():
            p2 = p + d
            if (p2 not in distfield and game.in_bounds(p2)
                    and game.is_passable(p2)):
                distfield[p2] = generation
                front.append(p2)
                if p2 == target:
                    found = True
    return distfield
def calculate_spanning_tree(game: Game, pos: Pt):
    front = deque([pos])
    visited = {pos: Treenode(pos, None)}
    found = None

    while front:
        p = front.popleft()
        pnode = visited[p]
        for d in Action.DIRS.keys():
            p2 = p + d
            if (p2 not in visited and game.in_bounds(p2)
                    and game.is_passable(p2)):
                visited[p2] = Treenode(p2, pnode)
                pnode.children.append(visited[p2])
                front.append(p2)

    visited[pos].fill_stats(game)
    return visited