ConnectForce/src/js/Game.js

205 lines
4.4 KiB
JavaScript

import { App } from "./Components.js";
import { render } from "./SJDON.js";
import { State } from "./State.js";
/**
* Represents a game.
*/
export class Game
{
/**
* The number of chips required for a win.
*/
static #count = 4;
/**
* The width of the board.
*/
static #width = 7;
/**
* The height of the board.
*/
static #height = 6;
/**
* The state of the game.
*
* @type {State}
*/
#state;
/**
* The id of the element to add the board to.
*
* @type {string}
*/
id;
/**
* Initializes a new instance of the {@link Game `Game`} class.
*
* @param {string} id
* The id of the element to add the board to.
*/
constructor(id)
{
this.id = id;
this.#state = new State(Game.#width, Game.#height);
}
/**
* Gets the state of the game.
*/
get state()
{
return this.#state;
}
/**
* Gets the board of the game.
*/
get board()
{
return this.state.board;
}
/**
* Gets the current player.
*/
get currentPlayer()
{
return this.state.currentPlayer;
}
/**
* Gets the id of the player that is winning.
*
* @type {CellOwner}
*/
get winner()
{
for (let yOffset = 0; yOffset <= 1; yOffset++)
{
for (let xOffset = (yOffset === 1) ? -1 : 1; xOffset <= 1; xOffset++)
{
let lowerBound = Math.max(0, xOffset * (Game.#count - 1) * -1);
let upperBound = Math.min(Game.#width, Game.#width - (xOffset * (Game.#count - 1)));
for (let y = 0; y < (Game.#height - yOffset * (Game.#count - 1)); y++)
{
for (let x = lowerBound; x < upperBound; x++)
{
/**
* @type {CellOwner[]}
*/
let tokens = [];
for (let i = 0; i < Game.#count; i++)
{
tokens.push(this.board[y + i * yOffset][x + i * xOffset]);
}
let player = tokens[0];
if (
player !== "" &&
tokens.every((token) => token === player))
{
return player;
}
}
}
}
}
return null;
}
/**
* Dumps the state of the game.
*
* @returns {IState}
* The JSON string representing the state.
*/
dump()
{
return {
turnCount: this.state.turnCount,
board: {
...this.state.board
}
};
}
/**
* Loads the game from the specified {@link data `data`}.
*
* @param {IState} data
* The data to load.
*/
load(data)
{
this.state.turnCount = data.turnCount;
this.state.board.splice(0);
this.#state = new State(Game.#width, Game.#height);
Object.assign(this.state.board, data.board);
this.draw();
}
/**
* Initializes the game.
*/
initialize()
{
this.draw();
}
/**
* Resets the game.
*/
reset()
{
this.#state = new State(Game.#width, Game.#height);
this.draw();
}
/**
* Replaces the content of the board with the current state.
*/
draw()
{
let container = document.getElementById(this.id);
container.innerHTML = "";
render([App, this], container);
}
/**
* Adds a chip to the board indicated by the {@link x `x`} and the {@link y `y`} coordinate.
*
* @param {number} x
* The x coordinate to add the chip to.
*
* @param {number} y
* The y coordinate to add the chip to.
*
* @returns {boolean}
* A value indicating whether the chip could be added.
*/
addChip(x, y)
{
if (!this.winner)
{
for (let i = Game.#height - 1; i >= 0; i--)
{
if (this.board[i][x] === "")
{
this.board[i][x] = this.state.currentPlayer;
return true;
}
}
}
return false;
}
}