From de52499d6f2a795576755479a460d80ea18f0060 Mon Sep 17 00:00:00 2001 From: Inga Date: Tue, 19 Nov 2024 18:00:59 +0000 Subject: [PATCH] unified button logic between backend and frontend --- src/backend/components/boardgame.tsx | 27 +++++++++++++------ src/backend/main/index.tsx | 6 +++++ src/frontend/components/board-game.ts | 37 ++++++++++----------------- src/shared/display.ts | 10 ++++++++ tsconfig.json | 2 +- 5 files changed, 49 insertions(+), 33 deletions(-) diff --git a/src/backend/components/boardgame.tsx b/src/backend/components/boardgame.tsx index 5b62ef0..b397fa3 100644 --- a/src/backend/components/boardgame.tsx +++ b/src/backend/components/boardgame.tsx @@ -1,6 +1,6 @@ import { sequence } from "../../shared/array-utils.ts"; -import { BoardgameStateType, CurrentOutcome, GameRules, Player } from "../../shared/datatypes.ts"; -import { getCellDisplayData, getDisplayStates } from "../../shared/display.ts"; +import { BoardgameStateType, CurrentOutcome, GameRules } from "../../shared/datatypes.ts"; +import { ButtonValues, getButtonValues, getCellDisplayData, getDisplayStates } from "../../shared/display.ts"; const getSubmitAttributes = (key: string, targetState: BoardgameStateType) => ({ type: "submit" as const, @@ -30,15 +30,26 @@ const getCellHtml = ({ ); }; +const getGenericButtonAttributes = ( + kind: keyof ButtonValues, + { key, buttonValues }: { key: string; buttonValues: ButtonValues }, +) => ({ + ...getSubmitAttributes(key, buttonValues[kind]), + className: kind, +}); + export const getBoardgameHtml = (key: string, gameState: BoardgameStateType, rules: GameRules) => { const currentOutcome = gameState.board ? rules.getBoardOutcome(gameState.board) : CurrentOutcome.Undecided; + + const buttonValues = getButtonValues(gameState); + const gameClasses = getDisplayStates(gameState, currentOutcome); const gameActiveClassNames = Object.entries(gameClasses) .filter(([, value]) => value) .map(([name]) => name); return ( - +

Current player: {gameState.currentPlayerName} @@ -64,34 +75,34 @@ export const getBoardgameHtml = (key: string, gameState: BoardgameStateType, rul

Currently X moves are made manually.{" "} -

Currently X moves are made by computer.{" "} -

Currently O moves are made manually.{" "} -

Currently O moves are made by computer.{" "} -

- diff --git a/src/backend/main/index.tsx b/src/backend/main/index.tsx index da90ab0..28ba9cf 100644 --- a/src/backend/main/index.tsx +++ b/src/backend/main/index.tsx @@ -13,6 +13,11 @@ export const mainPageHandler: RequestHandler = (req, res) => { return; } + const board2 = handleBoardgame(req, res, "tictactoe2"); + if (!board2) { + return; + } + sendHtml( res, @@ -68,6 +73,7 @@ export const mainPageHandler: RequestHandler = (req, res) => {

{board1}
+
{board2}
, ); diff --git a/src/frontend/components/board-game.ts b/src/frontend/components/board-game.ts index 916ea3f..9ae050d 100644 --- a/src/frontend/components/board-game.ts +++ b/src/frontend/components/board-game.ts @@ -1,7 +1,7 @@ import { BoardgameState } from "../../shared/boardgame-state.ts"; import { getTargetGameState } from "../../shared/boardgame.ts"; -import { CurrentOutcome, Player } from "../../shared/datatypes.ts"; -import { getCellDisplayData, getDisplayStates } from "../../shared/display.ts"; +import { CurrentOutcome } from "../../shared/datatypes.ts"; +import { ButtonValues, getButtonValues, getCellDisplayData, getDisplayStates } from "../../shared/display.ts"; import { gamesRules } from "../../shared/rules.ts"; import { replaceLocation } from "../lib/navigation-utils.ts"; import { TrackingTools } from "../lib/query-tracking-utils.ts"; @@ -24,37 +24,26 @@ export class BoardGameComponent extends HTMLElement { return; } - const currentOutcome = gameState.board ? rules.getBoardOutcome(gameState.board) : CurrentOutcome.Undecided; - - const displayStates = getDisplayStates(gameState, currentOutcome); - for (const [className, shouldEnable] of Object.entries(displayStates)) { - this.classList.toggle(className, shouldEnable); - } - for (const playerNameElement of this.querySelectorAll(".current-player-name")) { if ((playerNameElement as HTMLElement).innerText !== gameState.currentPlayerName) { (playerNameElement as HTMLElement).innerText = gameState.currentPlayerName; } } - for (const button of this.querySelectorAll("button.autoplayer-x-enable")) { - (button as HTMLButtonElement).value = gameState.withAutoPlayer(Player.X).serialize(); - } - - for (const button of this.querySelectorAll("button.autoplayer-x-disable")) { - (button as HTMLButtonElement).value = gameState.withoutAutoPlayer(Player.X).serialize(); - } - - for (const button of this.querySelectorAll("button.autoplayer-o-enable")) { - (button as HTMLButtonElement).value = gameState.withAutoPlayer(Player.O).serialize(); + const buttonValues = getButtonValues(gameState); + for (const button of this.querySelectorAll("button")) { + for (const className of button.classList) { + if (Object.hasOwn(buttonValues, className)) { + button.value = buttonValues[className as keyof ButtonValues].serialize(); + } + } } - for (const button of this.querySelectorAll("button.autoplayer-o-disable")) { - (button as HTMLButtonElement).value = gameState.withoutAutoPlayer(Player.O).serialize(); - } + const currentOutcome = gameState.board ? rules.getBoardOutcome(gameState.board) : CurrentOutcome.Undecided; - for (const button of this.querySelectorAll("button.game-start")) { - (button as HTMLButtonElement).value = gameState.withEmptyBoard().serialize(); + const displayStates = getDisplayStates(gameState, currentOutcome); + for (const [className, shouldEnable] of Object.entries(displayStates)) { + this.classList.toggle(className, shouldEnable); } for (const tbodyUntyped of this.querySelectorAll("tbody.game-board")) { diff --git a/src/shared/display.ts b/src/shared/display.ts index 00e8a2e..1729941 100644 --- a/src/shared/display.ts +++ b/src/shared/display.ts @@ -43,3 +43,13 @@ export const getCellDisplayData = ({ text: formatSquareState(squareState), }; }; + +export const getButtonValues = (gameState: BoardgameStateType) => ({ + "autoplayer-x-enable": gameState.withAutoPlayer(Player.X), + "autoplayer-x-disable": gameState.withoutAutoPlayer(Player.X), + "autoplayer-o-enable": gameState.withAutoPlayer(Player.O), + "autoplayer-o-disable": gameState.withoutAutoPlayer(Player.O), + "game-start": gameState.withEmptyBoard(), +}); + +export type ButtonValues = ReturnType; diff --git a/tsconfig.json b/tsconfig.json index 3c08298..388bb0b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,6 +8,6 @@ "jsxImportSource": "preact", "module": "NodeNext", "noEmit": true, - "target": "ES2020" + "target": "ES2022" } }