Back to all solutions
#1263 - Minimum Moves to Move a Box to Their Target Location
Problem Description
A storekeeper is a game in which the player pushes boxes around in a warehouse trying to get them to target locations.
The game is represented by an m x n grid of characters grid where each element is a wall, floor, or box.
Your task is to move the box 'B' to the target position 'T' under the following rules:
- The character 'S' represents the player. The player can move up, down, left, right in grid if it is a floor (empty cell).
- The character '.' represents the floor which means a free cell to walk.
- The character '#' represents the wall which means an obstacle (impossible to walk there).
- There is only one box 'B' and one target cell 'T' in the grid.
- The box can be moved to an adjacent free cell by standing next to the box and then moving in the direction of the box. This is a push.
- The player cannot walk through the box.
Return the minimum number of pushes to move the box to the target. If there is no way to reach the target, return -1.
Solution
/**
* @param {character[][]} grid
* @return {number}
*/
var minPushBox = function(grid) {
const rows = grid.length;
const cols = grid[0].length;
let player;
let box;
let target;
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
if (grid[i][j] === 'S') player = [i, j];
if (grid[i][j] === 'B') box = [i, j];
if (grid[i][j] === 'T') target = [i, j];
}
}
const queue = [[...box, ...player, 0]];
const seen = new Set([`${box}-${player}`]);
const directions = [[0, 1], [1, 0], [0, -1], [-1, 0]];
function canReach(src, dst, fixedBox) {
const visited = new Set();
const stack = [src];
while (stack.length) {
const [r, c] = stack.pop();
if (r === dst[0] && c === dst[1]) return true;
if (visited.has(`${r}-${c}`)) continue;
visited.add(`${r}-${c}`);
for (const [dr, dc] of directions) {
const nr = r + dr;
const nc = c + dc;
if (nr < 0 || nr >= rows || nc < 0 || nc >= cols || grid[nr][nc] === '#'
|| (nr === fixedBox[0] && nc === fixedBox[1])) continue;
stack.push([nr, nc]);
}
}
return false;
}
while (queue.length) {
const [boxRow, boxCol, playerRow, playerCol, pushes] = queue.shift();
if (boxRow === target[0] && boxCol === target[1]) return pushes;
for (const [dr, dc] of directions) {
const newBoxRow = boxRow + dr;
const newBoxCol = boxCol + dc;
const newPlayerRow = boxRow - dr;
const newPlayerCol = boxCol - dc;
if (newBoxRow < 0 || newBoxRow >= rows || newBoxCol < 0 || newBoxCol >= cols
|| grid[newBoxRow][newBoxCol] === '#') continue;
if (!canReach([playerRow, playerCol], [newPlayerRow, newPlayerCol], [boxRow, boxCol])) {
continue;
}
const state = `${newBoxRow}-${newBoxCol}-${newPlayerRow}-${newPlayerCol}`;
if (seen.has(state)) continue;
seen.add(state);
queue.push([newBoxRow, newBoxCol, newPlayerRow, newPlayerCol, pushes + 1]);
}
}
return -1;
};