I'm posting my code for a LeetCode problem. If you'd like to review, please do so. Thank you for your time!
Problem
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 a grid
of size m x n
, where each element is a wall, floor, or a box.
Your task is move the box 'B' to the target position 'T' under the following rules:
- Player is represented by character 'S' and can move up, down, left, right in the
grid
if it is a floor (empty cell). - Floor is represented by character '.' that means free cell to walk.
- Wall is represented by character '#' that means 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.
Example 1:
Image Courtesy of LeetCode.com
Input: grid = [["#","#","#","#","#","#"],
["#","T","#","#","#","#"],
["#",".",".","B",".","#"],
["#",".","#","#",".","#"],
["#",".",".",".","S","#"],
["#","#","#","#","#","#"]]
Output: 3
Explanation: We return only the number of times the box is pushed.
Example 2:
Input: grid = [["#","#","#","#","#","#"],
["#","T","#","#","#","#"],
["#",".",".","B",".","#"],
["#","#","#","#",".","#"],
["#",".",".",".","S","#"],
["#","#","#","#","#","#"]]
Output: -1
Example 3:
Input: grid = [["#","#","#","#","#","#"],
["#","T",".",".","#","#"],
["#",".","#","B",".","#"],
["#",".",".",".",".","#"],
["#",".",".",".","S","#"],
["#","#","#","#","#","#"]]
Output: 5
Explanation: push the box down, left, left, up and up.
Example 4:
Input: grid = [["#","#","#","#","#","#","#"],
["#","S","#",".","B","T","#"],
["#","#","#","#","#","#","#"]]
Output: -1
Constraints:
m == grid.length
n == grid[i].length
1 <= m <= 20
1 <= n <= 20
grid
contains only characters '.', '#', 'S' , 'T', or 'B'.- There is only one character 'S', 'B' and 'T' in the
grid
.
Code
#include <cstdint>
#include <array>
#include <vector>
#include <utility>
#include <queue>
#include <unordered_set>
class Solution {
using size_type = std::uint_fast16_t;
static constexpr char kPLAYER = 'S';
static constexpr char kBOX = 'B';
static constexpr char kTARGET = 'T';
static constexpr char kWALL = '#';
static constexpr char kFLOOR = '.';
static constexpr std::array<std::array<std::int_fast8_t, 2>, 4> kDIRECTIONS = {{{ -1, 0}, {1, 0}, {0, -1}, {0, 1}}};
public:
int minPushBox(std::vector<std::vector<char>>& grid) {
const size_type row_len = std::size(grid);
const size_type col_len = std::size(grid[0]);
std::queue<std::pair<size_type, size_type>> player_box_q;
std::unordered_set<std::string> box_player_encodes;
size_type start = 0;
size_type end = 0;
size_type player = 0;
for (size_type row = 0; row < row_len; ++row) {
for (size_type col = 0; col < col_len; ++col) {
const size_type curr_pos = row * col_len + col;
if (grid[row][col] == kPLAYER) {
player = curr_pos;
grid[row][col] = kFLOOR;
}
if (grid[row][col] == kBOX) {
start = curr_pos;
grid[row][col] = kFLOOR;
}
if (grid[row][col] == kTARGET) {
end = curr_pos;
grid[row][col] = kFLOOR;
}
}
}
if (start == end) {
return 0;
}
player_box_q.push({start, player});
size_type pushes = 0;
while (std::size(player_box_q)) {
size_type qlen = std::size(player_box_q);
while (qlen--) {
const auto curr_box_player = player_box_q.front();
player_box_q.pop();
const size_type box = curr_box_player.first;
const size_type player = curr_box_player.second;
if (box == end) {
return pushes;
}
const size_type x_box = box / col_len;
const size_type y_box = box % col_len;
for (const auto& direction : kDIRECTIONS) {
const size_type next_x_box = x_box + direction[0];
const size_type next_y_box = y_box + direction[1];
const size_type next_x_player = x_box - direction[0];
const size_type next_y_player = y_box - direction[1];
if (
next_x_box < 0 ||
next_x_box >= row_len ||
next_y_box < 0 ||
next_y_box >= col_len ||
grid[next_x_box][next_y_box] == kWALL
) {
continue;
}
if (
next_x_player < 0 ||
next_x_player >= row_len ||
next_y_player < 0 ||
next_y_player >= col_len ||
grid[next_x_player][next_y_player] == kWALL
) {
continue;
}
std::string box_player_encode = std::to_string(box) +
"," +
std::to_string(next_x_player * col_len + next_y_player);
if (box_player_encodes.count(box_player_encode)) {
continue;
}
if (isAccessible(grid, player, next_x_player * col_len + next_y_player, box)) {
player_box_q.push({next_x_box * col_len + next_y_box, box});
box_player_encodes.insert(box_player_encode);
}
}
}
++pushes;
}
return -1;
}
private:
static bool isAccessible(
std::vector<std::vector<char>>& grid,
const size_type start,
const size_type end,
const size_type box
) {
const size_type row_len = std::size(grid);
const size_type col_len = std::size(grid[0]);
std::queue<size_type> start_q;
std::vector<bool> valids(row_len * col_len);
start_q.push(start);
valids[start] = true;
grid[box / col_len][box % col_len] = kWALL;
while (std::size(start_q)) {
size_type qlen = std::size(start_q);
while (qlen--) {
const size_type curr = start_q.front();
start_q.pop();
if (curr == end) {
grid[box / col_len][box % col_len] = kFLOOR;
return true;
}
const size_type x_start = curr / col_len;
const size_type y_start = curr % col_len;
for (const auto& direction : kDIRECTIONS) {
const size_type x_next = x_start + direction[0];
const size_type y_next = y_start + direction[1];
const size_type curr_pos = x_next * col_len + y_next;
if (
x_next < 0 ||
x_next >= row_len ||
y_next < 0 ||
y_next >= col_len ||
grid[x_next][y_next] != kFLOOR ||
valids[curr_pos]) {
continue;
}
valids[curr_pos] = true;
start_q.push(curr_pos);
}
}
}
grid[box / col_len][box % col_len] = kFLOOR;
return false;
}
};