docs: 온라인 보드게임 사이트 계획서 (공통 14편 + 게임 26종)
- 개요, 조사(BGA·한국 인기 보드게임·UI/UX), 아키텍처, 실시간 프로토콜, 안정성·보안, 계정, 로비·방, UI/UX, 데이터 모델, 게임 엔진, 테스트, 배포·운영, 로드맵(M0~M9), 사용자 결정 항목 - 게임별 규칙·엔진 설계·UI·테스트 체크리스트 26종 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
251
docs/games/yut.md
Normal file
251
docs/games/yut.md
Normal file
@@ -0,0 +1,251 @@
|
||||
# 윷놀이 (`yut`)
|
||||
|
||||
> 마일스톤: M4 · 인원: 최소 2 ~ 최대 4명(개인전), 팀전 4·6·8명(2팀) · 예상 시간: 약 15~25분 · 난이도: 쉬움
|
||||
|
||||
## 1. 개요
|
||||
- 윷가락 4개를 던져 나온 결과(도·개·걸·윷·모, 빽도)만큼 말을 움직여, 자기 말을 모두 먼저 판 밖으로 내보내면(날) 이기는 한국 전통 놀이. 설날·명절에 남녀노소가 함께 하는 가장 대중적인 놀이로, 규칙 설명 없이도 대부분의 한국인이 안다. 그만큼 "우리 집 규칙"이 다양하므로 기본값을 정하고 나머지는 옵션으로 연다.
|
||||
- 인원 근거: 전통 윷놀이는 2명이 겨루거나, 여러 명이 두 편으로 나뉘어(인원 제한 없음) 한다. 개인전은 화면·말 색 구분이 가능한 4명까지, 팀전은 2팀 × 최대 4명(총 8명)으로 제한한다. `minPlayers = 2`, `maxPlayers = 8`이며 개인전 5명 이상은 옵션 검증에서 막는다.
|
||||
|
||||
## 2. 모드와 옵션
|
||||
| 옵션 키 | 설명 | 선택지 | 기본값 |
|
||||
|---|---|---|---|
|
||||
| `mode` | 개인전 / 팀전 | `individual`(2~4명), `team`(4·6·8명, 2팀) | `individual` |
|
||||
| `pieces` | 한 편(개인 또는 팀)이 가진 말 수 | 2, 3, 4, 5 | 4 |
|
||||
| `stickModel` | 윷가락 확률 모델 | `realistic`(가락 하나가 평평한 면(배)이 위로 갈 확률 0.6), `fair`(0.5) | `realistic` |
|
||||
| `backdo` | 빽도 사용 여부(표시된 가락 하나만 배가 위면 1칸 뒤로) | `true`, `false`(빽도 결과를 그냥 도로 처리) | `true` |
|
||||
| `backdoFromDo` | "도" 자리(첫 칸)에 있는 말이 빽도를 받으면 | `chammeogi`(참먹이로 가서 한 바퀴 돈 것으로 침), `finish`(즉시 남) | `chammeogi` |
|
||||
| `finishRule` | 날(완주) 판정 | `pass`(참먹이를 지나야 남, 참먹이에 멈추면 아직 안 남), `reach`(참먹이에 도착만 해도 남) | `pass` |
|
||||
| `nakPercent` | 낙(윷가락이 판 밖으로 떨어짐) 확률. 0이면 낙 없음 | 0, 3, 5, 10 | 0 |
|
||||
| `backdoCaptureBonus` | 빽도로 잡아도 한 번 더 던지기를 주는지 | `true`, `false` | `true` |
|
||||
| `ranking` | 3~4명 개인전에서 1등이 나온 뒤 | `first`(1등 나오면 종료, 나머지는 진행도로 순위), `all`(꼴찌가 정해질 때까지 계속) | `first` |
|
||||
| `turnSeconds` | 행동(던지기·말 고르기) 1회당 제한 시간 | 15, 30, 60, `null`(무제한, 끊김 처리만) | 30 |
|
||||
|
||||
옵션 검증(zod `superRefine`):
|
||||
- `mode = individual`이면 인원 2~4명.
|
||||
- `mode = team`이면 인원 4, 6, 8명(짝수). 좌석 순서대로 0,2,4,6번 자리가 청팀, 1,3,5,7번 자리가 홍팀. 방장이 시작 전 좌석을 바꿔 팀을 조정한다.
|
||||
- 2명은 `individual`만 허용(1:1).
|
||||
|
||||
## 3. 구성물
|
||||
- 윷판 1개: 29개 자리(바깥 20 + 대각선 안쪽 9). 정확한 그래프는 5장 참조.
|
||||
- 윷가락 4개: 한쪽은 평평한 면(배), 반대쪽은 둥근 면(등). 그중 1개에 빽도 표시(X).
|
||||
- 말: 편마다 `pieces`개(기본 4개), 편마다 다른 색. 팀전은 팀당 한 세트.
|
||||
|
||||
## 4. 준비(셋업)
|
||||
1. 편 구성: 개인전은 각자 1편, 팀전은 2편(청팀·홍팀).
|
||||
2. 모든 말은 "대기"(판 밖, 아직 출발 안 함) 상태로 시작.
|
||||
3. 선 정하기: RNG로 첫 차례 편을 정한다(전통의 "윷 던져 높은 쪽이 선"을 대신함). 개인전 차례는 좌석 시계 방향. 팀전은 청1 → 홍1 → 청2 → 홍2 … 순으로 팀이 번갈아 가며, 팀 안에서는 좌석 순으로 돌아간다(그 팀의 다음 차례 사람이 던지고 말도 고른다).
|
||||
4. RNG 상태를 State에 저장한다.
|
||||
|
||||
## 5. 진행 규칙
|
||||
|
||||
### 5.1 윷 던지기 결과
|
||||
윷가락 4개를 각각 독립적으로 던진다. 각 가락이 배(평평한 면)가 위로 나올 확률을 `p`라 한다(`realistic` 0.6, `fair` 0.5).
|
||||
|
||||
| 결과 | 조건(배가 위인 가락 수) | 이동 | 한 번 더 | realistic(p=0.6) | fair(p=0.5) |
|
||||
|---|---|---|---|---|---|
|
||||
| 도 | 1개(표시 가락이 아닌 것) | 앞으로 1 | 아니오 | 0.1152 | 0.1875 |
|
||||
| 빽도 | 1개이고 그것이 표시 가락 | 뒤로 1 | 아니오 | 0.0384 | 0.0625 |
|
||||
| 개 | 2개 | 앞으로 2 | 아니오 | 0.3456 | 0.375 |
|
||||
| 걸 | 3개 | 앞으로 3 | 아니오 | 0.3456 | 0.25 |
|
||||
| 윷 | 4개 | 앞으로 4 | 예 | 0.1296 | 0.0625 |
|
||||
| 모 | 0개(모두 등) | 앞으로 5 | 예 | 0.0256 | 0.0625 |
|
||||
|
||||
- 계산식: 배 k개일 확률 = C(4,k)·p^k·(1−p)^(4−k). 빽도 = p·(1−p)^3, 도 = 3·p·(1−p)^3.
|
||||
- `backdo = false`이면 빽도 조건도 그냥 "도"로 처리한다(표시 가락 무시).
|
||||
- `realistic`의 0.6은 나무위키에 소개된 실제 윷 단면 모델(배가 위로 갈 확률 약 0.61, 모 약 2.3%)을 반올림한 값이다. 실제 놀이 감각(개·걸이 많고 모가 드묾)과 맞다.
|
||||
- 낙: `nakPercent > 0`이면 매 던지기마다 먼저 RNG로 낙 여부를 판정한다. 낙이면 그 던지기는 무효(결과 없음)이며, 그 던지기가 윷·모로 얻은 추가 던지기였더라도 그 전에 모아 둔 결과는 그대로 남는다. 낙 자체는 한 번 더 던지기를 주지 않는다.
|
||||
|
||||
### 5.2 윷판 그래프(정확한 정의)
|
||||
자리 ID와 전통 명칭(명칭은 지역마다 조금 다르며 UI 표기는 선택 사항):
|
||||
|
||||
| ID | 명칭 | ID | 명칭 | ID | 명칭 | ID | 명칭 |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| 0 | 참먹이(출발·도착) | 5 | 모(모서리) | 10 | 뒷모(모서리) | 15 | 찌모(모서리) |
|
||||
| 1 | 도 | 6 | 뒷도 | 11 | 찌도 | 16 | 날도 |
|
||||
| 2 | 개 | 7 | 뒷개 | 12 | 찌개 | 17 | 날개 |
|
||||
| 3 | 걸 | 8 | 뒷걸 | 13 | 찌걸 | 18 | 날걸 |
|
||||
| 4 | 윷 | 9 | 뒷윷 | 14 | 찌윷 | 19 | 날윷 |
|
||||
| 20 | 앞모도 | 21 | 앞모개 | 22 | 방(중앙) | 23 | 속윷 |
|
||||
| 24 | 속모 | 25 | 뒷모도 | 26 | 뒷모개 | 27 | 사려 |
|
||||
| 28 | 안찌 | | | | | | |
|
||||
|
||||
배치(말은 반시계 방향으로 돈다): 참먹이(0)는 오른쪽 아래 모서리, 모(5) 오른쪽 위, 뒷모(10) 왼쪽 위, 찌모(15) 왼쪽 아래.
|
||||
- 대각선 1 (모 → 찌모): 5 → 20 → 21 → 22(방) → 23 → 24 → 15
|
||||
- 대각선 2 (뒷모 → 참먹이): 10 → 25 → 26 → 22(방) → 27 → 28 → 0
|
||||
|
||||
한 칸 전진 함수 `next(node, ctx)` (ctx = 이번 이동의 출발 자리인지, 직전에 지난 자리):
|
||||
|
||||
| 현재 자리 | 이번 이동을 여기서 "출발"하는 경우 | 이동 중 "지나가는" 경우 |
|
||||
|---|---|---|
|
||||
| 대기(HOME) | 1 | - |
|
||||
| 1~4, 6~9, 11~14, 16~18 | n+1 | n+1 |
|
||||
| 19 | 0 | 0 |
|
||||
| 5 (모) | 20 (지름길) | 6 |
|
||||
| 10 (뒷모) | 25 (지름길) | 11 |
|
||||
| 15 (찌모) | 16 | 16 (지름길 없음) |
|
||||
| 20 → 21, 21 → 22 | 동일 | 동일 |
|
||||
| 22 (방) | 27 (참먹이 쪽으로 꺾음) | 직전이 21이면 23(직진), 직전이 26이면 27(직진) |
|
||||
| 23 → 24, 24 → 15 | 동일 | 동일 |
|
||||
| 25 → 26, 26 → 22 | 동일 | 동일 |
|
||||
| 27 → 28, 28 → 0 | 동일 | 동일 |
|
||||
| 0 (참먹이, 한 바퀴 돈 말) | GOAL | GOAL(`pass`) |
|
||||
|
||||
- 핵심: 모서리(모·뒷모)와 방은 그 자리에 "멈춰 있다가" 다음 이동을 시작할 때만 꺾는다. 지나가는 중이면 직진한다.
|
||||
- 방에 멈췄다가 출발하면 항상 참먹이 방향(27)으로 간다(가장 빠른 길).
|
||||
- 대기 상태의 말이 처음 들어올 때는 0을 지나는 것이 아니라 1부터 센다(도 = 1, 모 = 5).
|
||||
|
||||
### 5.3 차례 진행
|
||||
1. 던지기 단계: 현재 차례 사람이 `THROW`. 결과를 그 차례의 "모아 둔 결과" 목록(`pending`)에 넣는다.
|
||||
- 윷 또는 모가 나오면 반드시 한 번 더 던진다(던지기 단계 유지). 윷·모가 계속 나오면 계속 던진다(상한 없음).
|
||||
- 도·개·걸·빽도가 나오면(또는 낙) 던지기를 멈추고 이동 단계로 간다.
|
||||
2. 이동 단계: `pending`에서 결과 하나와 움직일 말(대기 말 또는 판 위의 말 무더기) 하나를 골라 `MOVE`. 순서는 자유. 모든 결과를 다 쓸 때까지 반복한다.
|
||||
- 대기 말은 전진 결과(도~모)로만 판에 올릴 수 있다. 빽도로는 못 올린다.
|
||||
- 어떤 결과도 둘 곳이 없으면(예: 판 위에 말이 없는데 남은 결과가 빽도뿐) 그 결과들은 자동으로 버려진다. 일부 결과만 둘 곳이 없으면, 다른 결과를 먼저 쓰게 하고 매 이동 후 다시 판정한다(예: 빽도 + 개 → 개로 말을 올린 뒤 빽도를 그 말에 쓸 수 있음).
|
||||
3. 잡기 보너스: 이동이 상대 말을 잡으면 즉시 던지기 단계로 돌아가 1번 더 던진다. 남은 `pending` 결과는 그대로 유지되고 새 결과가 추가된다. 한 번 이동으로 업힌 상대 말 여러 개를 잡아도 보너스는 1번. 한 차례에 잡기를 여러 번 하면 그때마다 1번씩.
|
||||
4. `pending`이 비고 추가 던지기도 없으면 차례 종료, 다음 편(팀전은 다음 팀의 다음 사람)으로.
|
||||
|
||||
### 5.4 이동 규칙
|
||||
- 전진 n: `next()`를 n번 적용. 중간에 GOAL에 닿으면 남은 칸은 버리고 그 말(무더기)은 "남"(완주).
|
||||
- 날 판정:
|
||||
- `pass`(기본): 한 바퀴를 돈 말이 참먹이(0)를 "지나가야" 남. 참먹이에 정확히 멈추면 아직 판 위(잡힐 수 있음). 다음 이동에서 어떤 전진 결과든 1칸만 나가도 남.
|
||||
- `reach`: 한 바퀴 돈 말이 0에 도착하는 순간 남.
|
||||
- 빽도(뒤로 1): 그 말이 바로 직전에 있던 자리로 되돌아간다(말마다 지나온 자리 기록 `trail`을 유지하고 마지막 칸을 되돌림). 방(22)처럼 들어오는 길이 둘인 자리에서도 "왔던 길"로 돌아간다.
|
||||
- 도 자리(1)에서 빽도(이 말의 기록이 [1]뿐): `backdoFromDo = chammeogi`면 참먹이(0)로 가고 "한 바퀴 돈 말"로 취급한다(다음 전진에서 바로 날 수 있음). `finish`면 즉시 남.
|
||||
- 참먹이(0)에서 빽도: 기록상 직전 자리(19 또는 28)로. 기록이 없으면 19로.
|
||||
- 빽도로 대기 말을 움직일 수는 없다.
|
||||
- 업기: 자기 편 말이 있는 자리에 멈추면 무조건 업는다(합쳐서 하나의 무더기). 이후 그 무더기는 함께 움직이고, 함께 잡히고, 함께 난다. 업힌 무더기를 일부만 떼어 움직일 수 없다. 팀전에서는 팀 말끼리 업힌다.
|
||||
- 잡기: 상대 편 말(무더기)이 있는 자리에 "멈추면" 그 말들을 모두 대기로 돌려보낸다(기록 초기화). 지나가는 것은 잡지 않는다. 참먹이(0)에 서 있는 말도 잡힌다. 대기·남은 말은 잡을 수 없다.
|
||||
- 한 자리에 서로 다른 편 말이 함께 있을 수 없다(멈추면 반드시 잡으므로).
|
||||
|
||||
### 5.5 예시
|
||||
- 예시 1(한 차례에 완주): 대기 말만 있는 상태에서 윷(4) → 모(5) → 걸(3)이 나와 `pending=[윷,모,걸]`. 모로 새 말을 올림 → 5(모)에 멈춤. 걸: 5에서 출발하므로 지름길 20 → 21 → 22(방)에 멈춤. 윷: 22에서 출발하므로 27 → 28 → 0 → GOAL(4번째 칸). 이 말은 남(`pass` 기준). 한 차례 만에 1개 완주.
|
||||
- 예시 2(방 직진): 말이 20(앞모도)에 있고 걸(3) → 21, 22를 지나 23(속윷)에 멈춤. 방을 지나갔으므로 직진해 찌모 쪽으로 간다.
|
||||
- 예시 3(빽도 + 잡기): 내 말 A가 6(뒷도), 상대 말이 5(모)에 있음. 빽도를 A에 쓰면 5로 가서 상대 말을 잡고 한 번 더 던진다(`backdoCaptureBonus=true`). A는 이제 5에 "멈춰" 있으므로 다음 이동은 지름길(20)로 들어간다.
|
||||
- 예시 4(참먹이 대기): `pass` 기준, 말이 28(안찌)에서 도(1)로 0에 멈춤 → 아직 안 남. 상대가 0에 멈추면 잡힌다. 다음 차례 도 이상이면 남.
|
||||
|
||||
## 6. 승패와 점수 계산
|
||||
- 자기 편 말 `pieces`개를 모두 낸 편이 1등. 팀전은 이긴 팀 전원이 승리.
|
||||
- 개인전 3~4명:
|
||||
- `ranking = first`: 1등이 나오는 즉시 종료. 나머지 순위는 (1) 난 말 수 많은 순, (2) "남은 거리 합"이 작은 순, (3) 그래도 같으면 공동 순위.
|
||||
- `ranking = all`: 1등이 나온 편은 빠지고 남은 편끼리 계속. 마지막 1편이 남으면 그 편이 꼴찌로 확정되며 종료.
|
||||
- 남은 거리(말 1개 기준, `pass` 규칙에서 GOAL까지 최소 칸 수 = 0까지의 거리 + 1): 대기 12, 1→11, 2→10, 3→9, 4→8, 5→7, 6→11, 7→10, 8→9, 9→8, 10→7, 11→10, 12→9, 13→8, 14→7, 15→6, 16→5, 17→4, 18→3, 19→2, 0(참먹이)→1, 20→6, 21→5, 22→4, 23→8, 24→7, 25→6, 26→5, 27→3, 28→2. 업힌 무더기는 말 수만큼 곱한다. (`reach` 규칙이면 전부 1씩 뺀다.) 이 표는 순위 판정 전용이며 이동 규칙에는 쓰이지 않는다.
|
||||
- 점수(옵션 없이 고정): 결과 화면에는 "난 말 수"와 순위만 표시한다.
|
||||
|
||||
## 7. 지역 룰 / 하우스 룰 (옵션으로 켜고 끄기)
|
||||
- 빽도 사용 여부(`backdo`), 도 자리 빽도 처리(`backdoFromDo`), 날 판정(`finishRule`), 낙(`nakPercent`), 빽도 잡기 보너스(`backdoCaptureBonus`), 순위 방식(`ranking`): 2장 표 참조.
|
||||
- 말 수 2~5개(`pieces`): 전통적으로 3~5개, 흔히 4개.
|
||||
- 지원하지 않는 변형(문서화만): 자리마다 벌칙이 있는 "함정 윷판", 방에 멈추면 어느 방향이든 고를 수 있는 규칙(우리는 항상 참먹이 쪽), 업기를 거부하는 규칙, 빽도를 다음 차례까지 저장하는 규칙. 필요하면 후속 옵션으로 추가한다.
|
||||
|
||||
## 8. 엔진 설계
|
||||
|
||||
### 8.1 상태(State)
|
||||
```ts
|
||||
type NodeId = number; // 0..28, 5.2 표
|
||||
type SideId = number; // 개인전: 좌석 인덱스, 팀전: 0=청 1=홍
|
||||
type Throw = 'do' | 'gae' | 'geol' | 'yut' | 'mo' | 'backdo';
|
||||
|
||||
interface Piece {
|
||||
id: number; // 편 내 0..pieces-1
|
||||
status: 'home' | 'board' | 'done';
|
||||
node: NodeId | null; // board일 때만
|
||||
lapped: boolean; // 참먹이(0)에 서 있을 때 "한 바퀴 돈" 말인지 (0에 있는 board 말은 항상 true)
|
||||
trail: NodeId[]; // 판에 오른 뒤 지나온 자리(빽도용). 업히면 무더기 대표의 trail을 공유 복사
|
||||
}
|
||||
|
||||
interface YutState {
|
||||
options: YutOptions;
|
||||
rng: RngState;
|
||||
players: PlayerId[]; // 좌석 순
|
||||
sideOf: Record<PlayerId, SideId>;
|
||||
sides: { id: SideId; members: PlayerId[]; pieces: Piece[]; finishedRank: number | null }[];
|
||||
turnOrder: PlayerId[]; // 개인전: 좌석 순, 팀전: 청1,홍1,청2,홍2...
|
||||
turnIndex: number; // turnOrder에서 현재 차례
|
||||
phase: 'throw' | 'move' | 'finished';
|
||||
throwsOwed: number; // 앞으로 더 던져야 하는 횟수(윷/모/잡기). throw 단계 진입 시 1
|
||||
pending: Throw[]; // 모아 둔 결과
|
||||
lastThrow: { sticks: [boolean, boolean, boolean, boolean] | null; result: Throw | 'nak' } | null;
|
||||
turnSeq: number; // 행동마다 +1 (타이머·중복 요청 방지)
|
||||
deadlineAt: number | null;
|
||||
log: GameEvent[]; // 최근 이벤트(최대 N개)
|
||||
}
|
||||
```
|
||||
- 같은 노드의 같은 편 말들이 곧 "무더기"다. 별도 스택 객체를 두지 않고 노드로 묶는다(불변식: 한 노드에는 한 편만).
|
||||
|
||||
### 8.2 액션
|
||||
| type | payload | 누가 / 언제 | 검증 조건 |
|
||||
|---|---|---|---|
|
||||
| `THROW` | 없음 | 현재 차례 사람, `phase='throw'` | `throwsOwed > 0`. 위반 시 "지금은 윷을 던질 차례가 아니에요." |
|
||||
| `MOVE` | `{ throwIndex: number; from: NodeId \| 'home' }` | 현재 차례 사람, `phase='move'` | `pending[throwIndex]` 존재. `from='home'`이면 자기 편 대기 말이 있고 결과가 빽도가 아님. `from`이 노드면 자기 편 말이 그 노드에 있음. 빽도는 판 위 말에만. 위반 시 "그 말은 움직일 수 없어요." 등 |
|
||||
| `CONCEDE` | 없음 | 아무 참가자, 언제나 | 개인전: 그 편 탈락(남은 편이 1이면 종료). 팀전: 팀원 전원이 기권해야 팀 패배(또는 방장 설정) |
|
||||
|
||||
- 팀전에서는 현재 차례인 팀원만 행동할 수 있다(같은 팀 다른 사람은 채팅·추천만).
|
||||
- `apply` 이벤트: `thrown{sticks,result}`, `nak`, `moved{side,from,to,path,count}`, `stacked`, `captured{victimSide,count}`, `finishedPieces{count}`, `discarded{throws}`, `turnChanged`, `sideFinished{rank}`, `gameOver`.
|
||||
|
||||
### 8.3 공개/비공개 정보 (view)
|
||||
- 윷놀이에는 숨겨진 정보가 없다. 모든 참가자·관전자에게 같은 View를 준다: 말 위치, `pending`, 직전 던지기의 가락 4개 앞뒷면, 차례, 남은 시간.
|
||||
- 단, `rng` 상태(시드·내부 카운터)는 절대 View에 넣지 않는다(다음 던지기 예측 가능해짐).
|
||||
- 현재 차례 사람에게만 `legalMoves: { throwIndex, from, to, captures, finishes }[]`를 추가로 계산해 넣는다(하이라이트용). 다른 사람에게도 넣어도 무방하지만 페이로드 절약을 위해 차례인 사람만.
|
||||
|
||||
### 8.4 랜덤 요소 (시드 RNG 사용 지점)
|
||||
- 첫 차례 편 결정(setup 1회).
|
||||
- `THROW`마다: (1) `nakPercent > 0`이면 `rng() < nakPercent/100`로 낙 판정, (2) 가락 4개 각각 `rng() < p`로 배/등 결정(인덱스 0이 빽도 표시 가락). 결과는 5.1 표로 매핑. 가락 단위로 뽑아야 애니메이션(어떤 가락이 뒤집혔는지)과 확률이 일치한다.
|
||||
|
||||
### 8.5 타이머·시간 초과·연결 끊김 시 자동 행동
|
||||
- `deadline`: 행동이 필요할 때마다 `now + turnSeconds`. 끊긴 사람은 차례가 오면 5초 유예 후 자동 행동.
|
||||
- `onTimeout`:
|
||||
- `phase='throw'` → `THROW`.
|
||||
- `phase='move'` → 결정적 우선순위로 하나 선택: (1) 상대를 잡는 수(잡히는 말 수 많은 것 우선), (2) 말을 내는 수, (3) 자기 말 업기, (4) 가장 뒤처진(남은 거리 큰) 말을 가장 큰 결과로 전진, (5) 대기 말 올리기. 동률이면 `throwIndex` 작은 것, `from` 노드 번호 작은 것('home' 마지막).
|
||||
- 같은 사람이 3회 연속 시간 초과되면 "자리 비움" 표시(자동 진행은 계속).
|
||||
|
||||
### 8.6 종료 조건과 결과(GameResult)
|
||||
- 어떤 편의 말이 모두 `done`이 되면 그 편 순위 확정. 6장 규칙에 따라 종료.
|
||||
```ts
|
||||
interface YutResult {
|
||||
ranking: { rank: number; players: PlayerId[]; side: SideId; finishedPieces: number; remainingDistance: number }[];
|
||||
winners: PlayerId[];
|
||||
summary: string; // 예: "청팀 승리! (4개 모두 남)"
|
||||
stats: { throws: Record<Throw | 'nak', number>; captures: Record<SideId, number> };
|
||||
}
|
||||
```
|
||||
|
||||
## 9. UI/UX
|
||||
- 모바일 세로: 위쪽 2/3에 정사각형 윷판(자리 원 지름 48px 이상, 모서리·방은 더 크게), 아래에 "모아 둔 결과" 칩(도·개·걸·윷·모·빽도, 각 64px 이상)과 큰 "윷 던지기" 버튼, 맨 아래 대기 말·난 말 표시. PC: 윷판 왼쪽, 정보 패널 오른쪽.
|
||||
- 조작: 결과 칩을 먼저 누르고 → 움직일 수 있는 말이 반짝이고 → 말을 누르면 도착 자리가 표시되고 → 다시 누르면 확정(오조작 방지 2단계). 결과가 1개이고 움직일 말이 1가지면 "자동 이동" 버튼 강조.
|
||||
- 합법 수 하이라이트: 도착 자리에 점선 경로 미리보기. 잡을 수 있으면 빨간 테두리 "잡기!", 업기면 "업기", 나면 "날!" 배지.
|
||||
- 애니메이션: 윷가락 4개가 공중에서 돌다 떨어지는 0.8초 애니메이션(서버 결과를 받은 뒤 재생, 결과 조작 불가). 말은 칸마다 통통 튀며 이동. 잡힌 말은 대기 자리로 날아감.
|
||||
- 초보자 도움말: "규칙 보기"에 그림으로 도~모, 지름길(모서리·방에 멈추면 꺾임), 업기, 잡기 설명. 힌트 옵션을 켜면 추천 수(8.5 우선순위)를 연하게 표시.
|
||||
- 접근성: 결과 칩에 글자(도/개/걸/윷/모/빽도)와 이동 칸 수(1~5, −1)를 함께. 색약 대비로 편마다 모양(원·세모·네모·별) 구분.
|
||||
|
||||
## 10. 테스트 체크리스트
|
||||
- [ ] 확률: 시드 고정 10만 회 던지기에서 realistic/fair 각 결과 빈도가 5.1 표 값 ±0.5%p 이내.
|
||||
- [ ] 윷 → 모 → 걸: 던지기 단계가 걸에서 멈추고 `pending=[yut,mo,geol]`, 순서 자유롭게 사용 가능(예시 1 그대로 재현해 1개 완주).
|
||||
- [ ] 모(5)를 지나가는 이동(4에서 걸 → 7)은 지름길로 안 꺾인다. 5에 멈췄다 출발하면 20으로 꺾인다.
|
||||
- [ ] 방(22): 21에서 지나가면 23, 26에서 지나가면 27, 22에서 출발하면 27.
|
||||
- [ ] 찌모(15)에 멈췄다 출발해도 16으로(지름길 없음).
|
||||
- [ ] `pass`: 28에서 도 → 0에 멈춤, 미완주, 상대가 0에 오면 잡힘. 다음 도 → 남. `reach`: 28에서 도 → 즉시 남.
|
||||
- [ ] 빽도는 왔던 길로: 21→22로 온 말이 빽도 → 21. 26→22로 온 말이 빽도 → 26. 빽도로 21에 간 말이 다음에 개 → 22를 지나 23(직진).
|
||||
- [ ] 도 자리 빽도: `chammeogi`면 0으로 가고 다음 개 → 남. `finish`면 즉시 남.
|
||||
- [ ] 판 위 말 없음 + `pending=[backdo]` → 결과 버려지고 차례 넘어감. `pending=[backdo, gae]` → 개로 말을 올린 뒤 빽도 사용 가능.
|
||||
- [ ] 업기: 같은 편 말 위에 멈추면 합쳐지고, 이후 한 번에 2개가 같이 이동·같이 남. 업힌 2개가 잡히면 둘 다 대기로, 잡은 쪽 보너스는 1번.
|
||||
- [ ] 잡기 보너스: 잡은 즉시 `phase='throw'`, 남은 `pending` 유지. 보너스 던지기에서 윷이 나오면 또 던짐.
|
||||
- [ ] 지나가는 칸의 상대 말은 잡히지 않는다.
|
||||
- [ ] 낙 10%: 낙이 나오면 결과 없음, 그 전에 모아 둔 윷 결과는 유지되어 이동 단계로 간다.
|
||||
- [ ] 팀전 4명: 차례 순서 청1→홍1→청2→홍2, 홍1 차례에 청2가 보낸 `MOVE`는 "지금은 다른 사람 차례예요."로 거부.
|
||||
- [ ] 개인전 3명 `ranking=all`: 1등 편이 빠진 뒤 차례 순서에서 제외되고 끝까지 진행.
|
||||
- [ ] 시간 초과: throw 단계 → 자동 던지기. move 단계에서 잡기 가능한 수가 있으면 그것을 고른다.
|
||||
- [ ] 연결 끊김: 끊긴 사람 차례에 유예 후 자동 진행, 재접속하면 즉시 현재 View 수신.
|
||||
- [ ] 정보 유출: View JSON에 `rng`, 시드, 다음 결과가 없음(직렬화 스냅샷 테스트).
|
||||
- [ ] 결정성: 같은 시드 + 같은 액션 열 → 같은 최종 State(리플레이 테스트).
|
||||
- [ ] 옵션 검증: 개인전 5명, 팀전 5명 거부.
|
||||
|
||||
## 11. 참고 자료
|
||||
- 나무위키 "윷놀이": https://namu.wiki/w/윷놀이 (가락 확률 모델, 빽도·낙·업기·잡기·지름길·참먹이 규칙과 지역 차이)
|
||||
- 한국민족문화대백과사전 "윷놀이": https://encykorea.aks.ac.kr/Article/E0042794
|
||||
- 영남일보 "윷놀이판에 담긴 한국어 문화"(윷판 29개 자리 명칭): https://www.yeongnam.com/web/view.php?key=20200129010004667
|
||||
- 모아모앙 윷놀이 규칙 정리(대각선 자리 명칭, fair 확률): https://moamoang.co.kr/yut-nori/
|
||||
- Wikipedia "Yunnori": https://en.wikipedia.org/wiki/Yunnori
|
||||
|
||||
## 12. 메모 (상표·법적 주의 등)
|
||||
- 윷놀이는 전통 민속놀이로 상표·저작권 문제가 없다. 윷판 그림·말 디자인만 자체 제작하면 된다.
|
||||
- 내기(돈 걸기) 기능은 넣지 않는다. 점수·포인트도 방 안에서만 쓰이는 표시용이다.
|
||||
- 지역마다 규칙이 달라 사용자 항의가 잦을 수 있으므로, 방 만들기 화면에 현재 적용 규칙 요약(빽도 사용, 날 판정 방식 등)을 한 줄로 보여 준다.
|
||||
Reference in New Issue
Block a user