diff --git a/src/backend/components/boardgame.tsx b/src/backend/components/boardgame.tsx index 7392f12..8e15226 100644 --- a/src/backend/components/boardgame.tsx +++ b/src/backend/components/boardgame.tsx @@ -1,7 +1,7 @@ -import { sequence } from "../../shared/array-utils.ts"; -import { BoardgameStateType, CurrentOutcome } from "../../shared/datatypes.ts"; +import { sequence } from "../../shared/utils/array-utils.ts"; +import { BoardgameStateType, CurrentOutcome } from "../../shared/datatypes/types.ts"; import { ButtonValues, getButtonValues, getCellDisplayData, getDisplayStates } from "../../shared/display.ts"; -import { GameVariantName, gamesRules } from "../../shared/rules.ts"; +import { GameVariantName, gamesRules } from "../../shared/game-variants/index.ts"; const getSubmitAttributes = (key: string, targetState: BoardgameStateType) => ({ type: "submit" as const, diff --git a/src/backend/components/counter.tsx b/src/backend/components/counter.tsx new file mode 100644 index 0000000..f1e8097 --- /dev/null +++ b/src/backend/components/counter.tsx @@ -0,0 +1,22 @@ +import type { Request } from "express"; +import { safeGetQueryValue } from "../utils.ts"; + +export const getCounterHtml = (req: Request, key: string) => { + const counter = parseInt(safeGetQueryValue(req, "a") ?? "0", 10); + return ( + <> +
+ {" "} + +
{" "} + Value of "{key}":{" "} + + {counter} + + + ); +}; diff --git a/src/backend/main/boardgame-handler.ts b/src/backend/main/boardgame-handler.ts index d78397e..6d70453 100644 --- a/src/backend/main/boardgame-handler.ts +++ b/src/backend/main/boardgame-handler.ts @@ -1,9 +1,9 @@ import type { Request, Response } from "express"; import { rewriteQueryParamsWith, safeGetQueryValue } from "../utils.ts"; -import { BoardgameState } from "../../shared/boardgame-state.ts"; +import { BoardgameState } from "../../shared/datatypes/boardgame-state.ts"; import { getBoardgameHtml } from "../components/boardgame.tsx"; -import { GameVariantName, gamesRules } from "../../shared/rules.ts"; -import { getTargetGameState } from "../../shared/boardgame.ts"; +import { GameVariantName, gamesRules } from "../../shared/game-variants/index.ts"; +import { getTargetGameState } from "../../shared/gameplay/boardgame.ts"; // Returns nothing if query parameter is uninitialized and a redirect was made, // or component if query parameter is initialized. diff --git a/src/backend/main/index.tsx b/src/backend/main/index.tsx index 3fe1f92..bc7bd3f 100644 --- a/src/backend/main/index.tsx +++ b/src/backend/main/index.tsx @@ -1,15 +1,13 @@ import type { RequestHandler } from "express"; -import { safeGetQueryValue, sendHtml } from "../utils.ts"; +import { sendHtml } from "../utils.ts"; import { handleBoardgame } from "./boardgame-handler.ts"; +import { getCounterHtml } from "../components/counter.tsx"; export const mainPageHandler: RequestHandler = (req, res) => { - const counters = { - a: parseInt(safeGetQueryValue(req, "a") ?? "0", 10), - b: parseInt(safeGetQueryValue(req, "b") ?? "0", 10), - }; - const board1 = handleBoardgame(req, res, "tictactoe1", "tictactoe"); if (!board1) { + // No return value from handleBoardgame means that it redirected user to another URL, + // and we no longer need to render anything. return; } @@ -40,36 +38,8 @@ export const mainPageHandler: RequestHandler = (req, res) => { supports history navigation (you can go back & forward and see how the state changes).

{board1}
diff --git a/src/frontend/components/board-game.ts b/src/frontend/components/board-game.ts index cbf553d..4a4eeff 100644 --- a/src/frontend/components/board-game.ts +++ b/src/frontend/components/board-game.ts @@ -1,11 +1,11 @@ -import { BoardgameState } from "../../shared/boardgame-state.ts"; -import { getTargetGameState } from "../../shared/boardgame.ts"; -import { CurrentOutcome } from "../../shared/datatypes.ts"; +import { BoardgameState } from "../../shared/datatypes/boardgame-state.ts"; +import { getTargetGameState } from "../../shared/gameplay/boardgame.ts"; +import { CurrentOutcome } from "../../shared/datatypes/types.ts"; import { ButtonValues, getButtonValues, getCellDisplayData, getDisplayStates } from "../../shared/display.ts"; -import { GameVariantName, gamesRules } from "../../shared/rules.ts"; -import { replaceLocation } from "../lib/navigation-utils.ts"; -import { TrackingTools } from "../lib/query-tracking-utils.ts"; -import { updateWithQueryParams } from "../lib/url-utils.ts"; +import { GameVariantName, gamesRules } from "../../shared/game-variants/index.ts"; +import { replaceLocation } from "../utils/navigation-utils.ts"; +import { TrackingTools } from "../utils/query-tracking-utils.ts"; +import { updateWithQueryParams } from "../utils/url-utils.ts"; export class BoardGameComponent extends HTMLElement { private readonly trackingTools = new TrackingTools(this); diff --git a/src/frontend/components/progressive-form.ts b/src/frontend/components/progressive-form.ts index dce7a65..e7f998f 100644 --- a/src/frontend/components/progressive-form.ts +++ b/src/frontend/components/progressive-form.ts @@ -1,5 +1,5 @@ -import { goToLocation } from "../lib/navigation-utils.ts"; -import { updateWithQueryParams } from "../lib/url-utils.ts"; +import { goToLocation } from "../utils/navigation-utils.ts"; +import { updateWithQueryParams } from "../utils/url-utils.ts"; const submitListener = function (this: HTMLFormElement, e: SubmitEvent) { goToLocation(updateWithQueryParams(new URL(this.action), new FormData(this, e.submitter))); diff --git a/src/frontend/components/reactive-button.ts b/src/frontend/components/reactive-button.ts index da1f59b..faed76c 100644 --- a/src/frontend/components/reactive-button.ts +++ b/src/frontend/components/reactive-button.ts @@ -1,4 +1,4 @@ -import { TrackingTools } from "../lib/query-tracking-utils.ts"; +import { TrackingTools } from "../utils/query-tracking-utils.ts"; export class ReactiveButton extends HTMLButtonElement { private readonly trackingTools = new TrackingTools(this); diff --git a/src/frontend/components/reactive-span.ts b/src/frontend/components/reactive-span.ts index 8f68cb3..f930971 100644 --- a/src/frontend/components/reactive-span.ts +++ b/src/frontend/components/reactive-span.ts @@ -1,4 +1,4 @@ -import { TrackingTools } from "../lib/query-tracking-utils.ts"; +import { TrackingTools } from "../utils/query-tracking-utils.ts"; export class ReactiveSpan extends HTMLSpanElement { private readonly trackingTools = new TrackingTools(this); diff --git a/src/frontend/lib/navigation-utils.ts b/src/frontend/utils/navigation-utils.ts similarity index 100% rename from src/frontend/lib/navigation-utils.ts rename to src/frontend/utils/navigation-utils.ts diff --git a/src/frontend/lib/query-tracking-utils.ts b/src/frontend/utils/query-tracking-utils.ts similarity index 100% rename from src/frontend/lib/query-tracking-utils.ts rename to src/frontend/utils/query-tracking-utils.ts diff --git a/src/frontend/lib/url-utils.ts b/src/frontend/utils/url-utils.ts similarity index 100% rename from src/frontend/lib/url-utils.ts rename to src/frontend/utils/url-utils.ts diff --git a/src/shared/board.spec.ts b/src/shared/datatypes/board.spec.ts similarity index 99% rename from src/shared/board.spec.ts rename to src/shared/datatypes/board.spec.ts index 2b027ef..f754f9e 100644 --- a/src/shared/board.spec.ts +++ b/src/shared/datatypes/board.spec.ts @@ -1,7 +1,7 @@ import t, { type Test } from "tap"; import { Board } from "./board.ts"; -import { SquareState } from "./datatypes.ts"; +import { SquareState } from "./types.ts"; void t.test("Serialize / deserialize", async (t) => { const createAndCheckBoard = (t: Test, serialized: string) => { diff --git a/src/shared/board.ts b/src/shared/datatypes/board.ts similarity index 96% rename from src/shared/board.ts rename to src/shared/datatypes/board.ts index e7e6327..40885af 100644 --- a/src/shared/board.ts +++ b/src/shared/datatypes/board.ts @@ -1,5 +1,5 @@ -import { repeat } from "./array-utils.ts"; -import { BoardType, SquareState, formatSquareState, parseSquareState } from "./datatypes.ts"; +import { repeat } from "../utils/array-utils.ts"; +import { BoardType, SquareState, formatSquareState, parseSquareState } from "./types.ts"; export class Board implements BoardType { // State should be immutable diff --git a/src/shared/boardgame-state.spec.ts b/src/shared/datatypes/boardgame-state.spec.ts similarity index 99% rename from src/shared/boardgame-state.spec.ts rename to src/shared/datatypes/boardgame-state.spec.ts index b056cee..a516120 100644 --- a/src/shared/boardgame-state.spec.ts +++ b/src/shared/datatypes/boardgame-state.spec.ts @@ -1,7 +1,7 @@ import t, { type Test } from "tap"; import { BoardgameState } from "./boardgame-state.ts"; -import { Player, SquareState } from "./datatypes.ts"; +import { Player, SquareState } from "./types.ts"; const createAndCheckBoardgameState = (t: Test, serialized: string) => { const boardgameState = BoardgameState.fromSerialized(serialized); diff --git a/src/shared/boardgame-state.ts b/src/shared/datatypes/boardgame-state.ts similarity index 98% rename from src/shared/boardgame-state.ts rename to src/shared/datatypes/boardgame-state.ts index 13c5553..71ca590 100644 --- a/src/shared/boardgame-state.ts +++ b/src/shared/datatypes/boardgame-state.ts @@ -1,4 +1,4 @@ -import { compact } from "./array-utils.ts"; +import { compact } from "../utils/array-utils.ts"; import { Board } from "./board.ts"; import { BoardType, @@ -9,7 +9,7 @@ import { getNextPlayer, getOccupiedStateByPlayer, parsePlayer, -} from "./datatypes.ts"; +} from "./types.ts"; const parseDimensions = (dimensionsSerialized: string | undefined) => { if (!dimensionsSerialized) { diff --git a/src/shared/datatypes.spec.ts b/src/shared/datatypes/datatypes.spec.ts similarity index 99% rename from src/shared/datatypes.spec.ts rename to src/shared/datatypes/datatypes.spec.ts index a506cad..e65bbd3 100644 --- a/src/shared/datatypes.spec.ts +++ b/src/shared/datatypes/datatypes.spec.ts @@ -13,7 +13,7 @@ import { getUndesiredFinalOutcomeByPlayer, parsePlayer, parseSquareState, -} from "./datatypes.ts"; +} from "./types.ts"; // These unit tests are mostly useless because they're basically a tautology, // a rephrasing of implementation in slightly different words. diff --git a/src/shared/datatypes.ts b/src/shared/datatypes/types.ts similarity index 98% rename from src/shared/datatypes.ts rename to src/shared/datatypes/types.ts index 78120d2..36c0953 100644 --- a/src/shared/datatypes.ts +++ b/src/shared/datatypes/types.ts @@ -1,4 +1,4 @@ -import { unreachableString } from "./utils.ts"; +import { unreachableString } from "../utils/utils.ts"; export enum SquareState { Unoccupied = 1, // so that all SquareState values are truthy diff --git a/src/shared/display.ts b/src/shared/display.ts index 1729941..a75028d 100644 --- a/src/shared/display.ts +++ b/src/shared/display.ts @@ -1,4 +1,4 @@ -import { BoardgameStateType, CurrentOutcome, Player, SquareState, formatSquareState } from "./datatypes.ts"; +import { BoardgameStateType, CurrentOutcome, Player, SquareState, formatSquareState } from "./datatypes/types.ts"; export const getDisplayStates = (gameState: BoardgameStateType, currentOutcome: CurrentOutcome) => ({ "outcome-winx": currentOutcome === CurrentOutcome.WinX, diff --git a/src/shared/rules.ts b/src/shared/game-variants/index.ts similarity index 100% rename from src/shared/rules.ts rename to src/shared/game-variants/index.ts diff --git a/src/shared/tictactoe-rules.spec.ts b/src/shared/game-variants/tictactoe-rules.spec.ts similarity index 98% rename from src/shared/tictactoe-rules.spec.ts rename to src/shared/game-variants/tictactoe-rules.spec.ts index 5b092cf..0caded1 100644 --- a/src/shared/tictactoe-rules.spec.ts +++ b/src/shared/game-variants/tictactoe-rules.spec.ts @@ -1,7 +1,7 @@ import t from "tap"; -import { Board } from "./board.ts"; -import { CurrentOutcome, SquareState } from "./datatypes.ts"; +import { Board } from "../datatypes/board.ts"; +import { CurrentOutcome, SquareState } from "../datatypes/types.ts"; import { getBoardOutcome, getSequenceOutcome } from "./tictactoe-rules.ts"; void t.test("getSequenceOutcome", async (t) => { diff --git a/src/shared/tictactoe-rules.ts b/src/shared/game-variants/tictactoe-rules.ts similarity index 96% rename from src/shared/tictactoe-rules.ts rename to src/shared/game-variants/tictactoe-rules.ts index 5d78975..ed3f108 100644 --- a/src/shared/tictactoe-rules.ts +++ b/src/shared/game-variants/tictactoe-rules.ts @@ -1,4 +1,4 @@ -import { CurrentOutcome, GameRules, SquareState } from "./datatypes.ts"; +import { CurrentOutcome, GameRules, SquareState } from "../datatypes/types.ts"; export const getSequenceOutcome = (sequence: SquareState[]) => { for (let i = 1; i < sequence.length; i++) { diff --git a/src/shared/tictactoe.test.ts b/src/shared/game-variants/tictactoe.test.ts similarity index 98% rename from src/shared/tictactoe.test.ts rename to src/shared/game-variants/tictactoe.test.ts index 546f9e2..dc23aa1 100644 --- a/src/shared/tictactoe.test.ts +++ b/src/shared/game-variants/tictactoe.test.ts @@ -1,9 +1,9 @@ import t, { Test } from "tap"; -import { Board } from "./board.ts"; -import { ExpectedOutcome, FinalOutcome, Opponent, Player, getOccupiedStateByPlayer } from "./datatypes.ts"; -import { createOpponent } from "./opponent.ts"; -import { computeAllSolutions } from "./solver.ts"; +import { Board } from "../datatypes/board.ts"; +import { ExpectedOutcome, FinalOutcome, Opponent, Player, getOccupiedStateByPlayer } from "../datatypes/types.ts"; +import { createOpponent } from "../gameplay/opponent.ts"; +import { computeAllSolutions } from "../gameplay/solver.ts"; import { rules } from "./tictactoe-rules.ts"; void t.test("computeAllSolutions", async (t) => { diff --git a/src/shared/boardgame.ts b/src/shared/gameplay/boardgame.ts similarity index 84% rename from src/shared/boardgame.ts rename to src/shared/gameplay/boardgame.ts index 802d1be..9655ca0 100644 --- a/src/shared/boardgame.ts +++ b/src/shared/gameplay/boardgame.ts @@ -1,5 +1,5 @@ -import { BoardgameState } from "./boardgame-state.ts"; -import { CurrentOutcome, GameRules } from "./datatypes.ts"; +import { BoardgameState } from "../datatypes/boardgame-state.ts"; +import { CurrentOutcome, GameRules } from "../datatypes/types.ts"; import { createOpponent } from "./opponent.ts"; import { getAllSolutions } from "./solver-cache.ts"; diff --git a/src/shared/opponent.spec.ts b/src/shared/gameplay/opponent.spec.ts similarity index 96% rename from src/shared/opponent.spec.ts rename to src/shared/gameplay/opponent.spec.ts index 10891a7..0e1c93c 100644 --- a/src/shared/opponent.spec.ts +++ b/src/shared/gameplay/opponent.spec.ts @@ -1,6 +1,6 @@ import t from "tap"; -import { Board } from "./board.ts"; -import { ExpectedOutcome, FinalOutcome, Player, getOccupiedStateByPlayer } from "./datatypes.ts"; +import { Board } from "../datatypes/board.ts"; +import { ExpectedOutcome, FinalOutcome, Player, getOccupiedStateByPlayer } from "../datatypes/types.ts"; import { createOpponent } from "./opponent.ts"; void t.test("createOpponent", async (t) => { diff --git a/src/shared/opponent.ts b/src/shared/gameplay/opponent.ts similarity index 97% rename from src/shared/opponent.ts rename to src/shared/gameplay/opponent.ts index be7601d..b27007a 100644 --- a/src/shared/opponent.ts +++ b/src/shared/gameplay/opponent.ts @@ -1,4 +1,4 @@ -import { ExpectedOutcome, Opponent, SquareState, getOccupiedStateByPlayer } from "./datatypes.ts"; +import { ExpectedOutcome, Opponent, SquareState, getOccupiedStateByPlayer } from "../datatypes/types.ts"; export const createOpponent = (outcomesByBoard: Map): Opponent => { const getNextMove: Opponent["getNextMove"] = (board, currentPlayer) => { diff --git a/src/shared/solver-cache.ts b/src/shared/gameplay/solver-cache.ts similarity index 92% rename from src/shared/solver-cache.ts rename to src/shared/gameplay/solver-cache.ts index 2f613be..6fa1467 100644 --- a/src/shared/solver-cache.ts +++ b/src/shared/gameplay/solver-cache.ts @@ -1,4 +1,4 @@ -import { ExpectedOutcome, GameRules } from "./datatypes.ts"; +import { ExpectedOutcome, GameRules } from "../datatypes/types.ts"; import { computeAllSolutions } from "./solver.ts"; const solverCache = new Map>>(); diff --git a/src/shared/solver.spec.ts b/src/shared/gameplay/solver.spec.ts similarity index 99% rename from src/shared/solver.spec.ts rename to src/shared/gameplay/solver.spec.ts index 78c8715..47df26e 100644 --- a/src/shared/solver.spec.ts +++ b/src/shared/gameplay/solver.spec.ts @@ -1,6 +1,6 @@ import t, { type Test } from "tap"; -import { CurrentOutcome, ExpectedOutcome, FinalOutcome, GameRules, Player, SquareState } from "./datatypes.ts"; +import { CurrentOutcome, ExpectedOutcome, FinalOutcome, GameRules, Player, SquareState } from "../datatypes/types.ts"; import { computeAllSolutions, getPreferredNextOutcome } from "./solver.ts"; void t.test("getPreferredNextOutcome", async (t) => { diff --git a/src/shared/solver.ts b/src/shared/gameplay/solver.ts similarity index 98% rename from src/shared/solver.ts rename to src/shared/gameplay/solver.ts index 8857c22..33e8c4e 100644 --- a/src/shared/solver.ts +++ b/src/shared/gameplay/solver.ts @@ -1,4 +1,4 @@ -import { Board } from "./board.ts"; +import { Board } from "../datatypes/board.ts"; import { BoardType, CurrentOutcome, @@ -13,7 +13,7 @@ import { getNextPlayer, getOccupiedStateByPlayer, getUndesiredFinalOutcomeByPlayer, -} from "./datatypes.ts"; +} from "../datatypes/types.ts"; export const getPreferredNextOutcome = ( possibleNextOutcomes: ExpectedOutcome[], diff --git a/src/shared/array-utils.spec.ts b/src/shared/utils/array-utils.spec.ts similarity index 100% rename from src/shared/array-utils.spec.ts rename to src/shared/utils/array-utils.spec.ts diff --git a/src/shared/array-utils.ts b/src/shared/utils/array-utils.ts similarity index 100% rename from src/shared/array-utils.ts rename to src/shared/utils/array-utils.ts diff --git a/src/shared/utils.ts b/src/shared/utils/utils.ts similarity index 100% rename from src/shared/utils.ts rename to src/shared/utils/utils.ts