This code implements a solution for finding the shortest path to collect all keys in a grid-based game. Here's an explanation of the code:
-
The
State
class represents a state in the game grid, containing the current position(x, y)
, the number of steps taken so far, and the keys collected. -
The
Solution
class contains theshortestPathAllKeys
method, which takes a grid represented as a list of strings and returns the length of the shortest path to collect all keys. -
The
directions
list represents the possible movement directions: up, down, left, and right. -
The
shortestPathAllKeys
method initializes a queue (queue
) to store the states to be explored, as well as variables for the grid dimensions (n
andm
), the starting position (start
), sets for keys (keys
) and locks (locks
), and a variable to store a bit mask representing all the keys (allKeys
). -
The method iterates over the grid to find the starting position, keys, and locks. The keys are added to the
keys
set, and the bit mask for all keys is updated accordingly. The locks are added to thelocks
set. -
The starting state is created with the starting position, zero steps, and no keys collected. It is added to the queue.
-
The method calls the
traverse
method to explore the grid and find the shortest path. It passes the grid, queue, bit mask for all keys, set of keys, and set of locks. -
The
traverse
method initializes a 3-dimensional list (visited
) to keep track of visited states. The dimensions of the list correspond to the grid dimensions and the number of possible key combinations. -
While the queue is not empty, the method dequeues a state from the front (
node
) and marks it as visited in thevisited
list. -
For each direction in the
directions
list, the method calculates the new position (newX
andnewY
) based on the current position and direction. -
If the new position is within the grid boundaries and is not a wall (
'#'
), a new state (step
) is created with the updated position and the same number of steps and keys as the current state. -
If the new position contains a key, the key is decoded and set in the
step
state by updating thekeys
variable using a bitwise OR operation. -
If the new position contains a lock, the lock is decoded and checked if the corresponding key is present in the
step
state. If not, the loop continues to the next iteration. -
If all keys have been collected (
step.keys == allKeys
), the method returns the number of steps taken in thestep
state. -
If the new position has not been visited with the same key combination, it is marked as visited, and the
step
state is added to the queue. -
If no path is
The space complexity of this code is O(n * m * 2^k), where n and m are the dimensions of the grid and k is the number of keys. This is because the visited
list has dimensions n * m * (2^k) to store the visited states. The queue can also have up to O(n * m * 2^k) states at its maximum size.
The time complexity of this code is O(n * m * 2^k), where n and m are the dimensions of the grid and k is the number of keys. This is because,
in the worst case, every cell in the grid can be visited with every possible key combination.
class State {
final int x;
final int y;
final int steps;
int keys;
State(this.x, this.y, this.steps, this.keys);
}
class Solution {
final List<dynamic> directions = [
[0, -1],
[0, 1],
[1, 0],
[-1, 0]
];
int shortestPathAllKeys(List<String> grid) {
final Queue<State> queue = Queue<State>();
final int n = grid.length;
final int m = grid[0].length;
List<int> start = [0, 0];
final Set<String> keys = Set<String>();
final Set<String> locks = Set<String>();
int allKeys = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
switch (grid[i][j]) {
case '@':
start = [i, j];
break;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
keys.add(grid[i][j]);
allKeys += 1 << (grid[i][j].codeUnitAt(0) - 'a'.codeUnitAt(0));
break;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
locks.add(grid[i][j]);
break;
}
}
}
queue.add(State(start[0], start[1], 0, 0));
return traverse(grid, queue, allKeys, keys, locks);
}
int traverse(List<String> grid, Queue<State> queue, int allKeys,
Set<String> keys, Set<String> locks) {
final int n = grid.length;
final int m = grid[0].length;
final List<List<List<int>>> visited = List.generate(n, (_) {
return List.generate(m, (_) {
return List.generate(allKeys + 1, (_) => -1);
});
});
while (queue.isNotEmpty) {
final State node = queue.removeFirst();
visited[node.x][node.y][node.keys] = node.steps;
for (final List<int> dir in directions) {
final int newX = (node.x + dir[0]);
final int newY = node.y + dir[1];
if (newX >= 0 &&
newX < n &&
newY >= 0 &&
newY < m &&
grid[newX][newY] != '#') {
final step = State(newX, newY, node.steps + 1, node.keys);
final s = grid[newX][newY];
if (keys.contains(s)) {
final decoded = 1 << (s.codeUnitAt(0) - 'a'.codeUnitAt(0));
step.keys |= decoded;
} else if (locks.contains(s)) {
final decoded = 1 << (s.codeUnitAt(0) - 'A'.codeUnitAt(0));
if ((step.keys & decoded) == 0) continue;
}
if (step.keys == allKeys) return step.steps;
if (visited[newX][newY][step.keys] == -1) {
visited[newX][newY][step.keys] = step.steps;
queue.add(step);
}
}
}
}
return -1;
}
}