diff options
| author | Nicolas Paul <n@nc0.fr> | 2024-03-07 14:10:45 +0100 |
|---|---|---|
| committer | Nicolas Paul <n@nc0.fr> | 2024-03-08 23:12:55 +0100 |
| commit | 84061c97957b26c0bbb32d4fa2641569e0ee8f43 (patch) | |
| tree | 1119983091c9be1e97bb53e60e6eff97682563c6 | |
| parent | aed09fee6dfe278cfceafb56a4d4f14c84a737a8 (diff) | |
game: Add Board abstraction
The Board class is an abstraction over any 2D shaped board to allow the
use of any two dimensional shapes as a grid for the Life2 simulation.
This patch creates and exposes two types: the Board class, and a Grid
typedef.
The Board class is expected to be inherited by more concrete shaped
boards, such as classic "Rectangular" boards, or more complex "Triangle"
ones. Boards act as their own abstraction over their shape, with the
only requirement of implementing the small Board API defined by the
inherited class.
The Grid type serves as a encoded representation of the Board shape
using JavaScript Arrays and our defined Life2.Cell enumeration:
import {Cell} from "@life2/game";
/**
* @typedef {!Array<!Array<!Cell>>}
*/
let Grid;
The Grid structure can be though as a protocol.
The two combined can be represented as the following:
BOARD CODE
########## const grid = [[3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
###a.b.### [3, 3, 3, 1, 0, 2, 0, 3, 3, 3],
#.aab..ba# -> [3, 0, 1, 1, 2, 0, 0, 2, 1, 3],
###bb..### [3, 3, 3, 2, 2, 0, 0, 3, 3, 3],
########## [3, 3, 3, 3, 3, 3, 3, 3, 3, 3]];
Assuming:
* . = 0 = Cell.EMPTY
* a = 1 = Cell.TEAM_A
* b = 2 = Cell.TEAM_B
* # = 3 = Cell.BARRIER
The Grid representation could be obtained by calling the getGrid()
method, which can then be used by some user interface:
1. The simulator interface (our @life2/simulator)
2. A text format to share the grid state offline (our @life2/l2sf).
Signed-off-by: Nicolas Paul <n@nc0.fr>
| -rw-r--r-- | life2/game/board.js | 143 | ||||
| -rw-r--r-- | life2/game/index.js | 1 |
2 files changed, 144 insertions, 0 deletions
diff --git a/life2/game/board.js b/life2/game/board.js new file mode 100644 index 0000000..d9d508f --- /dev/null +++ b/life2/game/board.js @@ -0,0 +1,143 @@ +/** + * Copyright 2024 The Life2 Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * @license + */ + +/** + * @fileoverview A board is a grid of cells in a certain shape and size. + * The board is responsible for computing the next state of the game based on + * its current state and a set of rules. + * To make the game more interesting, the board can be configured to have + * different 2D shapes (from the classic rectangle to more complex shapes like + * hexagons). + * + * @package life2 + */ + +// Disables for false-positive errors with the JSDoc comments and the Closure +// Compiler types as ESLint is a dumb shit. +/* eslint-disable no-unused-vars */ +/* eslint-disable closure/jsdoc */ + +import {Cell} from './cell'; + +/** + * A grid is a unified, representation of the simulation board. + * It serves the purpose of standardizing the structure used by the internal API + * and downstream users. + * Specific board shapes can be achieved in a grid by playing with the BARRIER + * cells. + * + * A grid is coded as a one-dimensional array of cells, where each inner array + * is a line on the board. + * For illustration: + * + * BOARD CODE + * + * ########## const grid = [[3, 3, 3, 3, 3, 3, 3, 3, 3, 3], + * ###a.b.### [3, 3, 3, 1, 0, 2, 0, 3, 3, 3], + * #.aab..ba# -> [3, 0, 1, 1, 2, 0, 0, 2, 1, 3], + * ###bb..### [3, 3, 3, 2, 2, 0, 0, 3, 3, 3], + * ########## [3, 3, 3, 3, 3, 3, 3, 3, 3, 3]]; + * + * Assuming: + * + * * . = 0 = Cell.EMPTY + * * a = 1 = Cell.TEAM_A + * * b = 2 = Cell.TEAM_B + * * # = 3 = Cell.BARRIER + * + * @typedef {!Array<!Array<!Cell>>} + * @const + */ +export let Grid; + +/** + * A board is a grid of cells shaped after any valid 2D shape. + * The board is responsible for computing the next state of the game based on + * its current state and a set of rules that is passed to it. + * @interface + */ +export class Board { + /** + * Get the state of a cell at a given 2D position. + * @param {number} x The x position of the cell. + * @param {number} y The y position of the cell. + * @return {!Cell} The cell at the given position. + * @abstract + */ + getCell(x, y) {} + /** + * Set the state of a cell at a given 2D position. + * @param {number} x The x position of the cell. + * @param {number} y The y position of the cell. + * @param {!Cell} cell The new state of the cell. + * @abstract + */ + setCell(x, y, cell) {} + /** + * Get the neighbors of a cell at a given 2D position. + * @param {number} x The x position of the cell. + * @param {number} y The y position of the cell. + * @return {!Array<!Cell>} The neighbors of the cell at the given position. + * @abstract + */ + getNeighbors(x, y) {} + /** + * Calculate the next state of the board based on a set of rules. + * @param {!Array<!Rule>} rules The rules to apply to the board. + * @abstract + */ + calculateNextState(rules) {} + /** + * Check if a position is out of bounds. + * @param {number} x The x position of the cell. + * @param {number} y The y position of the cell. + * @return {boolean} True if the position is out of bounds, false otherwise. + * @abstract + */ + isOutOfBounds(x, y) {} + /** + * Get the grid representation of the board. + * @return {!Grid} The grid representation of the board. + * @abstract + */ + getGrid() {} + /** + * Set the grid representation of the board. + * Note that this method should be used with caution, as it can lead to + * inconsistent states if not used properly. In general, you should only use + * the default state and setCell methods to modify the board programmatically. + * @param {!Grid} grid The new grid representation of the board. + * @abstract + */ + setGrid(grid) {} + /** + * Returns the biggest width of the Grid representation of the board. + * This can be useful for downstream interfaces to initialize some UI elements + * without the need to get the whole grid, which can be expensive. + * @return {number} The width of the grid. + * @abstract + */ + getWidth() {} + /** + * Returns the biggest height of the Grid representation of the board. + * This can be useful for downstream interfaces to initialize some UI elements + * without the need to get the whole grid, which can be expensive. + * @return {number} The height of the grid. + * @abstract + */ + getHeight() {} +} diff --git a/life2/game/index.js b/life2/game/index.js index ce6b355..276e452 100644 --- a/life2/game/index.js +++ b/life2/game/index.js @@ -21,5 +21,6 @@ * @package life2 */ +export {Board, Grid} from './board'; export {Cell} from './cell'; export {Rule, RuleFunction} from './rule'; |
