Compare commits
No commits in common. "5ff474a7eab775a5b24b2d1cacf5e7a68d3fd7c3" and "8020d30d6b43f0680a40265a31a9a3d766280602" have entirely different histories.
5ff474a7ea
...
8020d30d6b
4 changed files with 135 additions and 150 deletions
|
@ -1,80 +0,0 @@
|
||||||
import { Constants } from "./Constants.js";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a component which represents the specified {@link game `game`}.
|
|
||||||
*
|
|
||||||
* @param {import("./Game.js").Game} game
|
|
||||||
* The game represented in this app.
|
|
||||||
*
|
|
||||||
* @returns {NodeDescriptor}
|
|
||||||
* The rendered node.
|
|
||||||
*/
|
|
||||||
export function App(game)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
"div",
|
|
||||||
[
|
|
||||||
Board,
|
|
||||||
game.board
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"div",
|
|
||||||
{ className: "log" },
|
|
||||||
game.winner ?
|
|
||||||
`Player ${Constants.PLAYER_NAMES[game.winner]} wins!` :
|
|
||||||
`It's player "${Constants.PLAYER_NAMES[game.currentPlayer]}"s turn`
|
|
||||||
]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders an element which represents the specified {@link board `board`}.
|
|
||||||
*
|
|
||||||
* @param {Board} board
|
|
||||||
* The board represented in this element.
|
|
||||||
*
|
|
||||||
* @returns {NodeDescriptor}
|
|
||||||
* The rendered element.
|
|
||||||
*/
|
|
||||||
export function Board(board)
|
|
||||||
{
|
|
||||||
let fields = board.flatMap((row) => row);
|
|
||||||
|
|
||||||
return [
|
|
||||||
"div",
|
|
||||||
{ className: "board" },
|
|
||||||
...fields.map(
|
|
||||||
(field) =>
|
|
||||||
{
|
|
||||||
return /** @type {NodeDescriptor} */([Field, field]);
|
|
||||||
}),
|
|
||||||
["div", { style: "clear: both;" }]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders an element which represents the specified {@link field `field`}.
|
|
||||||
*
|
|
||||||
* @param {CellOwner} field
|
|
||||||
* The field to represent.
|
|
||||||
*
|
|
||||||
* @returns {NodeDescriptor}
|
|
||||||
* The rendered element.
|
|
||||||
*/
|
|
||||||
export function Field(field)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
"div",
|
|
||||||
{ className: "field" },
|
|
||||||
...(
|
|
||||||
field !== "" ?
|
|
||||||
[
|
|
||||||
/** @type {NodeDescriptor} */
|
|
||||||
([
|
|
||||||
"div",
|
|
||||||
{ className: `piece ${Constants.PLAYER_NAMES[field]}` }
|
|
||||||
])
|
|
||||||
] :
|
|
||||||
[])
|
|
||||||
];
|
|
||||||
}
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { App } from "./Components.js";
|
import { Constants } from "./Constants.js";
|
||||||
|
import { elt } from "./elt.js";
|
||||||
|
import { render } from "./SJDON.js";
|
||||||
import { State } from "./State.js";
|
import { State } from "./State.js";
|
||||||
import { SuiWeb } from "./SuiWeb.js";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a game.
|
* Represents a game.
|
||||||
|
@ -29,6 +30,20 @@ export class Game
|
||||||
*/
|
*/
|
||||||
#state;
|
#state;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The actual board.
|
||||||
|
*
|
||||||
|
* @type {HTMLElement}
|
||||||
|
*/
|
||||||
|
#board;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The element containing a log message.
|
||||||
|
*
|
||||||
|
* @type {HTMLElement}
|
||||||
|
*/
|
||||||
|
#log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The id of the element to add the board to.
|
* The id of the element to add the board to.
|
||||||
*
|
*
|
||||||
|
@ -64,14 +79,6 @@ export class Game
|
||||||
return this.state.board;
|
return this.state.board;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the current player.
|
|
||||||
*/
|
|
||||||
get currentPlayer()
|
|
||||||
{
|
|
||||||
return this.state.currentPlayer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the id of the player that is winning.
|
* Gets the id of the player that is winning.
|
||||||
*
|
*
|
||||||
|
@ -152,6 +159,22 @@ export class Game
|
||||||
*/
|
*/
|
||||||
initialize()
|
initialize()
|
||||||
{
|
{
|
||||||
|
let container = document.getElementById(this.id);
|
||||||
|
|
||||||
|
this.#board = elt(
|
||||||
|
"div",
|
||||||
|
{
|
||||||
|
class: "board"
|
||||||
|
});
|
||||||
|
|
||||||
|
this.#log = elt(
|
||||||
|
"div",
|
||||||
|
{
|
||||||
|
class: "log"
|
||||||
|
});
|
||||||
|
|
||||||
|
container.appendChild(this.#board);
|
||||||
|
container.appendChild(this.#log);
|
||||||
this.draw();
|
this.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,9 +192,57 @@ export class Game
|
||||||
*/
|
*/
|
||||||
draw()
|
draw()
|
||||||
{
|
{
|
||||||
let container = document.getElementById(this.id);
|
let board = this.#board;
|
||||||
container.innerHTML = "";
|
board.innerHTML = "";
|
||||||
SuiWeb.render([App, this], container);
|
|
||||||
|
render(
|
||||||
|
[
|
||||||
|
"div",
|
||||||
|
...this.board.flatMap(
|
||||||
|
(row, y) =>
|
||||||
|
{
|
||||||
|
return row.map(
|
||||||
|
(cell, x) =>
|
||||||
|
{
|
||||||
|
return /** @type {NodeDescriptor} */ ([
|
||||||
|
"div",
|
||||||
|
{
|
||||||
|
className: "field",
|
||||||
|
onclick: () =>
|
||||||
|
{
|
||||||
|
if (this.addChip(x, y))
|
||||||
|
{
|
||||||
|
this.state.turnCount++;
|
||||||
|
this.draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
...(
|
||||||
|
cell !== "" ?
|
||||||
|
[
|
||||||
|
/** @type {NodeDescriptor} */ (["div", { className: `piece ${Constants.PLAYER_NAMES[cell]}` }])
|
||||||
|
] :
|
||||||
|
[])
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
["div", { style: "clear: both;" }]
|
||||||
|
],
|
||||||
|
board);
|
||||||
|
|
||||||
|
this.#log.innerHTML = "";
|
||||||
|
|
||||||
|
render(
|
||||||
|
[
|
||||||
|
"div",
|
||||||
|
{
|
||||||
|
className: this.state.currentPlayer
|
||||||
|
},
|
||||||
|
this.winner ?
|
||||||
|
`Player ${Constants.PLAYER_NAMES[this.winner]} wins!` :
|
||||||
|
`It's player "${Constants.PLAYER_NAMES[this.state.currentPlayer]}"s turn`
|
||||||
|
],
|
||||||
|
this.#log);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
51
src/js/SJDON.js
Normal file
51
src/js/SJDON.js
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/**
|
||||||
|
* Renders the specified {@link data `data`} and appends it to the specified {@link element `element`}.
|
||||||
|
*
|
||||||
|
* @param {NodeDescriptor} data
|
||||||
|
* The node to render written in SJDON notation.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} element
|
||||||
|
* The element to add the rendered node to.
|
||||||
|
*/
|
||||||
|
export function render(data, element)
|
||||||
|
{
|
||||||
|
if (Array.isArray(data))
|
||||||
|
{
|
||||||
|
let descriptor = data[0];
|
||||||
|
let args = data.slice(1);
|
||||||
|
|
||||||
|
if (typeof descriptor === "function")
|
||||||
|
{
|
||||||
|
render(descriptor(...args), element);
|
||||||
|
}
|
||||||
|
else if (typeof descriptor === "string")
|
||||||
|
{
|
||||||
|
let result = element.ownerDocument.createElement(descriptor);
|
||||||
|
element.appendChild(result);
|
||||||
|
|
||||||
|
for (let arg of args)
|
||||||
|
{
|
||||||
|
if (typeof arg === "object" && !Array.isArray(arg))
|
||||||
|
{
|
||||||
|
Object.assign(result, arg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
render(arg, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new SyntaxError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (typeof data === "string")
|
||||||
|
{
|
||||||
|
element.appendChild(element.ownerDocument.createTextNode(data));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new SyntaxError();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,57 +0,0 @@
|
||||||
/**
|
|
||||||
* Provides component for rendering elements written in SJDON notation.
|
|
||||||
*/
|
|
||||||
export class SuiWeb
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Renders the specified {@link data `data`} and appends it to the specified {@link element `element`}.
|
|
||||||
*
|
|
||||||
* @param {NodeDescriptor} data
|
|
||||||
* The node to render written in SJDON notation.
|
|
||||||
*
|
|
||||||
* @param {HTMLElement} element
|
|
||||||
* The element to add the rendered node to.
|
|
||||||
*/
|
|
||||||
static render(data, element)
|
|
||||||
{
|
|
||||||
if (Array.isArray(data))
|
|
||||||
{
|
|
||||||
let descriptor = data[0];
|
|
||||||
let args = data.slice(1);
|
|
||||||
|
|
||||||
if (typeof descriptor === "function")
|
|
||||||
{
|
|
||||||
SuiWeb.render(descriptor(...args), element);
|
|
||||||
}
|
|
||||||
else if (typeof descriptor === "string")
|
|
||||||
{
|
|
||||||
let result = element.ownerDocument.createElement(descriptor);
|
|
||||||
element.appendChild(result);
|
|
||||||
|
|
||||||
for (let arg of args)
|
|
||||||
{
|
|
||||||
if (typeof arg === "object" && !Array.isArray(arg))
|
|
||||||
{
|
|
||||||
Object.assign(result, arg);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SuiWeb.render(arg, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new SyntaxError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (typeof data === "string")
|
|
||||||
{
|
|
||||||
element.appendChild(element.ownerDocument.createTextNode(data));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new SyntaxError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue