Find the minimum number of die rolls necessary to reach the final cell of the given Snakes and Ladders board game.
Rules are as usual. Player starts from cell one, rolls a die and advances 1-6 (a random number of) steps at a time. Should they land on a cell where a ladder starts, the player immediately climbs up that ladder. Similarly, having landed on a cell with a snake’s mouth, the player goes down to the tail of that snake before they roll the die again. Game ends when the player arrives at the last cell.
Input: A board with 20 cells, two ladders 2->19 and 12->15 and a snake 9->2.
The two-dimensional view is for our visual convenience only: there are really just 20 cells, one after another, linearly. See below in the Notes how such a board is represented in the Input Parameters.
Having started from cell 1, player rolls 1 and moves to cell 2. The stair takes them from cell 2 to cell 19. They then roll 1 to arrive at the last, 20th cell. The player reached the end of the board in two rolls; that’s the fewest rolls possible.
Input: A board with eight cells, no snakes and no ladders:
There are several ways to reach the last cell from the first cell in two rolls: 6+1, 5+2, 4+3, 3+4, 2+5, 1+6. No way to reach it with any fewer rolls though.
Input Parameters: Function has two arguments:
1. n, size of the board, and
2. moves, array of integers defining the snakes and ladders:
● moves[i] = -1: no ladder or snake starts at i-th cell
● moves[i] < i: snake from i down to moves[i]
● moves[i] > i: ladder from i up to moves[i]
The indices and values in moves array are zero-based, for example moves=18 means there is a ladder from cell 2 up to cell 19. moves for “Example One” above looks like this:
[-1, 18, -1, -1, -1, -1, -1, -1, 2, -1, -1, 15, -1, -1, -1, -1, -1, -1, -1, -1]
Output: Function must return an integer, the minimum number of dice rolls required to reach the last cell from the first. Return -1 if the last cell cannot be reached.
● No snake starts from the last cell and no ladder starts from the first cell.
No snake or ladder starts from a cell where another snake or ladder arrives.
Optimal solution using BFS
Consider the entire board as a graph. All cells are nodes and there is an edge from every cell to the next 6 cells on the board, as there are 6 numbers on a dice. Whenever there is a snake or a ladder, we go to its respective ends with no cost instead of staying at its beginning. For instance, when we are at cell 24 and we roll 3 to reach cell 27, we would check if a snake or a ladder starts from cell 27: if there is, our graph would not have an edge from cell 24 to 27, but instead from 24 to the end of that snake or ladder.
We need to find the minimum distance (as measured by the number of edges) to the end cell from the start cell in the graph built like so. We can run a simple breadth first search (BFS) since we just need to count edges and don’t need to account for their length or weight. Note that we don't need to build entire graph upfront: to be more efficient the provided solution creates Node objects only as it visits cells. Once it reaches the last cell, the algorithm returns without necessarily building the entire graph of possible paths. Note that the algorithm ignores any paths to a particular node except the one that was found first. That’s because the first arrival to a node using BFS is guaranteed to use the fewest possible number of edges.
Auxiliary Space Used:
Auxiliary space is taken by array visited and linked list queue.
The visited array has n elements so it takes O(n) space.
Let’s see why the queue cannot ever have more than 6*n nodes (and therefore takes O(n) space too). Processing each node adds at most 6 new nodes to the queue, and no one node is processed more than once. Even if somehow all n nodes get processed before any nodes removed from the queue (not quite possible in practice as nodes get removed from the queue as algorithm processes them), we would have the queue with 6*n nodes and no more nodes could possibly be added to it (because visited[i] is true for all indices by then).
Total Auxiliary Space Used is O(n) + O(n) = O(n)
Auxiliary Space Used of O(n) plus input size of O(n) give us a total of O(n).
Using the same logic we used when calculating the Auxiliary Space Used we can conclude the Time Complexity of O(n).