Fix commit and reset actions crossing pointers by creating an action stack (will be used to send data to backend)
parent
7391d78c03
commit
10269ec448
|
|
@ -105,4 +105,8 @@ export class Cell {
|
|||
throw Error("No adjacent exit or piece available to connect to");
|
||||
}
|
||||
}
|
||||
|
||||
public removePiece() {
|
||||
this.placedPiece = undefined;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/node": "^16.18.119",
|
||||
"@types/node": "^17.0.29",
|
||||
"@types/react": "^18.3.12",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"interface": "file:../interface",
|
||||
|
|
@ -4201,9 +4201,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "16.18.119",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.119.tgz",
|
||||
"integrity": "sha512-ia7V9a2FnhUFfetng4/sRPBMTwHZUkPFY736rb1cg9AgG7MZdR97q7/nLR9om+sq5f1la9C857E0l/nrI0RiFQ==",
|
||||
"version": "17.0.29",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.29.tgz",
|
||||
"integrity": "sha512-tx5jMmMFwx7wBwq/V7OohKDVb/JwJU5qCVkeLMh1//xycAJ/ESuw9aJ9SEtlCZDYi2pBfe4JkisSoAtbOsBNAA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node-forge": {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/node": "^16.18.119",
|
||||
"@types/node": "^17.0.29",
|
||||
"@types/react": "^18.3.12",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"interface": "file:../interface",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import DiceSet from "./components/DiceSet";
|
|||
import "./GamePage.scss";
|
||||
import { buildBoard, PieceId } from "interface";
|
||||
import { DieViewProps } from "./types/DieViewProps";
|
||||
import { PlacePieceActionStack } from "./types/PlacePieceActionStack";
|
||||
|
||||
const GamePage = () => {
|
||||
const getRandomPieceId = () => {
|
||||
|
|
@ -71,15 +72,19 @@ const GamePage = () => {
|
|||
return dice.concat(specialDice).find((die) => matcher(die));
|
||||
};
|
||||
|
||||
const [storedBoard, setStoredBoard] = useState(buildBoard());
|
||||
const [board, setBoard] = useState(buildBoard());
|
||||
const [id, setId] = useState(1);
|
||||
const refreshBoardRender = () => {
|
||||
setBoard(board);
|
||||
setId(id + 1);
|
||||
};
|
||||
|
||||
const [placePieceActionStack, setPlacePieceActionStack] = useState(
|
||||
new PlacePieceActionStack(),
|
||||
);
|
||||
const resetBoard = () => {
|
||||
setBoard(storedBoard);
|
||||
placePieceActionStack.resetActions(board);
|
||||
setBoard(board);
|
||||
modifyDieState(
|
||||
() => true,
|
||||
() => {
|
||||
|
|
@ -90,7 +95,7 @@ const GamePage = () => {
|
|||
};
|
||||
const commitBoard = () => {
|
||||
if (dice.some((die) => !die.isDisabled)) return;
|
||||
setStoredBoard(board);
|
||||
placePieceActionStack.commitActions();
|
||||
setDice(getRandomDiceSet());
|
||||
setSpecialDieUsedInRound(false);
|
||||
};
|
||||
|
|
@ -105,6 +110,8 @@ const GamePage = () => {
|
|||
setSpecialDieUsedInRound={setSpecialDieUsedInRound}
|
||||
refreshBoardRender={refreshBoardRender}
|
||||
board={board}
|
||||
placePieceActionStack={placePieceActionStack}
|
||||
setPlacePieceActionStack={setPlacePieceActionStack}
|
||||
/>
|
||||
<div className="right-panel">
|
||||
<DiceSet
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Cell, CellType, directions, Exit } from "interface";
|
||||
import { Cell, CellType, directions, Exit, PieceId } from "interface";
|
||||
import "./BoardCell.scss";
|
||||
import { useState } from "react";
|
||||
import { DieViewProps } from "../types/DieViewProps";
|
||||
|
|
@ -14,6 +14,7 @@ export interface BoardCellProps {
|
|||
matcher: (die: DieViewProps) => boolean,
|
||||
) => DieViewProps | undefined;
|
||||
setSpecialDieUsedInRound: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
placePieceActionHandler: (pieceId: PieceId, rotation: number) => void;
|
||||
}
|
||||
|
||||
const BoardCell = (props: BoardCellProps) => {
|
||||
|
|
@ -23,16 +24,14 @@ const BoardCell = (props: BoardCellProps) => {
|
|||
modifyDieState,
|
||||
fetchDie,
|
||||
setSpecialDieUsedInRound,
|
||||
placePieceActionHandler,
|
||||
} = props;
|
||||
const [pieceRotationAngle, setPieceRotationAngle] = useState(0);
|
||||
const handleBoardCellClick = () => {
|
||||
const selectedDie = fetchDie((die) => die.isSelected);
|
||||
if (!selectedDie) return;
|
||||
try {
|
||||
cell.placePiece(
|
||||
selectedDie.pieceId,
|
||||
selectedDie.rotation as 0 | 90 | 180 | 270,
|
||||
);
|
||||
placePieceActionHandler(selectedDie.pieceId, selectedDie.rotation);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import { Cell } from "interface";
|
|||
import "./GameBoard.scss";
|
||||
import BoardCell from "./BoardCell";
|
||||
import { DieViewProps } from "../types/DieViewProps";
|
||||
import { PlacePieceActionStack } from "../types/PlacePieceActionStack";
|
||||
import { PlacePieceAction } from "../types/PlacePieceAction";
|
||||
|
||||
export interface GameBoardProps {
|
||||
modifyDieState: (
|
||||
|
|
@ -14,15 +16,31 @@ export interface GameBoardProps {
|
|||
setSpecialDieUsedInRound: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
refreshBoardRender: () => void;
|
||||
board: Cell[][];
|
||||
placePieceActionStack: PlacePieceActionStack;
|
||||
setPlacePieceActionStack: React.Dispatch<
|
||||
React.SetStateAction<PlacePieceActionStack>
|
||||
>;
|
||||
}
|
||||
|
||||
const GameBoard = (props: GameBoardProps) => {
|
||||
const { board } = props;
|
||||
const { board, placePieceActionStack, setPlacePieceActionStack } = props;
|
||||
|
||||
return (
|
||||
<div className="game-board">
|
||||
{board.flatMap((row) =>
|
||||
row.map((cell) => <BoardCell {...props} cell={cell} />),
|
||||
{board.flatMap((row, rowIndex) =>
|
||||
row.map((cell, colIndex) => (
|
||||
<BoardCell
|
||||
{...props}
|
||||
cell={cell}
|
||||
placePieceActionHandler={(pieceId, rotation) => {
|
||||
placePieceActionStack.executeAction(
|
||||
new PlacePieceAction(pieceId, rotation, rowIndex, colIndex),
|
||||
board,
|
||||
);
|
||||
setPlacePieceActionStack(placePieceActionStack);
|
||||
}}
|
||||
/>
|
||||
)),
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
import { Cell, PieceId } from "interface";
|
||||
|
||||
export class PlacePieceAction {
|
||||
pieceId: PieceId;
|
||||
rotation: number;
|
||||
cell: {
|
||||
row: number;
|
||||
col: number;
|
||||
};
|
||||
|
||||
constructor(pieceId: PieceId, rotation: number, row: number, col: number) {
|
||||
this.pieceId = pieceId;
|
||||
this.rotation = rotation;
|
||||
this.cell = {
|
||||
row: row,
|
||||
col: col,
|
||||
};
|
||||
}
|
||||
|
||||
do(board: Cell[][]) {
|
||||
const cell = board[this.cell.row][this.cell.col];
|
||||
cell.placePiece(this.pieceId, this.rotation as 0 | 90 | 180 | 270);
|
||||
}
|
||||
|
||||
undo(board: Cell[][]) {
|
||||
const cell = board[this.cell.row][this.cell.col];
|
||||
if (!cell.placedPiece || cell.placedPiece.id !== this.pieceId) {
|
||||
throw Error("Un-doing action error");
|
||||
}
|
||||
cell.removePiece();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
import { Cell } from "interface";
|
||||
import { PlacePieceAction } from "./PlacePieceAction";
|
||||
|
||||
export class PlacePieceActionStack {
|
||||
readonly committedActions: PlacePieceAction[] = [];
|
||||
inProgressActions: PlacePieceAction[] = [];
|
||||
|
||||
executeAction(action: PlacePieceAction, board: Cell[][]) {
|
||||
action.do(board);
|
||||
this.inProgressActions.push(action);
|
||||
}
|
||||
|
||||
undoLastAction(board: Cell[][]) {
|
||||
const lastAction = this.inProgressActions.pop();
|
||||
if (!lastAction) {
|
||||
throw Error("No in progress action to undo");
|
||||
}
|
||||
lastAction.undo(board);
|
||||
}
|
||||
|
||||
resetActions(board: Cell[][]) {
|
||||
try {
|
||||
while (true) {
|
||||
this.undoLastAction(board);
|
||||
}
|
||||
} catch (error) {
|
||||
if (
|
||||
!(error instanceof Error) ||
|
||||
error.message !== "No in progress action to undo"
|
||||
) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
commitActions() {
|
||||
this.committedActions.push(...this.inProgressActions);
|
||||
this.inProgressActions = [];
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue