Allow moves to be undone
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
parent
21d940d3ea
commit
aeeff83e01
2 changed files with 83 additions and 5 deletions
|
@ -4,6 +4,7 @@ const saveGameKey = "connect-force-save";
|
|||
const newGameClass = "new-game";
|
||||
const saveGameClass = "save-game";
|
||||
const loadGameClass = "load-game";
|
||||
const undoClass = "undo-game";
|
||||
|
||||
/**
|
||||
* Gets a component which represents the specified {@link game `game`}.
|
||||
|
@ -35,6 +36,10 @@ export function App(game)
|
|||
{
|
||||
game.load(JSON.parse(localStorage.getItem(saveGameKey)));
|
||||
}
|
||||
else if (target.classList.contains(undoClass))
|
||||
{
|
||||
game.undo();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (let y = 0; y < game.board.length; y++)
|
||||
|
@ -49,7 +54,6 @@ export function App(game)
|
|||
{
|
||||
if (game.addChip(x, y))
|
||||
{
|
||||
game.state.turnCount++;
|
||||
game.draw();
|
||||
}
|
||||
}
|
||||
|
@ -141,7 +145,8 @@ export function MenuBar()
|
|||
{ className: "menu-bar" },
|
||||
[Button, ["New Game", { className: newGameClass }]],
|
||||
[Button, ["Save Game", { className: saveGameClass }]],
|
||||
[Button, ["Load Game", { className: loadGameClass }]]
|
||||
[Button, ["Load Game", { className: loadGameClass }]],
|
||||
[Button, ["Undo Last Move", { className: undoClass }]]
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,13 @@ export class Game
|
|||
*/
|
||||
static #height = 6;
|
||||
|
||||
/**
|
||||
* The previous states of the game.
|
||||
*
|
||||
* @type {IState[]}
|
||||
*/
|
||||
#previousStates = [];
|
||||
|
||||
/**
|
||||
* The state of the game.
|
||||
*
|
||||
|
@ -140,7 +147,7 @@ export class Game
|
|||
*/
|
||||
load(data)
|
||||
{
|
||||
this.#state = data;
|
||||
this.setState([], data);
|
||||
this.draw();
|
||||
}
|
||||
|
||||
|
@ -157,10 +164,27 @@ export class Game
|
|||
*/
|
||||
reset()
|
||||
{
|
||||
this.#state = State.create(Game.#width, Game.#height);
|
||||
this.setState([], State.create(Game.#width, Game.#height));
|
||||
this.draw();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverts the last move.
|
||||
*/
|
||||
undo()
|
||||
{
|
||||
this.#state = this.#previousStates.pop();
|
||||
|
||||
if (!this.#state)
|
||||
{
|
||||
this.reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.draw();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the content of the board with the current state.
|
||||
*/
|
||||
|
@ -171,6 +195,55 @@ export class Game
|
|||
SuiWeb.render([App, this], container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value located at the specified {@link path `path`} to the specified {@link value `value`}.
|
||||
*
|
||||
* @param {(keyof any)[]} path
|
||||
* The path of the value to set.
|
||||
*
|
||||
* @param {any} value
|
||||
* The value to set.
|
||||
*/
|
||||
setState(path, value)
|
||||
{
|
||||
this.#previousStates.push(this.#state);
|
||||
this.#state = { ...this.#state };
|
||||
this.#state.turnCount++;
|
||||
|
||||
if (path.length === 0)
|
||||
{
|
||||
this.#state = value;
|
||||
}
|
||||
else if (path.length === 1)
|
||||
{
|
||||
this.#state = {
|
||||
...this.#state,
|
||||
[path[0]]: value
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
let target = /** @type {any} */ (this.#state);
|
||||
|
||||
while (path.length > 1)
|
||||
{
|
||||
if (Array.isArray(target[path[0]]))
|
||||
{
|
||||
target[path[0]] = [...target[path[0]]];
|
||||
}
|
||||
else
|
||||
{
|
||||
target[path[0]] = { ...target[path[0]] };
|
||||
}
|
||||
|
||||
target = target[path[0]];
|
||||
path = path.slice(1);
|
||||
}
|
||||
|
||||
target[path[0]] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a chip to the board indicated by the {@link x `x`} and the {@link y `y`} coordinate.
|
||||
*
|
||||
|
@ -191,7 +264,7 @@ export class Game
|
|||
{
|
||||
if (this.board[i][x] === "")
|
||||
{
|
||||
this.board[i][x] = this.currentPlayer;
|
||||
this.setState(["board", i, x], this.currentPlayer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue