Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions lefthook.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pre-commit:
commands:
check:
glob: "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}"
run: bunx @biomejs/biome check --write {staged_files} && git add {staged_files}
format:
glob: "*.{ts,tsx,json,jsonc}"
run: bunx @biomejs/biome check {staged_files} --write && git add {staged_files}
1 change: 0 additions & 1 deletion rr/app/lib/db/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export const hai = pgTable("hai", {
});

// relation between user and haiyama
// TODO: index
export const kyoku = pgTable(
"kyoku",
{
Expand Down
65 changes: 65 additions & 0 deletions rr/app/lib/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { create } from "zustand";
import type { Hai } from "./hai";
import { sortTehai } from "./hai";

interface GameState {
kyoku: number;
junme: number;
haiyama: Hai[];
sutehai: Hai[];
// Hai * 13
tehai: Hai[];
// null as an initial value
tsumohai: Hai | null;
}

interface PlayerAction {
// tsumo just after tedashi or tsumogiri
tedashi: (index: number) => void;
tsumogiri: () => void;
}

const useGameStore = create<GameState & PlayerAction>()((set, get) => ({
kyoku: 1,
junme: 1,
haiyama: [],
sutehai: [],
tehai: [],
tsumohai: null,

tedashi: (index) => {
const state = get();
if (!state.tsumohai) {
throw new Error("syohai");
}
const tsumohai = state.tsumohai;

if (index < 0 || 12 < index) {
throw new Error("index out of tehai length");
}
const deletedTehai = state.tehai.filter((_, i) => i !== index);
const discardedHai = state.tehai[index];
set(() => ({
kyoku: state.kyoku + 1,
junme: state.junme + 1,
haiyama: state.haiyama.slice(1),
sutehai: [...state.sutehai, discardedHai],
tehai: sortTehai([...deletedTehai, tsumohai]),
tsumohai: state.haiyama[0],
}));
},
tsumogiri: () => {
const state = get();
if (!state.tsumohai) {
throw new Error("syohai");
}
const tsumohai = state.tsumohai;
set(() => ({
kyoku: state.kyoku + 1,
junme: state.junme + 1,
haiyama: state.haiyama.slice(1),
sutehai: [...state.sutehai, tsumohai],
tsumohai: state.haiyama[0],
}));
},
}));
3 changes: 3 additions & 0 deletions rr/bun.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-router": "^7.9.2",
"zustand": "^5.0.8",
},
"devDependencies": {
"@cloudflare/vite-plugin": "^1.13.5",
Expand Down Expand Up @@ -753,6 +754,8 @@

"zod": ["[email protected]", "", {}, "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ=="],

"zustand": ["[email protected]", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw=="],

"@babel/core/semver": ["[email protected]", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],

"@babel/helper-compilation-targets/semver": ["[email protected]", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
Expand Down
3 changes: 2 additions & 1 deletion rr/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"pg": "^8.16.3",
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-router": "^7.9.2"
"react-router": "^7.9.2",
"zustand": "^5.0.8"
},
"devDependencies": {
"@cloudflare/vite-plugin": "^1.13.5",
Expand Down