/**
* 489. Robot Room Cleaner
* Given a robot cleaner in a room modeled as a grid.
* Each cell in the grid can be empty or blocked.
* The robot cleaner with 4 given APIs can move forward, turn left or turn right. Each turn it made is 90 degrees.
* When it tries to move into a blocked cell, its bumper sensor detects the obstacle and it stays on the current cell.
* Design an algorithm to clean the entire room using only the 4 given APIs shown below.
* interface Robot {
* // returns true if next cell is open and robot moves into the cell.
* // returns false if next cell is obstacle and robot stays on the current cell.
* boolean move();
* // Robot will stay on the same cell after calling turnLeft/turnRight.
* // Each turn will be 90 degrees.
* void turnLeft();
* void turnRight();
* // Clean the current cell.
* void clean();
* }
* Example:
*
* Input:
* room = [
* [1,1,1,1,1,0,1,1],
* [1,1,1,1,1,0,1,1],
* [1,0,1,1,1,1,1,1],
* [0,0,0,1,0,0,0,0],
* [1,1,1,1,1,1,1,1]
* ],
* row = 1,
* col = 3
* Explanation:
* All grids in the room are marked by either 0 or 1.
* 0 means the cell is blocked, while 1 means the cell is accessible.
* The robot initially starts at the position of row=1, col=3.
* From the top left corner, its position is one row below and three columns right.
* The input is only given to initialize the room and the robot’s position internally.
* You must solve this problem “blindfolded”. In other words, you must control the robot using only the mentioned 4 APIs,
* without knowing the room layout and the initial robot’s position.
* The robot’s initial position will always be in an accessible cell.
* The initial direction of the robot will be facing up.
* All accessible cells are connected, which means the all cells marked as 1 will be accessible by the robot.
* Assume all four edges of the grid are all surrounded by wall.
*/
See solution to the problem on github here: https://github.com/zcoderz/leetcode/blob/main/src/main/java/frequent/hard/RobotRoomCleaner.java
This is a very elegant and simple solution for traversal and hence I have included it here.
Here is the algorithm:
- Traversal in a matrix is simplified via creating the below offsets per move.
- The directions are in a clockwise order starting from Up.
- create a set of moves in a clockwise direction
- int[] rowOffset = {-1, 0, 1, 0};
- int[] colOffset = {0, 1, 0, -1};
- Traverse the matrix via moving the robot in each of the possible directions while keeping track of each cell that has been visited so as to not revisit a previously visited cell.
- Keep track of the direction offset in a variable which you increment and mod by 4 to find the next direction.
- Once a direction has been traversed, step the robot back to its original cell and direction via using the stepBackRobot method.
- Turn the robot right at end of each directional move so that the direction of the robot for next traversal is correct.
Here is the code:
/**
* method cleans room and recurse
*
*/
void recurseClean(int row, int col, Robot robot, int direction) {
//mark room as visited
Pair<Integer, Integer> spot = new Pair<>(row, col);
visited.add(spot);
robot.clean(); //clean room
//do 4 moves , forward, right, down, left. since they are circular you just keep turning right
for (int i = 0; i < 4; i++) {
//this one is tricky but extremely smart, avoids having to write a bunch of direction management code
//you basically start with orig direction and rotate 4 more directions on it. therefore, your starting
//point is direction passed as param. since it could be any of 0,1,2,3 you mod by 4 to get next 4 directions
int newDir = (direction + i) % 4;
int newRow = row + rowOffset[newDir];
int newCol = col + colOffset[newDir];
Pair<Integer, Integer> newSpot = new Pair<>(newRow, newCol);
if (!visited.contains(newSpot) && robot.move()) {
//continue recurse if its a valid move
recurseClean(newRow, newCol, robot, newDir);
//very important, change back to starting direction that was passed in to the above recurse method
stepBackRobot(robot);
}
//change directions
robot.turnRight();
}
}
/**
* move back to starting cell
*/
void stepBackRobot(Robot robot) {
robot.turnRight();
robot.turnRight();//change direction
robot.move();//move back
robot.turnRight();//change direction again so that direction is same as what you started with
robot.turnRight();
}