Files
joke-app/docs/games/baduk.md
EJClaw f4d63e1544 docs: 온라인 보드게임 사이트 계획서 (공통 14편 + 게임 26종)
- 개요, 조사(BGA·한국 인기 보드게임·UI/UX), 아키텍처, 실시간 프로토콜,
  안정성·보안, 계정, 로비·방, UI/UX, 데이터 모델, 게임 엔진, 테스트,
  배포·운영, 로드맵(M0~M9), 사용자 결정 항목
- 게임별 규칙·엔진 설계·UI·테스트 체크리스트 26종

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 04:18:29 +09:00

273 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 바둑 (`baduk`)
> 마일스톤: M2 · 인원: 최소 2 ~ 최대 2명 · 예상 시간: 9줄 약 10~20분, 13줄 약 30분, 19줄 약 60~120분 · 난이도: 어려움
## 1. 개요
- 흑과 백이 번갈아 교차점에 돌을 놓아 더 많은 집(영역)을 차지하는 2인 전략 게임. 한국에서 어린이 교육(바둑 학원)부터 어르신 여가까지 폭넓게 즐기며, 한국기원 규칙(일본식과 같은 계가 방식, 덤 6집 반)이 국내 표준이다.
- 인원 근거: 원작이 흑·백 2인 게임. 최소 2, 최대 2. 그 외는 관전자.
- 완전 정보 게임. 숨길 정보는 없고 서버 내부 값(RNG 상태)만 view에서 제외한다.
## 2. 모드와 옵션
| 옵션 키 | 설명 | 선택지 | 기본값 |
|---|---|---|---|
| `boardSize` | 판 크기 | `9` / `13` / `19` | `19` (방 만들기 화면에서 초보에게 9줄 추천 문구) |
| `scoring` | 계가 방식 | `territory`(한국·일본식 집 계산) / `area`(중국식 영역 계산) | `territory` |
| `komi` | 덤 (백에게 더하는 점수, 0.5 단위, -10 ~ 10) | 숫자 | 맞바둑: `territory` 6.5, `area` 7.5 / 접바둑: 0.5 |
| `handicap` | 접바둑 치석 수 (흑이 미리 놓는 돌) | 0, 2~9 (9줄은 0, 2~5) | 0 |
| `koRule` | 패 규칙 | `positionalSuperko`(동형 반복 금지) / `korean`(단순 패 + 삼패 등 장생형 반복 시 무승부) | `positionalSuperko` |
| `colorAssignment` | 흑백 결정 | `nigiri`(무작위) / `hostBlack` / `hostWhite` | `nigiri` (접바둑이면 방장이 하수/상수 지정) |
| `timeControl.kind` | 시간 방식 | `none` / `byoyomi`(기본 시간 + 초읽기) / `fischer` | `byoyomi` |
| `timeControl.mainSec` | 기본 시간 | 0 ~ 3600 | 9줄 180, 13줄 600, 19줄 1200 |
| `timeControl.periodSec` | 초읽기 1회 시간 | 10 / 20 / 30 / 60 | 30 |
| `timeControl.periods` | 초읽기 횟수 | 1 ~ 5 | 3 |
| `timeControl.incSec` | `fischer` 수당 추가 | 0 ~ 30 | 10 |
| `idleLimitSec` | `none`일 때 무응답 한도 | 300 / 600 | 600 |
| `undo` | 무르기 허용 횟수(1인당, 상대 동의) | `off` / `1` / `3` / `unlimited` | `3` |
| `drawOffer` | 무승부(빅) 합의 제안 허용 | `true` / `false` | `true` |
| `atariWarning` | 단수 경고 힌트(내 돌이 단수에 몰리면 표시) | `true` / `false` | `true` |
| `scoringDeadlineSec` | 사석 확인 단계 제한 시간 | 120 / 180 / 300 | 180 |
| `disconnectGraceSec` | 연결 끊김 유예 | 60 / 120 / 300 | 120 |
## 3. 구성물
- 판: 9×9, 13×13, 19×19 교차점. 화점(별 표시): 9줄 C3·G3·C7·G7·E5, 13줄 D4·K4·D10·K10·G7, 19줄 D4·K4·Q4·D10·K10·Q10·D16·K16·Q16.
- 좌표 표기: 열은 A부터, `I`를 건너뛴다(A B C D E F G H J K …). 행은 아래에서 위로 1부터. 내부 좌표 `(x, y)`: `x` 왼→오 0부터, `y` 위→아래 0부터.
- 흑돌·백돌: 개수 제한 없음. 따낸 돌(사석/포로) 수를 각자 센다.
## 4. 준비(셋업)
1. 흑백 결정: `nigiri`면 시드 RNG로 무작위. 접바둑이면 하수가 흑.
2. 맞바둑: 빈 판, 흑이 먼저 둔다.
3. 접바둑(`handicap = N`): 흑이 아래 고정 위치에 N개를 놓고(엔진이 자동 배치), 백이 먼저 둔다. 위치(흑 기준, 한국·일본 관례):
| N | 19줄 | 13줄 | 9줄 |
|---|---|---|---|
| 2 | Q16, D4 | K10, D4 | G7, C3 |
| 3 | + Q4 | + K4 | + G3 |
| 4 | + D16 | + D10 | + C7 |
| 5 | 4점 + K10 | 4점 + G7 | 4점 + E5 |
| 6 | 4점 + D10, Q10 | 4점 + D7, K7 | — |
| 7 | 6점 + K10 | 6점 + G7 | — |
| 8 | 4점 + D10, Q10, K4, K16 | 4점 + D7, K7, G4, G10 | — |
| 9 | 8점 + K10 | 8점 + G7 | — |
(참고: GTP 프로토콜은 3점의 세 번째 돌을 D16에 두는 등 관례가 다르다. 본 서비스는 위 표를 고정 사용한다.)
4. 덤: 맞바둑 기본 6.5(`area`는 7.5). 접바둑은 0.5(무승부 방지). `area` 접바둑은 추가로 백에게 N점 보정(중국 규칙의 치석 보정, 9.2절 참고).
5. 시계 초기화, 포로 0, `positionHistory`에 초기 국면 해시 추가.
## 5. 진행 규칙
### 5.1 턴
- 차례인 플레이어는 착수 또는 패스 중 하나를 한다.
- 용어: 연결(chain) = 상하좌우로 이어진 같은 색 돌 묶음. 활로(liberty) = 연결에 상하좌우로 맞닿은 빈 교차점.
### 5.2 착수 처리 순서 (서버)
1. 빈 교차점인지 확인.
2. 돌을 놓는다.
3. 놓은 돌에 맞닿은 상대 연결 중 활로가 0인 것을 모두 판에서 들어내고 내 포로에 더한다.
4. 놓은 돌이 속한 내 연결의 활로가 0이면 자충수(자살수) → 불법. 원상복구하고 거부.
5. 패 규칙 검사 (5.3). 위반이면 원상복구하고 거부.
6. 확정: 기보 기록, 국면 해시를 `positionHistory`에 추가, 연속 패스 카운트 0, 차례 넘김.
### 5.3 패(ko) 규칙 — 선택과 근거
- 기본값 `positionalSuperko`(동형 반복 금지): 착수 결과의 판 전체 배치(차례와 무관, 돌 색 배치만)가 이 대국에서 이전에 한 번이라도 나왔던 배치와 같으면 그 착수는 불법. 단순 패(바로 되따기 금지)는 이 규칙에 자동 포함된다.
- 근거 1: 한국기원 규칙의 삼패·사패·장생 처리("어느 쪽도 양보하지 않으면 무승부/무효")는 심판 판단이 필요한데, 온라인에서는 판정할 심판이 없고 어린이·어르신에게 "판 무효"는 납득하기 어렵다.
- 근거 2: 동형 반복 금지는 중국·AGA·뉴질랜드·Tromp-Taylor 규칙에서 쓰는 검증된 방식이고, 해시 집합 조회만으로 결정적으로 판정 가능하다. 무한 반복이 원천 봉쇄되어 서버 안정성에도 유리하다.
- 근거 3: 실전에서 단순 패 이외의 동형 반복은 극히 드물어, 한국식과 결과가 달라지는 경우가 거의 없다.
- 패스는 판을 바꾸지 않으므로 슈퍼코 검사 대상이 아니다(항상 합법).
- 옵션 `korean`: 단순 패만 금지(직전 상대 착수로 돌 1개를 따냈고 그 돌이 1점 단독 연결이며, 내가 그 자리에 두어 정확히 그 돌 하나를 되따는 경우 금지). 판 전체 배치 + 둘 차례가 같은 국면이 세 번째로 나타나면 즉시 무승부(`reason: 'repetition'`)로 종료(삼패·순환패·장생에 해당).
- 해시: 길이 `size*size` 문자열(`.`, `b`, `w`) 그대로를 Set에 저장하거나, 고정 상수 테이블의 Zobrist 64비트 해시(게임 RNG와 무관한 상수)를 쓴다. 19줄 300수 기준 문자열 방식도 약 110KB로 충분히 작다.
### 5.4 패스와 종국
- 패스는 언제나 합법. 패스가 연속 2번(흑·백 각 1번) 나오면 대국 정지 → 사석 확인 단계(`scoring`)로 전환.
- `korean`·`territory`에서 패스로 상대에게 포로를 주지 않는다(일본식처럼 패스는 무료). `area`도 마찬가지.
### 5.5 사석 확인 단계 (사활 합의)
1. 진입 시 서버가 "사석 후보"를 자동 제안한다(아래 휴리스틱). 제안은 참고용이며 최종은 합의로 정한다.
2. 두 플레이어는 연결(정확히는 같은 색의 "그룹": 같은 색 돌들 중 빈칸·상대 사석만을 거쳐 이어지는 묶음)을 탭해서 사석/생석을 토글한다. 빈 영역을 탭해서 빅(세키) 표시를 토글할 수 있다.
3. 표시가 바뀌면 양쪽 `agreed`가 모두 해제된다. 현재 표시를 기준으로 계가 미리보기가 실시간으로 갱신된다.
4. 두 플레이어가 같은 표시 상태에 대해 모두 "동의"하면 계가 확정 → 종료.
5. 어느 한쪽이 "이의 – 대국 재개"를 누르면 표시를 모두 버리고 `playing`으로 복귀한다. 재개 후 첫 수는 재개를 요청한 사람의 상대가 둔다(일본기원 규약 제9조와 같은 방식). 재개 후 다시 연속 2패스가 나오면 5.5를 다시 진행한다.
6. 사석 확인 단계에서 시계는 멈춘다. 대신 `scoringDeadlineSec` 제한이 있다(8.5).
- 자동 제안 휴리스틱(단순·결정적): (a) 활로 1개인 연결 중 그 활로에 상대가 두면 따내지고 되따기도 불가능한 것, (b) 상대 영역(상대 돌로만 둘러싸인 빈 영역)에 완전히 갇혀 있고 그 영역 안에서 두 눈(서로 떨어진 두 개 이상의 단독 빈 영역)이 없는 연결. 오판이 있어도 플레이어가 고치면 되므로 단순하게 둔다. 향후 KataGo 같은 엔진 기반 추정은 별도 작업으로 분리.
### 5.6 공배와 빅(세키)
- 공배(dame): 흑·백 양쪽 생석에 모두 닿은 빈 영역. 아무의 집도 아니다.
- 빅(세키): 서로 따낼 수 없이 공배를 공유하며 사는 형태. `territory`에서는 빅 안의 집(눈)은 집으로 세지 않는다(한국기원·일본 규칙). `area`에서는 빅의 돌과 그 눈은 해당 색 영역으로 센다.
- 빅 자동 추정(사석 확인 단계 진입 시 제안): 한 색 C의 돌로만 둘러싸인 빈 영역 R에 대해, R을 둘러싼 C 연결 중 하나라도 "R 밖의 활로가 모두 공배이고 그 공배가 상대 생석 연결의 활로이기도 한" 경우 R을 빅 후보로 표시. 플레이어가 최종 수정한다.
## 6. 승패와 점수 계산
### 6.1 계가 알고리즘 (공통 전처리)
1. 합의된 사석을 판에서 제거하고, 제거한 돌 수를 상대의 포로에 더한다(`territory`에서만 의미 있음).
2. 빈 교차점을 상하좌우 연결로 영역 분할(flood fill).
3. 각 영역의 경계 돌 색 집합을 구한다.
- 흑만 → 흑 영역, 백만 → 백 영역, 둘 다 또는 없음(빈 판) → 중립(공배).
- 빅으로 표시된 영역 → `territory`에서는 중립, `area`에서는 경계 색의 영역.
### 6.2 `territory` (한국·일본식, 기본)
- 흑 점수 = 흑 영역 교차점 수 + 흑이 따낸 돌(대국 중 + 사석)
- 백 점수 = 백 영역 교차점 수 + 백이 따낸 돌 + 덤
- 한국 기원식 실물 계가(따낸 돌로 상대 집 메우기)와 결과가 같다: `(흑집 - 백포로) - (백집 - 흑포로) = (흑집 + 흑포로) - (백집 + 백포로)`.
- 자기 집 안에 착수하면 그 점은 집이 아니게 되므로 1집 손해, 상대 집 안에 착수해 결국 사석이 되면 상대 포로 +1 — 일본식 규칙과 동일하게 자연히 반영된다.
### 6.3 `area` (중국식)
- 흑 점수 = 판 위 흑 생석 수 + 흑 영역 수
- 백 점수 = 판 위 백 생석 수 + 백 영역 수 + 덤 (+ 접바둑이면 치석 수 N)
- 포로는 세지 않는다. 공배는 아무에게도 주지 않는다(중국 규칙의 공배 나누기는 쓰지 않음; 모든 공배를 메운 결과와 같아지도록 사용자에게 "공배를 메운 뒤 패스하세요" 안내).
### 6.4 예시 (9줄)
- 흑이 E열(x=4) 전체 9개, 백이 F열(x=5) 전체 9개를 이어 판을 둘로 나눔. 흑 쪽(A~D열 36점) 안에 백 사석 1개(B5). 대국 중 흑이 따낸 돌 2개, 백이 따낸 돌 3개.
- `territory`, 덤 6.5: 흑 = 36(B5 포함) + 2 + 1 = 39, 백 = 27(G~J열) + 3 + 6.5 = 36.5 → 흑 2.5집 승.
- `area`, 덤 7.5: 흑 = 9 + 36 = 45, 백 = 9 + 27 + 7.5 = 43.5 → 흑 1.5점 승.
### 6.5 승패와 동점
- 점수가 높은 쪽 승. 표시: "흑 2집 반 승"(`territory`) / "흑 1.5점 승"(`area`).
- 덤이 정수일 때만 동점(빅/무승부, `reason: 'jigo'`) 가능. 기본 덤은 0.5 단위라 무승부 없음.
- 그 외 종료: 불계(기권, `resign`), 시간패(`timeLoss`), 무승부 합의(`drawAgreed`), `koRule=korean`의 반복 무승부(`repetition`).
## 7. 지역 룰 / 하우스 룰 (옵션으로 켜고 끄기)
- 한국기원식(기본): `territory` + 덤 6.5 + 빅 안의 집 불인정. 패 규칙만 동형 반복 금지로 단순화(5.3 근거). 순수 한국기원식을 원하면 `koRule=korean`.
- 중국식: `area` + 덤 7.5 + 접바둑 치석 보정.
- 덤 없는 바둑(친선 "맞바둑 덤 없음"): `komi = 0` (무승부 가능).
- 접바둑 자유 치석(흑이 원하는 곳에 배치)은 v1 미지원.
- 초읽기 대신 피셔 방식도 선택 가능.
## 8. 엔진 설계
### 8.1 상태(State)
```ts
type Color = 'black' | 'white';
type Cell = 0 | 1 | 2;
type Pt = { x: number; y: number };
interface BadukState {
options: BadukOptions;
size: 9 | 13 | 19;
board: Cell[]; // y*size + x
players: Record<Color, PlayerId>;
turn: Color;
phase: 'playing' | 'scoring' | 'finished';
captures: Record<Color, number>; // 각 색이 따낸 상대 돌 수(대국 중)
consecutivePasses: number;
moves: ({ kind: 'place'; color: Color; pt: Pt; captured: Pt[] } | { kind: 'pass'; color: Color })[];
positionHistory: string[]; // 슈퍼코: 착수 결과 배치 해시 (Set으로 재구성)
situationCounts: Record<string, number>; // koRule=korean: (배치+차례) 등장 횟수
koPoint: Pt | null; // koRule=korean의 단순 패 금지점
scoringMarks: {
dead: number[]; // 사석으로 표시된 교차점 index
seki: number[]; // 빅으로 표시된 빈 영역의 대표 index
agreed: Record<Color, boolean>;
startedAt: number;
resumeRequestedBy: Color | null;
} | null;
clock: {
mainMs: Record<Color, number>;
periodsLeft: Record<Color, number>;
inByoyomi: Record<Color, boolean>;
turnStartedAt: number;
};
undo: { usedBy: Record<Color, number>; pending: { by: Color; plies: 1 | 2 } | null };
draw: { pendingBy: Color | null; lastOfferMove: Record<Color, number> };
result: BadukResult | null;
rng: RngState;
}
```
### 8.2 액션
| type | payload | 누가 / 언제 | 검증 조건 |
|---|---|---|---|
| `place` | `{ x, y }` | 차례인 플레이어, `playing` | 판 안, 빈칸, 자충수 아님("둘 곳의 활로가 없어 둘 수 없어요"), 패 규칙 위반 아님("패는 바로 되따낼 수 없어요. 다른 곳에 한 수 두고 오세요" / "같은 모양이 반복되어 둘 수 없어요") |
| `pass` | `{}` | 차례인 플레이어, `playing` | 항상 가능. 연속 2회째면 `scoring` 진입 |
| `toggleDead` | `{ x, y }` | 두 플레이어, `scoring` | 그 점에 돌이 있어야 함. 해당 그룹 전체 토글, 양쪽 `agreed` 해제 |
| `toggleSeki` | `{ x, y }` | 두 플레이어, `scoring` | 빈 교차점. 해당 빈 영역 토글, `agreed` 해제 |
| `agreeScore` | `{}` | 두 플레이어, `scoring` | 본인 `agreed = true`. 둘 다 true면 계가 확정, 종료 |
| `resumePlay` | `{}` | 두 플레이어, `scoring` | 표시 초기화, `playing` 복귀, 차례 = 요청자의 상대, `consecutivePasses = 0` |
| `requestUndo` | `{}` | 플레이어, `playing` | `undo != off`, 횟수 남음, 대기 요청 없음, 본인 수(착수 또는 패스) 존재. 1수 또는 2수 |
| `respondUndo` | `{ accept }` | 상대 | 수락 시 `moves`를 처음부터 재생해서 판·포로·`positionHistory`·`koPoint` 재구성(역연산보다 안전). 시계는 되돌리지 않음 |
| `offerDraw` | `{}` | 플레이어, `playing` | `drawOffer=true`, 대기 없음, 직전 거절 이후 본인 5수 이상 |
| `respondDraw` | `{ accept }` | 상대 | 수락 → 무승부 |
| `cancelOffer` | `{}` | 요청자 | 대기 요청 취소 |
| `resign` | `{}` | 플레이어, `playing`/`scoring` | 언제든 |
| `timeout` | `{}` | 시스템 | 8.5 |
- 대기 요청은 요청받은 쪽이 `place`/`pass`를 하면 자동 거절.
- 시계 처리(`place`/`pass` 시, `byoyomi`): `elapsed = now - turnStartedAt`. 기본 시간이 남아 있으면 먼저 차감, 부족분은 초읽기에서 처리: 초읽기 1회 시간 안이면 그 회차 유지(다음 수에 다시 전체 `periodSec`), 넘기면 넘긴 만큼 회차 소진. `periodsLeft`가 0이 되는 순간 이미 시간패이므로 그 액션은 거부.
- 이벤트: `stonePlaced`(따낸 좌표 포함), `captured`, `pass`, `atari`(힌트용), `scoringStarted`, `marksChanged`, `playResumed`, `gameEnded` 등.
### 8.3 공개/비공개 정보 (view)
- 모두 공개(플레이어·관전자 동일): 판, 차례, 포로 수, 기보, 단계, 사석/빅 표시와 계가 미리보기, 양쪽 동의 여부, 시계(기본 시간, 초읽기 남은 횟수, `deadline`), 대기 중인 요청, 결과.
- 차례인 플레이어에게만 편의 정보: `illegalPoints`(패·자충으로 둘 수 없는 점), `atariWarnings`.
- view에서 제외: `rng`, `positionHistory`(크기 문제로 제외, 필요하면 기보로 재구성), `situationCounts`.
### 8.4 랜덤 요소 (시드 RNG 사용 지점)
- `colorAssignment=nigiri`의 흑백 결정 1회뿐. 대국 진행에는 RNG를 쓰지 않는다.
### 8.5 타이머·시간 초과·연결 끊김 시 자동 행동
- `deadline(state)`:
- `playing` + `byoyomi`: `turnStartedAt + mainMs[turn] + periodsLeft[turn] * periodSec*1000` (현재 회차를 다 쓰면 다음 회차가 이어지므로 이 합이 최종 시간패 시각)
- `playing` + `fischer`: `turnStartedAt + mainMs[turn]`
- `playing` + `none`: `turnStartedAt + idleLimitSec*1000`
- `scoring`: `scoringMarks.startedAt + scoringDeadlineSec*1000`
- `finished`: `null`
- `activePlayers`: `playing`이면 차례인 1명. `scoring`이면 아직 `agreed`하지 않은 플레이어 전원(동시 행동 단계).
- `onTimeout(state, player)` → `{ type: 'timeout' }`. `apply` 처리:
- `playing`: 해당 플레이어 시간패 (`timeLoss`). 바둑은 자동 착수를 하지 않는다(무작위 수는 판을 망치므로).
- `scoring`: 시간 내 합의하지 못한 플레이어는 현재 표시에 동의한 것으로 간주(`agreeScore`). 두 사람 모두 미응답이면 현재 표시대로 계가 확정. 표시가 비어 있으면 모든 돌을 생석으로 계가.
- 연결 끊김: 서버는 끊긴 플레이어가 행동해야 할 때 `min(deadline, 끊김 + disconnectGraceSec)`에 `onTimeout` 호출. 시간 제한이 긴 19줄에서도 방치가 길어지지 않게 하기 위함.
### 8.6 종료 조건과 결과(GameResult)
```ts
interface BadukResult {
ranking: { playerId: PlayerId; rank: 1 | 2 }[]; // 무승부면 둘 다 1
winner: Color | null;
reason: 'score' | 'jigo' | 'resign' | 'timeLoss' | 'drawAgreed' | 'repetition';
score?: {
method: 'territory' | 'area';
black: { territory: number; captures: number; stones: number; total: number };
white: { territory: number; captures: number; stones: number; komi: number; handicapComp: number; total: number };
margin: number; // 승자 기준 차이 (예: 2.5)
ownership: (0 | 1 | 2)[]; // 교차점별 귀속(표시용)
};
summaryKo: string; // 예: "흑 2집 반 승", "백 불계승", "흑 시간승"
}
```
## 9. UI/UX
- 모바일 세로: 상단 상대 정보(따낸 돌, 시계 + 초읽기 남은 횟수 점 3개), 가운데 정사각 판, 하단 내 정보와 버튼(패스, 무르기, 무승부, 기권, 규칙 보기).
- 19줄은 교차점 간격이 약 18px라 "탭 → 미리보기 돌 + 확대 돋보기 → 확인 버튼" 2단계 착수가 기본. 9줄은 한 번 탭 착수 옵션 제공.
- 마지막 수 표시, 따낸 돌 사라지는 애니메이션과 효과음(끌 수 있음), 단수 경고(옵션) 시 해당 연결 테두리 깜빡임.
- 패/자충 금지점을 탭하면 이유 말풍선.
- 초읽기 진입 시 음성/효과음 카운트("10, 9, …")와 화면 테두리 색 변화(어르신 배려: 큰 숫자).
- 패스 버튼은 실수 방지를 위해 확인 모달. 상대가 패스하면 "상대가 패스했어요. 끝내려면 패스하세요" 안내.
- 사석 확인 단계: 판 위에 사석은 반투명 + ×, 집은 작은 사각 표시, 하단에 "흑 39 : 백 36.5" 미리보기, 큰 "동의" / "이의(대국 재개)" 버튼. 상대가 표시를 바꾸면 바뀐 그룹을 강조.
- 규칙 보기: 따내기, 자충수, 패, 집 세는 법 그림 설명. 초보 모드에서 9줄 추천.
- 관전자: 계가 미리보기 보기 가능, 버튼 없음.
## 10. 테스트 체크리스트
- [ ] 1점 따내기, 여러 연결 동시 따내기, 가장자리·귀에서 따내기.
- [ ] 자충수 거부. 단, 놓는 순간 상대를 따내서 활로가 생기는 수는 합법.
- [ ] 단순 패: 따낸 직후 바로 되따기 거부, 다른 곳 한 수(팻감) 후 되따기 허용.
- [ ] `positionalSuperko`: 삼패 순환에서 이전 배치를 재현하는 수가 거부되는지.
- [ ] `koRule=korean`: 같은 국면(배치+차례) 3회째에 무승부 종료.
- [ ] 연속 2패스 → `scoring`. 패스-착수-패스는 진입 안 함.
- [ ] 사석 토글 후 상대가 동의해 있던 상태가 해제되는지, 두 사람 동의 시 계가 확정.
- [ ] 이의 → 재개 후 첫 수 차례가 요청자의 상대인지, 재개 후 다시 2패스 시 재진입.
- [ ] 6.4 예시 국면에서 `territory`/`area` 점수가 39 : 36.5, 45 : 43.5로 계산.
- [ ] 빅 영역: `territory`에서 빅 안 눈이 집으로 안 세어지고, `area`에서 세어짐.
- [ ] 접바둑 N=2~9 배치가 표와 일치, 백이 먼저 둠, 덤 0.5, `area`에서 백 +N 보정.
- [ ] 초읽기: 기본 시간 소진 후 30초 안에 두면 회차 유지, 넘기면 회차 감소, 마지막 회차 초과 시 시간패, 그 뒤 도착 착수 거부.
- [ ] `scoring` 단계 시간 초과 → 미응답자 자동 동의 후 계가.
- [ ] 연결 끊김 유예 후 시간패, 재접속 시 유예 해제.
- [ ] 무르기 수락 시 따낸 돌이 복원되고 포로 수·슈퍼코 이력이 재생으로 정확히 복원.
- [ ] 정보 누출: view에 `rng`, `positionHistory`, `situationCounts`가 없는지. 관전자 view에 `illegalPoints`/`atariWarnings` 없음.
- [ ] 리플레이 결정성: 같은 시드·액션 로그 → 같은 결과.
## 11. 참고 자료
- 한국기원 바둑 규칙 안내: https://www.baduk.or.kr/story/badukRule.asp
- 나무위키 「계가」: https://namu.wiki/w/%EA%B3%84%EA%B0%80 , 「삼패」: https://namu.wiki/w/%EC%82%BC%ED%8C%A8 , 「바둑/국가별 룰」: https://namu.wiki/w/%EB%B0%94%EB%91%91/%EA%B5%AD%EA%B0%80%EB%B3%84%20%EB%A3%B0
- 위키백과 「덤 (바둑)」: https://ko.wikipedia.org/wiki/%EB%8D%A4_(%EB%B0%94%EB%91%91)
- 일본기원 규약(1989) 영문: https://www.cs.cmu.edu/~wjh/go/rules/Japanese.html (사활 다툼 시 재개, 빅 안의 집 불인정)
- Sensei's Library "Superko", "Handicap placement": https://senseis.xmp.net/?Superko , https://senseis.xmp.net/?HandicapPlacement
- Tromp-Taylor 규칙(영역 계산·동형 반복 금지의 간결한 정의): https://tromp.github.io/go.html
## 12. 메모 (상표·법적 주의 등)
- "바둑", "Go", "Weiqi", "Baduk"은 전통 게임 명칭으로 상표 문제 없음. "한국기원 공인" 같은 표현은 쓰지 않는다.
- 사활 자동 추정은 보조 기능일 뿐이며, 결과는 반드시 두 플레이어의 합의로 확정된다는 점을 UI에 명시.
- 금전·베팅 요소 없음.