Microsoft Interview Question
SDE-2sTeam: STB and MVO
Country: United States
Interview Type: In-Person
A knight can move in 8 directions from the current position
2 in front, 4 sideways and 2 backwards.
Thus we can easily calculate the position using recursion from the current position where a knight can move.
Here is a algo that I have thought
void KnightMove(int **a, int m, int n, int currx, curry)
{
if(currx<0 || curry <0)
return;
if(currx >= n || curry >=m)
return;
if(a[currx][curry] == VISITED)
return;
else
{
a[currx][curry] == VISITED;
//move forward
KnightMove(a, m, n, currx-1, curry+2);
KnightMove(a, m, n, currx+1, curry+2);
//move sideways
KnightMove(a, m, n, currx-2, curry+1);
KnightMove(a, m, n, currx-2, curry-1);
KnightMove(a, m, n, currx+2, curry+1);
KnightMove(a, m, n, currx+2, curry-1);
//move backward
KnightMove(a, m, n, currx-1, curry-2);
KnightMove(a, m, n, currx+1, curry-2);
}
}
Please do let me know If I am missing something here
@DashDash: just extended your logic
#define SIZE 8
#define VISITED 567
int KnightMove(int (*a)[SIZE], int m, int n, int currx, int curry)
{
if(currx<0 || curry <0)
return 0;
if(currx >= SIZE || curry >= SIZE)
return;
//checking if 3,3 is reachable or not as we are starting
//from 0,0 index.
if(currx == 3 && curry == 3)
return 1;
if(a[currx][curry] == VISITED)
return 0;
else
{
a[currx][curry] = VISITED;
//move forward
if(KnightMove(a, m, n, currx-1, curry+2) == 1)
return 1;
if(KnightMove(a, m, n, currx+1, curry+2) == 1)
return 1;
//move sideways
if(KnightMove(a, m, n, currx-2, curry+1) == 1)
return 1;
if(KnightMove(a, m, n, currx-2, curry-1) == 1)
return 1;
if(KnightMove(a, m, n, currx+2, curry+1) == 1)
return 1;
if(KnightMove(a, m, n, currx+2, curry-1) == 1)
return 1;
a[currx][curry] = 0;
}
}
void printSolution(int sol[SIZE][SIZE])
{
int i, j;
for (i = 0; i < SIZE; i++)
{
for (j = 0; j < SIZE; j++)
printf("%8d", sol[i][j]);
printf("\n");
}
}
int main()
{
int a[SIZE][SIZE] = {0};
memset(a, 0, sizeof(int)*SIZE*SIZE);
KnightMove(a, SIZE, SIZE, 0, 0);
printSolution(a);
return 0;
}
Solution by DashDash will eventually make all cells of a[][] as VISITED. This will not tell me the cells traversed inorder to reach a particular destination cell.
@aka : can you please clarify your logic more, coz as far as I think, your solution will either make all cells visited as DashDash's solution or all cells 0. Please elaborate your logic.
@I.mFirst This will print the path when you reach your destination i,j. I have modified the code to print the path to reach destination i, j which is in the below code is 3,3.
#define SIZE 8
#define VISITED 567
int KnightMove(int (*a)[SIZE], int m, int n, int currx, int curry)
{
if(currx<0 || curry <0)
return 0;
if(currx >= SIZE || curry >= SIZE)
return;
//checking if 3,3 is reachable or not as we are starting
//from 0,0 index.
if(currx == 3 && curry == 3) {
a[currx][curry] = VISITED;
printf("%d %d\n", currx, curry);
return 1;
} if(a[currx][curry] == VISITED)
return 0;
else
{
printf("%d %d\n", currx, curry);
a[currx][curry] = VISITED;
//move forward
if(KnightMove(a, m, n, currx-1, curry+2) == 1)
return 1;
if(KnightMove(a, m, n, currx+1, curry+2) == 1)
return 1;
//move sideways
if(KnightMove(a, m, n, currx-2, curry+1) == 1)
return 1;
if(KnightMove(a, m, n, currx-2, curry-1) == 1)
return 1;
if(KnightMove(a, m, n, currx+2, curry+1) == 1)
return 1;
if(KnightMove(a, m, n, currx+2, curry-1) == 1)
return 1;
if(KnightMove(a, m, n, currx-1, curry-2) == 1)
return 1;
if(KnightMove(a, m, n, currx+1, curry-2) == 1)
return 1;
}
}
void printSolution(int sol[SIZE][SIZE])
{
int i, j;
for (i = 0; i < SIZE; i++)
{
for (j = 0; j < SIZE; j++)
printf("%8d", sol[i][j]);
printf("\n");
}
}
int main()
{
int a[SIZE][SIZE] = {0};
memset(a, 0, sizeof(int)*SIZE*SIZE);
KnightMove(a, SIZE, SIZE, 0, 0);
printSolution(a);
return 0;
}
Do you need all the places that the knight can eventually reach, or all the places the knight can reach in one move? A knight can eventually reach any square on a standard chessboard.
I need all the places knight can reach from a given position along with all the positions reachable from new found positions.
suppose knight is at position (x,y) and it can reach (i, j) from it and can reach (w,q) from (i, j). So I need (i, j) and (w,q) both.
Therefore I need all positions reachable directly from (x, y) and all positions reachable from positions reachable from position (x, y) and so on and on.
I understand that eventually all the cells would be traversed by knight. But it will not give me the intermediate positions
which knight travelled before landing at a cell.
Therefore give me anything which also tells me the path. You decide what u need to return me to do so.
@I.mFirst: "Therefore I need all positions reachable directly from (x, y) and all positions reachable from positions reachable from position (x, y) and so on and on."Where do you want to stop it?
@aka: I need all the cells reachable from a given cell either directly or indirectly.
For example: if given cell is (7, 7) then I can reach to (5, 6) and (6, 5)
then from (5, 6) I can reach to (3, 5), (4, 4), (3, 7) and so on.
and similarly for (6, 5).
Obviously I want to stop this traversal and stop at those cells which are invalid in a chessboard.
@I.mFirst "if given cell is (7, 7) then I can reach to (5, 6) and (6, 5)
then from (5, 6) I can reach to (3, 5), (4, 4), (3, 7) and so on.
and similarly for (6, 5)." but this will keep on going.When do you want to stop as from x, y it will go to a,b and this will keep going somewhere that is your knight will keep on going.When do you want your knight to stop????
I am not concerned about minimum path.
I just want to know the cells I am reachable from source cell.
For ex. from (3, 3) I am reachable to 8 cells (I hope u know which ones)
Then from each of those 8 cells I am reachable to 8 more (or probably less because some cells may be out of range of chessboard cells) and so on and on.
So this will give me reachable cells. Now you can give me back a tree or graph or anything which depicts this. I hope I am clear now.
@aka: Trust me this will eventually stop :). And it will stop when u reach invalid cells .
Invalid cell means something like: (-1, -2) or (8, 8) or (-1, 2) etc etc...
I hope this makes it clear.
@l.mFirst: it is never going to go to invalid cell as the logic which we have written will never let it to go invalid cell.Check how i,j is getting changed in the algo.
@aka: Then your logic is wrong sir. Please understand what I have given in question and in follow up comments.
@l.mFirst: "Return me something (adjacency matrix or list or anything) which shows all the positions the knight can reach upto from a given position".This is what you have given.
@aka: Right ...this was the question. Later I also wrote follow-up comments...which if you read will come to know more.
This problem reduces to the standard BFS algorithm with the only difference being the edges are not present! Instead of going out from the source square following the adjacent edges we need to follow the knight move pattern and find the adjacent squares that are reachable from any square by the knight.
[DebuggerDisplay("{ToString()}, Visited = {Visited}")]
public class ChessSquare
{
private readonly int _row;
private readonly int _column;
public ChessSquare(int row, int column)
{
_row = row;
_column = column;
Visited = false;
Parent = null;
}
public int Row { get { return _row; } }
public int Column { get { return _column; } }
public ChessSquare Parent { get; set; }
public bool Visited { get; set; }
public static bool IsValid(int row, int column)
{
return (row >= 0 && row < 8 && column >= 0 && column < 8);
}
public override string ToString()
{
return string.Format("{0}{1}", (char)((int)'a' + _row), _column + 1);
}
}
public class Chess
{
ChessSquare[,] _board;
public Chess()
{
_board = new ChessSquare[8, 8];
InitializeSquares();
}
private void InitializeSquares()
{
for (int row = 0; row < 8; row++)
{
for (int col = 0; col < 8; col++)
{
_board[row, col] = new ChessSquare(row, col);
}
}
}
public void DiscoverKnightMoves(int row, int column)
{
var queue = new Queue<ChessSquare>();
var sourceSquare = _board[row, column];
sourceSquare.Visited = true;
queue.Enqueue(sourceSquare);
while (queue.Count > 0)
{
var current = queue.Dequeue();
var adjacentSquares = GetAdjacentSquares(current.Row, current.Column);
foreach (var square in adjacentSquares)
{
square.Visited = true;
square.Parent = current;
queue.Enqueue(square);
}
}
PrintPaths();
}
private List<ChessSquare> GetAdjacentSquares(int row, int col)
{
var adjacentSquares = new List<ChessSquare>();
//north-east quadrant
CheckAdd(row - 1, col + 2, adjacentSquares);
CheckAdd(row - 2, col + 1, adjacentSquares);
//south-east quadrant
CheckAdd(row + 1, col + 2, adjacentSquares);
CheckAdd(row + 2, col + 1, adjacentSquares);
//north-west quadrant
CheckAdd(row - 1, col - 2, adjacentSquares);
CheckAdd(row - 2, col - 1, adjacentSquares);
//south-west quadrant
CheckAdd(row + 1, col - 2, adjacentSquares);
CheckAdd(row + 2, col - 1, adjacentSquares);
return adjacentSquares;
}
private void CheckAdd(int row, int column, List<ChessSquare> adjacentSquares)
{
if (ChessSquare.IsValid(row, column) && !_board[row, column].Visited)
adjacentSquares.Add(_board[row, column]);
}
private void PrintPaths()
{
foreach (var square in _board)
{
//only if square has been visited it is reachable from the source square
if (square.Visited)
{
PrintPath(square);
Console.WriteLine();
}
}
}
private void PrintPath(ChessSquare square)
{
if (square != null)
{
Console.Write("{0}", square);
if (square.Parent != null)
Console.Write(" <- ");
PrintPath(square.Parent);
}
}
}
public static bool FindAllPos(int x, in y, int[,] reachTable)
{
//x= 1,...,8; y= 1,...,8
if(x<1||x>8||y<1||y>8) return false;
if( reachTable[x-1,y-1] !=0) return false;
bool flag = false;
for( int i =-2;i<=2;++)
{
for(int j = -2; j<=2; ++j)
{
if( (i*i)+(j*j) != 5 ) continue; //Knight always jump this distance. Total 8 cases.
if( FindAllPos(x+i, y+j, reachTable) )
{ //reach table element remember the previous position
reachTable[x+i,y+j] = x + (y-1)*8; // To identify 8*8 tatal 1,2,3,...,64 possible positions
flag = true;
}
}
}
return flag;
}
public static main()
{ int x = 2; int y =3;
int[8,8] reach_table = new int[8,8]{0};
FindAllPos(x,y, reach_table);
}
1) Use BFS to compute all the positions that are reachable from the knight.
2) For each position, store it in a Hash
3) Compute a trie structure when doing BFS, basically is you can reach positions Y and Z from X, then X has two children Y and Z; and also maintain parent pointer for Y and Z which point to X
If the query is if P can be reached, then look the hashtable and return true if present.
If path is requested, then trace the path from P to root (starting position) using parent pointers.
If the query is to
package graphs.search;
import utility.Queue;
import java.util.ArrayList;
import java.util.List;
class ChessCell {
private int x;
private int y;
//Path to reach the cell from the start cell
List<ChessCell> pathList;
public ChessCell(int x, int y) {
this.x = x;
this.y = y;
this.pathList = new ArrayList<>();
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public String toString() {
return "("+x+","+y+")";
}
public boolean compareAnotherChessCell(ChessCell cell) {
return this.getX() == cell.getX() && this.getY() == cell.getY();
}
}
public class KnightPositionChess {
private static final int[] XMOVE = new int[]{2, 1, -1, -2, -2, -1, 1, 2};
private static final int[] YMOVE = new int[]{1, 2, 2, 1, -1, -2, -2, -1};
private static final int N = 3;
private ChessCell startCell;
private List<ChessCell> reachableFromStartCell;
public KnightPositionChess(int x,int y) {
startCell = new ChessCell(x,y);
reachableFromStartCell = findAllReachable();
}
public Iterable<ChessCell> findPath(int x,int y) {
ChessCell newChessCell = new ChessCell(x,y);
if(reachableFromStartCell.isEmpty()) {
findAllReachable();
}
for (ChessCell cell : reachableFromStartCell) {
if(cell.compareAnotherChessCell(newChessCell)) {
return cell.pathList;
}
}
return null;
}
public Iterable<ChessCell> getReachableCells() {
return reachableFromStartCell;
}
private List<ChessCell> findAllReachable() {
startCell.pathList.add(startCell);
Queue<ChessCell> queue = new Queue<>();
queue.enqueue(startCell);
List<ChessCell> reachableCells = new ArrayList<>();
boolean[][] visited = new boolean[N][N];
visited[startCell.getX()][startCell.getY()] = true;
while (!queue.isEmpty()) {
ChessCell current = queue.dequeue();
int currentX = current.getX();
int currentY = current.getY();
for (int i=0;i<8;i++) {
int newX = currentX + XMOVE[i];
int newY = currentY + YMOVE[i];
if(isValid(newX,newY,visited)) {
ChessCell newCell = new ChessCell(newX,newY);
//Visited true is marked as soon as the cell is visited, so that it is not visited while bfs of another cell
visited[newX][newY] = true;
newCell.pathList = new ArrayList<>(current.pathList);
newCell.pathList.add(newCell);
queue.enqueue(newCell);
reachableCells.add(newCell);
}
}
}
return reachableCells;
}
private boolean isValid(int x,int y,boolean[][] visited) {
return (x>=0 && y>=0 && x<N && y<N && !visited[x][y]);
}
public static void main(String[] args) {
KnightPositionChess kp = new KnightPositionChess(2,0);
Iterable<ChessCell> iterable = kp.getReachableCells();
System.out.println("All reachable vertices are : ");
for (ChessCell coordinates : iterable) {
System.out.print(coordinates.toString() + " ");
}
System.out.println("path for element 0,2 : " );
for (ChessCell coordinates : kp.findPath(0,2)) {
System.out.print(coordinates.toString() + " ");
}
}
}
Here's my solution. I gave in interview adjacency Iist based solution.
Here I am giving both, adjacency-list and adjacency-matrix based solution for your reference:
}
- pavi.8081 March 09, 2014