File GridMaze.h¶
Go to the documentation of this file
#ifndef GRID_PLUS_PLUS_GRID_MAZE_H_
#define GRID_PLUS_PLUS_GRID_MAZE_H_
#include <stdexcept>
#include <string>
#include <utility>
#include "GridPlusPlus.h"
namespace gridpp {
class GridMaze : public GridObject {
public:
static constexpr int kMaxWidth = 64;
static constexpr int kMaxHeight = 64;
GridMaze(int cols, int rows);
void SetWall(int x, int y, bool wall);
bool IsWall(int x, int y) const;
void SetWallAsset(const std::string& asset);
void SetWallTiles(const std::string& isolated, const std::string& end, const std::string& straight,
const std::string& corner, const std::string& tee, const std::string& cross);
int width() const;
int height() const;
void Render(GridEngine* engine) override;
private:
// 鄰居是否為牆。上、右、下、左分別使用 bits 0 到 3。
int ConnectivityMask(int x, int y) const;
// 把連通情況 mask 轉成「基本形狀索引 + 旋轉方向(0~3)」。
static std::pair<int, int> ShapeFor(int mask);
int width_ = 0;
int height_ = 0;
bool walls_[kMaxHeight][kMaxWidth] = {};
std::string single_wall_;
std::string wall_tiles_[6];
bool use_tiles_ = false;
};
// Inline definitions
inline GridMaze::GridMaze(int cols, int rows) : GridObject("", -1, -1), width_(cols), height_(rows) {
if (cols < 1 || rows < 1 || cols > kMaxWidth || rows > kMaxHeight) {
throw std::invalid_argument("GridMaze Error: dimensions must be between 1x1 and 64x64");
}
set_tag("maze");
}
inline void GridMaze::SetWall(int x, int y, bool wall) {
if (x < 0 || y < 0 || x >= width_ || y >= height_) {
throw std::out_of_range("GridMaze Error: wall position (" + std::to_string(x) + ", " + std::to_string(y) +
") is outside " + std::to_string(width_) + "x" + std::to_string(height_) + " maze");
}
walls_[y][x] = wall;
}
inline bool GridMaze::IsWall(int x, int y) const {
if (x < 0 || y < 0 || x >= width_ || y >= height_) return true;
return walls_[y][x];
}
inline void GridMaze::SetWallAsset(const std::string& asset) {
single_wall_ = asset;
use_tiles_ = false;
}
inline void GridMaze::SetWallTiles(const std::string& isolated, const std::string& end, const std::string& straight,
const std::string& corner, const std::string& tee, const std::string& cross) {
wall_tiles_[0] = isolated;
wall_tiles_[1] = end;
wall_tiles_[2] = straight;
wall_tiles_[3] = corner;
wall_tiles_[4] = tee;
wall_tiles_[5] = cross;
use_tiles_ = true;
}
inline int GridMaze::width() const { return width_; }
inline int GridMaze::height() const { return height_; }
inline void GridMaze::Render(GridEngine* engine) {
for (int y = 0; y < height_; ++y) {
for (int x = 0; x < width_; ++x) {
if (!walls_[y][x]) continue;
if (use_tiles_) {
const auto [shape, direction] = ShapeFor(ConnectivityMask(x, y));
engine->DrawCell(wall_tiles_[shape], x, y, direction);
} else {
engine->DrawCell(single_wall_, x, y);
}
}
}
}
inline int GridMaze::ConnectivityMask(int x, int y) const {
int mask = 0;
if (IsWall(x, y - 1)) mask |= 1;
if (IsWall(x + 1, y)) mask |= 2;
if (IsWall(x, y + 1)) mask |= 4;
if (IsWall(x - 1, y)) mask |= 8;
return mask;
}
inline std::pair<int, int> GridMaze::ShapeFor(int mask) {
static constexpr int kShapes[16] = {0, 1, 1, 3, 1, 2, 3, 4, 1, 3, 2, 4, 3, 4, 4, 5};
static constexpr int kDirections[16] = {0, 0, 3, 0, 2, 0, 3, 0, 1, 1, 1, 1, 2, 2, 3, 0};
return {kShapes[mask], kDirections[mask]};
}
} // namespace gridpp
#endif // GRID_PLUS_PLUS_GRID_MAZE_H_