M8: 그림 맞히기 규칙·화면·테스트
- packages/games/src/catchmind: 규칙 모듈(출제 순서·단어 풀 RNG, 고르기/그리기/공개 단계,
정답 정규화(NFKC·제로폭·끝말·초성 차단·정답 포함 차단·자모 거리 "아까워요"), multi/firstOnly 점수,
힌트 50%/75%, 신고 과반, 출제자 연결 끊김 10초, 자리 비움 건너뛰기와 "돌아왔어요", 결과 순위),
단어 740개(words.ko.json, 10개 분야·쉬움/보통, 어린이 안전), 테스트 34개(§10 전부 + 무작위 1,000판)
- 그림 스트리밍: draw 액션은 canvasOp 이벤트만 'stream' 메시지로 중계하고 view에는 개수만,
(재)접속·sync 때만 syncView로 전체 그림 기록 전송. 스트림 액션 로그는 묶어서(최대 1초) 저장
- 엔진/서버 최소 확장(하위 호환): validate(..., ctx?: {now}), isStreamAction, syncView,
disconnectGraceMs 선택 훅, ServerMessage 'stream', RoomStore.save 로그 배열 허용
- apps/web/src/games/catchmind: 캔버스 그리기(포인터·coalesced 이벤트, 색 12·굵기 4·지우개·되돌리기·
전체 지우기), 게이트웨이 한도 아래로 맞춘 배치 전송, 중간점 곡선 렌더링, 힌트 줄·시간 막대·점수판,
정답/채팅 입력과 "아까워요"·"정답!" 표시, 단어 고르기, 그림 PNG 저장, 옵션·규칙
- 등록(GAMES, 카탈로그, 화면 레지스트리, 아이콘), 방 단위 테스트 4개, E2E 계획(PC+폰 실제 그리기·맞히기)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -34,12 +34,16 @@ export interface GameDefinition<S, A, V, O> {
|
||||
actionSchema: ZodType<A>; // 서버 입력 검증(모양만), 규칙 검증은 validate
|
||||
playersFor?(options: O): { min: number; max: number }; // 모드별 인원이 다를 때
|
||||
setup(ctx: { players: PlayerId[]; options: O; rng: Rng; now: number; gameNo?: number }): S; // players는 방장 자리부터 시계 방향
|
||||
validate(state: S, actor: PlayerId, action: A): { ok: true } | { ok: false; reason: string };
|
||||
validate(state: S, actor: PlayerId, action: A, ctx?: { now: number }): { ok: true } | { ok: false; reason: string }; // now: 서버가 넘김(레이트 리밋용)
|
||||
apply(state: S, actor: PlayerId, action: A, ctx: { rng: Rng; now: number }): { state: S; events: GameEvent[] };
|
||||
view(state: S, viewer: PlayerId | null): V;
|
||||
activePlayers(state: S): PlayerId[];
|
||||
deadline?(state: S): number | null;
|
||||
timeoutPlayers?(state: S): PlayerId[]; // 마감이 적용되는 사람(기본: activePlayers)
|
||||
timeoutNotBefore?(state: S): number | null; // 자리 비움이어도 이 시각 전에는 시간 초과 처리 안 함(실시간 게임)
|
||||
disconnectGraceMs?(state: S): number | null; // 연결 끊긴 마감 대상의 유예 시간(ms), null이면 방의 graceSec
|
||||
isStreamAction?(action: A): boolean; // 그림 획처럼 잦은 행동: 이벤트만 'stream' 메시지로 중계, 저장은 묶어서
|
||||
syncView?(state: S, viewer: PlayerId | null): V; // (재)접속·sync 때 보내는 전체 view(기본: view)
|
||||
onTimeout(state: S, player: PlayerId): A;
|
||||
onLeave?(state: S, player: PlayerId): A | null; // 기권·자리 비움 처리
|
||||
result(state: S): GameResult | null;
|
||||
|
||||
Reference in New Issue
Block a user