Find a path: Depth first search
Got stuck on a question about computing possible moves across a one dimensional array.
Given
A game representing an array of integers. Here is an example game board, which is kept short for simplicity
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
value | 3 | 2 | 0 | 1 | 3 | 1 | 2 | 0 | 0 |
The point of the game is to reach the final index in the array; this is the winning condition. If you reach a zero that is not the final position, you have lost. Not all game boards are winnable.
The game starts at index 0. You can move to a new index within the range of the current index, plus the current value. For example, from index 0 in the example, you may move forward 0, 1, 2, or 3 spaces
Implement a function that will determine if a given game board has a winnable path
General idea is start at the beginning and compute the maximum amount of distance you can move and then move there. If it works then continue if not go back one step and decrement distance by 1 and try again. Repeat till you have reached the end or get stuck.
Initial pass tried to do a while loop to track the changes, but this approach was hard to keep track of and I didn't finish in time.
Thought about it a bit more and it's a search a depth first search to be specific. Therefore if I need to keep the possible next steps as a stack of choices and pop them off as needed.
Check for the end conditions
- Am I at the end node
- Am I at a dead node value of index is
0
- Is the stack empty
Now the solution is this. Keep track of the nodes visited as a set and also the dead nodes as another set. Subtract the sets for the path
from collections import deque
from icecream import ic
def find_winning_path(moves: list[int]) -> set:
current_stack = deque([0])
visited_nodes = set()
dead_nodes = set()
while current_stack:
index = current_stack.pop()
if index in visited_nodes:
continue
visited_nodes.add(index)
if index == len(moves) - 1:
return visited_nodes - dead_nodes
if moves[index] == 0:
dead_nodes.add(index)
continue
for move in range(1, moves[index] + 1):
next_index = index + move
if next_index < len(moves):
current_stack.append(next_index)
return visited_nodes - dead_nodes
if __name__ == "__main__":
moves = [3, 2, 0, 1, 3, 1, 2, 0, 0]
winning_node = len(moves) - 1
if winning_node in ic(find_winning_path(moves)):
ic('Has a winning path')
else:
ic('No winning path')