Snakes and Ladders

Introduction

Graph problems pervade computer science, and algorithms to working with them are fundamental to the field. Hundreds of interesting computational problems are couched in terms of graphs. Today let’s discuss graph algorithms.

In fact, I like this problem so much because it reminds me of my childhood. We were playing this game during our school holidays with our friends and it was fun. Let us get into the details next.


Problem Statement

You are given an $n \times n$ integer matrix board where the cells are labeled from $1$ to $n^2$ in a Boustrophedon style starting from the bottom left of the board (i.e. $board[n - 1][0]$) and alternating direction each row.
You start on square $1$ of the board. In each move, starting from square curr, do the following:
Choose a destination square next with a label in the range $[curr + 1, min(curr + 6, n^2)]$
This choice simulates the result of a standard 6-sided die roll: i.e., there are always at most 6 destinations, regardless of the size of the board.
If next has a snake or ladder, you must move to the destination of that snake or ladder. Otherwise, you move to next.
The game ends when you reach the square $n^2$.

A board square on row $r$ and column $c$ has a snake or ladder if $board[r][c] \neq -1$. The destination of that snake or ladder is $board[r][c]$. Squares $1$ and $n^2$ are not the starting points of any snake or ladder.

Note that you only take a snake or ladder at most once per dice roll. If the destination to a snake or ladder is the start of another snake or ladder, you do not follow the subsequent snake or ladder.

For example, suppose the board is 

$\begin{bmatrix}-1 & 4\\-1 & 3\end{bmatrix}$, 

and on the first move, your destination square is 2. You follow the ladder to square 3, but do not follow the subsequent ladder to 4.

Return the least number of dice rolls required to reach the square $n^2$. If it is not possible to reach the square, return $-1$. [1]


Our Approach

This problem is an interesting problem and we solve it using reduction. We reduce the problem into a graph problem and solve it using a graph algorithm which then provides the answer to the original problem. In fact, we can solve this problem using Breadth First Search algorithm. 

From my current position, I roll the dice and it gives me some value $v : v \in \{1, 2, 3, 4, 5, 6\}$ which I can then use to move onto my next position. A dice rolling event would have six possible outcomes and each of them can be thought of as an edge from the current vertex to the next vertex in our graph $G$. Note that $G$ is a directed graph with outdegree $6$.  What follows is our pseudocode to solve this problem.

SNAKE_AND_LADDERS(board)  
    $\phantom{{}++{}}$ let $n \gets board.length$  
    $\phantom{{}++{}}$ let $size \gets n^2$  
    $\phantom{{}++{}}$ let $d$ be a boolean array of size $n^2 + 1$  
    $\phantom{{}++{}}$ let $q$ be a FIFO queue  
    $\phantom{{}++{}}$ $d[1] \gets true$  
    $\phantom{{}++{}}$ enqueue a vertex with label $1$ and distance $0$ to $q$     
    $\phantom{{}++{}}$ `while` $q$ is not empty   
    $\phantom{{}++{}}$ $\phantom{{}++{}}$ let $u \gets q.remove()$  
    $\phantom{{}++{}}$ $\phantom{{}++{}}$ `for` $i = 1$ to $6$      
    $\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$  let $next = u.label + i$  
    $\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$  `if` $next \le size$    
    $\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ let $r, c$ be the corresponding row and column values of the current square with label $next$   
    $\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ let $dest \gets next$  
    $\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ `if` $board[r][c] \neq -1$  
    $\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ $dest \gets board[r][c]$  
$\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ `if` $dest == size$  
$\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ `return` $u.distance + 1$  
$\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ `if` $!d[dest]$  
$\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ $d[dest] \gets true$  
$\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ $\phantom{{}++{}}$ enqueue a vertex with label $dest$ and distance $u.distance + 1$ to $q$  
$\phantom{{}++{}}$ `return` $-1$  

What follows is a sample implementation of the algorithm described above.



Analysis

Let $n \times n$ be the dimensions of the input matrix. Each block is enqueued at most once, hence dequeued at most once. The operations of enqueueing and dequeueing takes O(1) time, and so the total time devoted to queue operations is $\Theta(n^2)$. Calculations of the $d$ values take $\Theta(1)$ time per entry. Thus, the calculation over all the entries in the table $d$ incurs a total cost of $\Theta(n^2)$. The overhead of initialization is $\Theta(n^2)$. Thus, the total running time of our algorithm is $\Theta(n^2)$. Apart from that it consumes $\Theta(n^2)$ asymptotic space complexity for maintaining the table $d$. 


Comments

Popular posts from this blog

Introducing Java Reactive Extentions in to a SpringBoot Micro Service

Optimal binary search trees

Edit distance