node-maze-generator
Version:
Generate perfect mazes with Node using a growing tree algorithm
140 lines (131 loc) • 5.44 kB
JavaScript
const Cell = require("./cell");
const {Random} = require("./utils");
const MIN_WIDTH = 5;
const MIN_HEIGHT = 5;
const MIN_BOUNDARY = -1;
const MIN_NEIGHBOR_BOUNDARY = 0;
const MIN_FLOORS = 1;
/**
* @class Grid
* @description The grid class is responsible for generating, storing and manipulating a grid of Cell object instances.
* @param {Object} options - The options object.
* @param {Number} options.width - The width of the grid.
* @param {Number} options.height - The height of the grid.
* @param {Array} options.floors - The total number of floors in the grid.
* @param {Number} options.start_x - The x position of the starting cell.
* @param {Number} options.start_y - The y position of the starting cell.
* @param {Number} options.start_z - The z position of the starting cell.
* @param {Cell} options.cell_class - The class used to represent a cell on the grid.
*/
class Grid {
/**
* @function constructor
* @description Generate a Grid object of given dimensions filled with Cell objects and floor data.
* @param {Object} options Optional arguments for the Grid object.
*/
constructor(options) {
// Initialize all properties, and then the grid.
this.width = parseInt(options.width) || MIN_WIDTH;
this.height = parseInt(options.height) || MIN_HEIGHT;
this.total_floors = parseInt(options.total_floors) || MIN_FLOORS;
this.start_x = parseInt(options.start_x) || 0;
this.start_y = parseInt(options.start_y) || 0;
this.start_z = parseInt(options.start_z) || 0;
this.CellClass = options.cell_class||Cell;
this.currentFloor = options.currentFloor||0;
if (this.width <= MIN_WIDTH) this.width = MIN_WIDTH;
if (this.height <= MIN_HEIGHT) this.height = MIN_HEIGHT;
if (this.start_x > this.width - 1) this.start_x = this.start_x - 1;
if (this.start_y > this.height - 1) this.start_y = this.start_y - 1;
if (this.start_z >= this.total_floors) this.start_z = this.total_floors - 1;
this.floors = [];
this.initialize();
}
/**
* @function initialize
* @description Iterates through each coordinate and creates a cell at that location.
* @return {void}
*/
initialize = () => {
this.cells = [];
for (let z = this.start_z; z < this.total_floors; z++) {
this.floors[z] = {}; // set floor data to an empty object
this.cells[z] = [];
for (let y = this.start_y; y < this.height; y++) {
this.cells[z][y] = [];
for (let x = this.start_x; x < this.width; x++) {
this.cells[z][y][x] = new this.CellClass(x, y, z);
}
}
}
}
/**
* @function randomCell
* @description Returns a random cell from the grid.
* @param {Number} z The floor to get a cell from
* @return {Object} Cell object
*/
randomCell = (z) => {
const x = Random.range(MIN_NEIGHBOR_BOUNDARY, this.width - 2);
const y = Random.range(MIN_NEIGHBOR_BOUNDARY, this.height - 2);
return this.getCell(x, y, z);
}
/**
* @function isInBounds
* @description Checks if given coordinates are within the bounds of the grid.
* @param {Number} x x-coordinate of the cell
* @param {Number} y y-coordinate of the cell
* @return {Boolean} true if in bounds, false otherwise
*/
isInBounds = (x, y) => (
x < this.width
&& x > MIN_BOUNDARY
&& y < this.height
&& y > MIN_BOUNDARY
);
/**
* @function isInNavigationBounds
* @description Checks if given coordinates are within the bounds of the grid used for navigation.
* @param {Number} x x-coordinate of the cell
* @param {Number} y y-coordinate of the cell
* @return {Boolean} true if in bounds, false otherwise
*/
isInNavigationBounds = (x, y) => (
x < this.width - 1
&& x > MIN_NEIGHBOR_BOUNDARY
&& y < this.height - 1
&& y > MIN_NEIGHBOR_BOUNDARY
);
/**
* @function getCell
* @description Gets a cell from the grid.
* @param {Number} x x-coordinate of the cell
* @param {Number} y y-coordinate of the cell
* @param {Number} z the floor of the cell
* @return {Object} Cell object if in bounds, null otherwise
*/
getCell = (x, y, z) => this.isInBounds(x, y) ? this.cells[z][y][x] : null;
/**
* @function getNeighborCell
* @description Gets a cell from the grid. Functions the same as getCell, but checks against navigation bounds.
* @param {Number} x x-coordinate of the cell
* @param {Number} y y-coordinate of the cell
* @param {Number} z the floor of the cell
* @return {Object} Cell object if in bounds, null otherwise
*/
getNeighborCell = (x, y, z) => this.isInNavigationBounds(x, y) ? this.cells[z][y][x] : null;
/**
* @function unblockCell
* @description Unblocks a cell if it is in bounds.
* @param {Number} x x-coordinate of the cell
* @param {Number} y y-coordinate of the cell
* @param {Number} z the floor of the cell
* @return {void}
*/
unblockCell = (x, y, z) => {
if (this.isInBounds(x, y)) {
this.cells[z][y][x].blocked = false;
}
}
}
module.exports = Grid;