게임 4개 원래 이름으로, .5 + NPMplus 배포 구성
- 보석 상인 → 스플렌더, 벽 쌓기 길찾기 → 쿼리도, 숫자 타일 → 루미큐브, 주사위 땅따먹기 → 부루마불 - deploy/docker-compose.proxy.yml: Caddy 없이 앱만(.5:2970), HTTPS·헤더는 NPMplus - deploy/npmplus-advanced.conf: Caddyfile과 같은 보안 헤더 - 문서: 2026-10-06 결정, 배포 7절 (e2e 구십구 0 카드 방향 버튼 반영 포함) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* 주사위 땅따먹기 판 데이터 (docs/games/marble.md §3). Pure data + price helpers, no zod,
|
||||
* 부루마불 판 데이터 (docs/games/marble.md §3). Pure data + price helpers, no zod,
|
||||
* so it stays cheap to import. Every number here is copied from the doc tables (tests compare
|
||||
* them with the §3.2 formulas).
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* 주사위 땅따먹기 computer player: buys and builds while it keeps a cash reserve against the tolls ahead, sells the
|
||||
* 부루마불 computer player: buys and builds while it keeps a cash reserve against the tolls ahead, sells the
|
||||
* cheapest thing that covers a debt, escapes the island early in the game, flies to the best square on 우주여행,
|
||||
* never proposes trades and only accepts clearly good ones.
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/** 주사위 땅따먹기 (docs/games/marble.md). Hidden info: the 행운카드 deck order (only its size is public). */
|
||||
/** 부루마불 (docs/games/marble.md). Hidden info: the 행운카드 deck order (only its size is public). */
|
||||
import type { ZodType } from 'zod';
|
||||
import { fail, ok, type GameDefinition, type GameEvent, type GameResult, type PlayerId, type Validation } from '@bg/engine';
|
||||
import {
|
||||
@@ -246,7 +246,7 @@ function spacePreview(s: MarbleState, id: PlayerId): MarbleSpacePreview[] {
|
||||
|
||||
export const marble: GameDefinition<MarbleState, MarbleAction, MarbleView, MarbleOptions> = {
|
||||
id: 'marble',
|
||||
nameKo: '주사위 땅따먹기',
|
||||
nameKo: '부루마불',
|
||||
minPlayers: 2,
|
||||
maxPlayers: 4,
|
||||
stateVersion: 1,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* 주사위 땅따먹기 상태 기계 (docs/games/marble.md §5, §8). Functions here mutate a state that
|
||||
* 부루마불 상태 기계 (docs/games/marble.md §5, §8). Functions here mutate a state that
|
||||
* `apply` has already cloned. The RNG is only used for dice (ROLL) — the deck is shuffled once in
|
||||
* setup and never again (cards go back to the bottom).
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* 벽 쌓기 길찾기 판 계산 (docs/games/quoridor.md §3, §5): 좌표, 벽 충돌, 말 이동, BFS 경로.
|
||||
* 쿼리도 판 계산 (docs/games/quoridor.md §3, §5): 좌표, 벽 충돌, 말 이동, BFS 경로.
|
||||
* 칸 (c, r) 0~8, r=0이 1행(아래). 벽 앵커 (c, r) 0~7은 칸 (c,r)(c+1,r)(c,r+1)(c+1,r+1)의 가운데 교차점.
|
||||
*/
|
||||
export type Seat = 'S' | 'W' | 'N' | 'E';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/** 벽 쌓기 길찾기 computer player: shortest path, winning step, walls a rival who is about to win. */
|
||||
/** 쿼리도 computer player: shortest path, winning step, walls a rival who is about to win. */
|
||||
import { describe, expect, test } from 'bun:test';
|
||||
import { SeededRng } from '@bg/engine';
|
||||
import { decideBotAction } from '../bots/index';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* 벽 쌓기 길찾기 computer player: step onto the goal when possible, otherwise walk the shortest path; when the
|
||||
* 쿼리도 computer player: step onto the goal when possible, otherwise walk the shortest path; when the
|
||||
* leading rival would get home first, put up the wall that delays that rival most compared to itself.
|
||||
*/
|
||||
import type { BotStrategy } from '../bots/types';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/** 벽 쌓기 길찾기 (docs/games/quoridor.md). 내부 id 'quoridor'는 화면에 보이지 않는다(§12). */
|
||||
/** 쿼리도 (docs/games/quoridor.md). 내부 id 'quoridor'는 화면에 보이지 않는다(§12). */
|
||||
import { z } from 'zod';
|
||||
import { fail, nextSeat, ok, type GameDefinition, type GameEvent, type GameResult, type PlayerId, type Rng } from '@bg/engine';
|
||||
import {
|
||||
@@ -504,7 +504,7 @@ function chargeClock(s: QuoridorState, i: number, now: number): boolean {
|
||||
|
||||
export const quoridor: GameDefinition<QuoridorState, QuoridorAction, QuoridorView, QuoridorOptions> = {
|
||||
id: 'quoridor',
|
||||
nameKo: '벽 쌓기 길찾기',
|
||||
nameKo: '쿼리도',
|
||||
minPlayers: 2,
|
||||
maxPlayers: 4,
|
||||
stateVersion: 1,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* 숫자 타일 computer player. A turn is two decisions: first one `setDraft` with the whole plan (rack-only sets, then
|
||||
* 루미큐브 computer player. A turn is two decisions: first one `setDraft` with the whole plan (rack-only sets, then
|
||||
* single tiles laid off on table / new sets), then `commit` once the view says the draft is valid. If the draft is
|
||||
* not valid (should not happen) it draws, which also throws the draft away — it never leaves a half-built draft.
|
||||
* Table sets are never rearranged beyond adding tiles to their ends.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/** 숫자 타일 (루미큐브 방식, docs/games/rummikub.md). Scores are room-only result points (§6, §12). */
|
||||
/** 루미큐브 (docs/games/rummikub.md). Scores are room-only result points (§6, §12). */
|
||||
import { z } from 'zod';
|
||||
import { fail, ok, type GameDefinition, type GameEvent, type GameResult, type PlayerId, type Rng, type Validation } from '@bg/engine';
|
||||
import {
|
||||
@@ -525,7 +525,7 @@ function describeSet(d: DraftSet, n: NormalSet | null): DraftSetView {
|
||||
|
||||
export const rummikub: GameDefinition<RummikubState, RummikubAction, RummikubView, RummikubOptions> = {
|
||||
id: 'rummikub',
|
||||
nameKo: '숫자 타일',
|
||||
nameKo: '루미큐브',
|
||||
minPlayers: 2,
|
||||
maxPlayers: 4,
|
||||
stateVersion: 1,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* 숫자 타일 (docs/games/rummikub.md §3, §5.1, §5.5): tile ids, set validation / joker interpretation,
|
||||
* 루미큐브 (docs/games/rummikub.md §3, §5.1, §5.5): tile ids, set validation / joker interpretation,
|
||||
* scoring helpers and simple "what can I play from my rack" search (hint button + random playouts).
|
||||
* Pure functions without zod so the screen can import them cheaply.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* 보석 상인 computer player: buys the best affordable card (points first, then bonuses that nobles and
|
||||
* 스플렌더 computer player: buys the best affordable card (points first, then bonuses that nobles and
|
||||
* wanted cards need); otherwise picks a target card (value per missing gem) and takes gems toward it,
|
||||
* reserving it now and then. Uses only its own view (board, nobles, its tokens / bonuses / reservations).
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* 보석 상인 component data (docs/games/splendor.md §3.1, §3.2). Kept in a separate data file so the card
|
||||
* 스플렌더 component data (docs/games/splendor.md §3.1, §3.2). Kept in a separate data file so the card
|
||||
* list can be swapped for an own list with the same structure (§12). Encoding: `<id>:<points>:<W U G R K cost digits>`.
|
||||
*/
|
||||
export const COLORS = ['W', 'U', 'G', 'R', 'K'] as const;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* 보석 상인 (스플렌더 방식, docs/games/splendor.md). Pure rules module: all randomness is in setup
|
||||
* 스플렌더 (docs/games/splendor.md). Pure rules module: all randomness is in setup
|
||||
* (turn order, nobles, decks), state is plain JSON, the view hides deck contents and blind reservations.
|
||||
*/
|
||||
import { z } from 'zod';
|
||||
@@ -656,7 +656,7 @@ function meView(s: SplendorState, me: PlayerId): SplendorMeView {
|
||||
|
||||
export const splendor: GameDefinition<SplendorState, SplendorAction, SplendorView, SplendorOptions> = {
|
||||
id: 'splendor',
|
||||
nameKo: '보석 상인',
|
||||
nameKo: '스플렌더',
|
||||
minPlayers: 2,
|
||||
maxPlayers: 4,
|
||||
stateVersion: 1,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/** Random playouts for 보석 상인 (docs/09 §7): 1,000 seeds plus a few full engine randomPlayout runs. */
|
||||
/** Random playouts for 스플렌더 (docs/09 §7): 1,000 seeds plus a few full engine randomPlayout runs. */
|
||||
import { describe, expect, test } from 'bun:test';
|
||||
import { SeededRng, randomPlayout, seedN, type PlayerId } from '@bg/engine';
|
||||
import { COLORS, NOBLES, TIERS, componentCounts, splendor, type SplendorAction, type SplendorOptions, type SplendorState, type Tokens } from './index';
|
||||
|
||||
Reference in New Issue
Block a user