Skip to content

Commit

Permalink
Refactor the way we define moves
Browse files Browse the repository at this point in the history
The new way is less verbose and has better type support inside the move
definitions.
  • Loading branch information
simlmx committed Jun 27, 2024
1 parent 0af00ef commit 0c59750
Show file tree
Hide file tree
Showing 17 changed files with 3,321 additions and 6,315 deletions.
2 changes: 1 addition & 1 deletion game-template/game/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
"devDependencies": {
"@lefun/core": "workspace:*",
"@lefun/game": "workspace:*",
"@rollup/plugin-typescript": "^11.1.6",
"rollup": "^4.18.0",
"rollup-plugin-typescript2": "^0.36.0",
"tslib": "^2.6.3",
"typescript": "^5.5.2"
},
Expand Down
2 changes: 1 addition & 1 deletion game-template/game/rollup.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import typescript from "@rollup/plugin-typescript";
import typescript from "rollup-plugin-typescript2";

export default {
input: "src/index.ts",
Expand Down
77 changes: 62 additions & 15 deletions game-template/game/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { UserId } from "@lefun/core";
import { createMove, GameDef, Moves, PlayerMove } from "@lefun/game";
import {
GameDef,
GameState,
PlayerMoveDef,
BoardMoveDef,
definePlayerMove,
defineBoardMove,
INIT_MOVE,
} from "@lefun/game";

type Player = {
isRolling: boolean;
Expand All @@ -11,21 +19,52 @@ export type Board = {
players: Record<UserId, Player>;
};

const [ROLL, roll] = createMove("roll");
type EmptyObject = Record<string, never>;
type GS = GameState<Board>;

const moves: Moves<Board> = {
[ROLL]: {
executeNow({ board, userId }) {
board.players[userId].isRolling = true;
},
execute({ board, userId, random }) {
board.players[userId].diceValue = random.d6();
board.players[userId].isRolling = false;
const [moveWithArgDef, moveWithArg] = definePlayerMove<GS, { someArg: string }>(
"moveWithArg",
{
execute({ board, userId, payload }) {
// execute content
},
},
};
);

const [rollDef, roll] = definePlayerMove<GS>("roll", {
executeNow({ board, userId }) {
board.players[userId].isRolling = true;
},
execute({ board, userId, random, playerboards, delayMove }) {
board.players[userId].diceValue = random.d6();
board.players[userId].isRolling = false;
delayMove(someBoardMove(), 100);
delayMove(someBoardMoveWithArgs({ someArg: 3 }), 100);
},
});

const [initMoveDef] = defineBoardMove<GS>(INIT_MOVE, {
execute({ board }) {
//
},
});

const game: GameDef<Board> = {
const [someBoardMoveDef, someBoardMove] = defineBoardMove<GS>("someboardMove", {
execute({ board }) {
//
},
});

const [someBoardMoveWithArgsDef, someBoardMoveWithArgs] = defineBoardMove<
GS,
{ someArg: number }
>("someboardMoveWithArgs", {
execute({ board, payload }) {
//
},
});

const game = {
initialBoards: ({ players }) => ({
board: {
count: 0,
Expand All @@ -34,9 +73,17 @@ const game: GameDef<Board> = {
),
},
}),
moves,
playerMoves: {
...rollDef,
...moveWithArgDef,
},
boardMoves: {
...initMoveDef,
...someBoardMoveDef,
...someBoardMoveWithArgsDef,
},
minPlayers: 1,
maxPlayers: 10,
};
} satisfies GameDef<GS>;

export { game, roll };
export { GS, game, roll, moveWithArg };
5 changes: 3 additions & 2 deletions game-template/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"main": "dist/index.js",
"types": "dist/types/index.d.ts",
"scripts": {
"build": "rm -rf ./dist && pnpm rollup --config",
"build": "rm -rf ./dist && pnpm lingui:compile && pnpm rollup --config",
"watch": "pnpm rollup --config --watch",
"dev": "pnpm vite --host",
"lingui:compile": "pnpm lingui compile",
"lingui:extract": "pnpm lingui extract"
Expand All @@ -27,7 +28,6 @@
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-commonjs": "^26.0.1",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-typescript": "^11.1.6",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
Expand All @@ -36,6 +36,7 @@
"rollup": "^4.18.0",
"rollup-plugin-copy": "^3.5.0",
"rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-typescript2": "^0.36.0",
"typescript": "^5.5.2",
"vite": "^5.3.1"
},
Expand Down
2 changes: 1 addition & 1 deletion game-template/ui/rollup.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { babel } from "@rollup/plugin-babel";
import commonjs from "@rollup/plugin-commonjs";
import { nodeResolve } from "@rollup/plugin-node-resolve";
import typescript from "@rollup/plugin-typescript";
import typescript from "rollup-plugin-typescript2";
import copy from "rollup-plugin-copy";
import postcss from "rollup-plugin-postcss";

Expand Down
31 changes: 20 additions & 11 deletions game-template/ui/src/Board.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import './index.css';
import "./index.css";

import classNames from "classnames";

Expand All @@ -7,27 +7,25 @@ import {
useUsername,
makeUseSelector,
makeUseSelectorShallow,
useDispatch,
useMakeMove,
} from "@lefun/ui";

import { Board as _Board, roll } from "roll-game";
import { GS, roll, moveWithArg } from "roll-game";

import { Trans } from "@lingui/macro";

type B = _Board;

// Dice symbol characters
const DICE = ["", "\u2680", "\u2681", "\u2682", "\u2683", "\u2684", "\u2685"];

const useSelector = makeUseSelector<B>();
const useSelectorShallow = makeUseSelectorShallow<B>();
const useSelector = makeUseSelector<GS>();
const useSelectorShallow = makeUseSelectorShallow<GS>();

function Player({ userId }: { userId: UserId }) {
const itsMe = useSelector((state) => state.userId === userId);
const username = useUsername(userId);

return (
<div className='player'>
<div className="player">
<span className={classNames(itsMe && "bold")}>{username}</span>
<Die userId={userId} />
</div>
Expand All @@ -42,11 +40,15 @@ function Die({ userId }: { userId: UserId }) {
(state) => state.board.players[userId].isRolling,
);

return <span className="dice">{isRolling || !diceValue ? "?" : DICE[diceValue]}</span>;
return (
<span className="dice">
{isRolling || !diceValue ? "?" : DICE[diceValue]}
</span>
);
}

function Board() {
const dispatch = useDispatch();
const makeMove = useMakeMove();
const players = useSelectorShallow((state) =>
Object.keys(state.board.players),
);
Expand All @@ -59,9 +61,16 @@ function Board() {
<Player key={userId} userId={userId} />
))}
</div>
<button onClick={() => dispatch(roll())}>
<button onClick={() => makeMove(roll())}>
<Trans>Roll</Trans>
</button>
<button
onClick={() => {
makeMove(moveWithArg({ someArg: "123" }));
}}
>
Go
</button>
</div>
);
}
Expand Down
4 changes: 2 additions & 2 deletions game-template/ui/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { render } from "@lefun/dev-server";
import { Board, game } from "roll-game";
import { GS, game } from "roll-game";

// @ts-expect-error abc
import { messages as en } from "./locales/en/messages";
// @ts-expect-error abc
import { messages as fr } from "./locales/fr/messages";

render<Board>({
render<GS>({
board: async () => {
const { default: Board } = await import("./Board");
// @ts-expect-error the import is there even if TS does not see it!
Expand Down
6 changes: 4 additions & 2 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ export * from "./types";

import { UserId } from "./types";

// FIXME this comment?
/*
* This is the type returned by move functions created by the game developer.
*/
export type Move<P = unknown> = {

export type AnyMove = {
name: string;
payload: P;
payload: unknown;
};

export type AkaType = "similar" | "aka" | "inspired" | "original";
Expand Down
Loading

0 comments on commit 0c59750

Please sign in to comment.