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:
272
docs/games/baduk.md
Normal file
272
docs/games/baduk.md
Normal file
@@ -0,0 +1,272 @@
|
||||
# 바둑 (`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에 명시.
|
||||
- 금전·베팅 요소 없음.
|
||||
Reference in New Issue
Block a user