Files
joke-app/docs/games/chess.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

213 lines
20 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.
# 체스 (`chess`)
> 마일스톤: M2 · 인원: 최소 2 ~ 최대 2명 · 예상 시간: 블리츠 약 10분, 래피드 약 20~40분 · 난이도: 보통~어려움
## 1. 개요
- 백과 흑이 16개씩의 기물로 상대 킹을 체크메이트하면 이기는 서양 장기. 한국에서는 학교 방과후 수업과 온라인(chess.com, lichess)으로 어린이·청소년층 인지도가 높다.
- 인원 근거: 원작이 2인 게임. 최소 2, 최대 2.
- 규칙 기준: FIDE 체스 규칙(Laws of Chess, 2023년 1월 시행판). 온라인 환경에 맞춘 차이는 7장과 6장에 명시.
- 완전 정보 게임. view에서 제외할 것은 RNG 상태뿐.
## 2. 모드와 옵션
| 옵션 키 | 설명 | 선택지 | 기본값 |
|---|---|---|---|
| `variant` | 변형 | `standard` / `chess960` | `standard` |
| `timeControl` | 시간 방식(피셔: 기본 시간 + 수당 추가) | 프리셋: 블리츠 `3+2`, `5+0`, `5+3` / 래피드 `10+0`, `10+5`, `15+10` / 클래식 `30+0` / `none` / 사용자 지정(1~90분, 0~60초) | `10+5` |
| `drawMode` | 반복·50수 무승부 처리 | `auto`(3회 반복·50수 즉시 자동 무승부) / `fide`(3회 반복·50수는 클레임, 5회 반복·75수는 자동) | `auto` |
| `colorAssignment` | 백흑 결정 | `random` / `hostWhite` / `hostBlack` / `alternate` | `random` |
| `autoQueen` | 승진 시 퀸 자동 선택(설정 끄면 선택 창) | `true` / `false` | `false` (선택 창, 퀸이 첫 번째 큰 버튼) |
| `undo` | 무르기 허용 횟수(1인당, 상대 동의) | `off` / `1` / `3` / `unlimited` | `1` |
| `drawOffer` | 무승부 제안 | `true` / `false` | `true` |
| `firstMoveSec` | 첫 수 제한(넘기면 대국 취소) | 15 / 30 / 60 | 30 |
| `idleLimitSec` | `timeControl=none`일 때 무응답 한도 | 300 / 600 | 600 |
| `hints` | 초보 도움말(이동 가능 칸 표시, 공격받는 기물 경고) | `off` / `moves` / `movesAndThreats` | `moves` |
| `disconnectGraceSec` | 연결 끊김 유예 | 30 / 60 / 120 | 60 |
## 3. 구성물
- 8×8 칸(64칸), a1이 흑색 칸(백 기준 왼쪽 아래가 어두운 칸).
- 각 색: 킹 1, 퀸 1, 룩 2, 비숍 2, 나이트 2, 폰 8.
- 좌표: 열 a~h(백 기준 왼→오), 행 1~8(백 쪽부터). 기보는 SAN(예: `Nf3`, `exd5`, `O-O`, `e8=Q+`) 저장, 내부 처리는 UCI(`e2e4`, `e7e8q`).
## 4. 준비(셋업)
- `standard`: 백 1행 a~h: R N B Q K B N R, 2행 폰. 흑은 8행·7행에 대칭(퀸은 자기 색 칸: 백 Q d1, 흑 Q d8). FEN `rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1`.
- `chess960`: 시드 RNG로 0~959 중 번호 n을 뽑아 백 1행 배치를 만들고 흑은 같은 열에 대칭 배치. 폰 배치는 동일. 번호 → 배치(Scharnagl 방식):
1. `b1 = n % 4; n = floor(n/4)` → 밝은 칸 비숍을 열 `2*b1 + 1`(b, d, f, h)에.
2. `b2 = n % 4; n = floor(n/4)` → 어두운 칸 비숍을 열 `2*b2`(a, c, e, g)에.
3. `q = n % 6; n = floor(n/6)` → 남은 6칸 중 왼쪽부터 `q`번째(0부터)에 퀸.
4. `n`(0~9)로 남은 5칸 중 나이트 두 자리: 0:(0,1) 1:(0,2) 2:(0,3) 3:(0,4) 4:(1,2) 5:(1,3) 6:(1,4) 7:(2,3) 8:(2,4) 9:(3,4).
5. 남은 3칸에 왼쪽부터 R, K, R.
- 검증: n = 518 → RNBQKBNR(표준 배치).
- 백이 먼저 둔다. 시계: 양쪽 `baseSec`. 첫 수 규칙은 8.5 참고.
## 5. 진행 규칙
### 5.1 기물 이동
- 킹: 8방향 1칸. 공격받는 칸으로는 못 간다.
- 퀸: 가로·세로·대각 어느 거리든(가로막히면 정지).
- 룩: 가로·세로 어느 거리든. 비숍: 대각 어느 거리든. 나이트: L자(2+1), 다른 기물을 뛰어넘음.
- 폰: 앞으로 1칸(빈칸), 처음 위치에서는 2칸(두 칸 모두 빈칸). 대각 앞 1칸으로만 잡는다.
- 잡기: 상대 기물이 있는 칸으로 이동하면 그 기물을 제거. 자기 기물 칸으로는 못 간다.
### 5.2 특수 규칙
- 앙파상(en passant): 상대 폰이 직전 수에 처음 위치에서 2칸 전진해 내 폰 바로 옆에 섰을 때, 바로 다음 수에 한해 그 폰이 1칸만 전진한 것처럼 대각선으로 잡을 수 있다.
- 승진(promotion): 폰이 마지막 행에 도달하면 같은 색 퀸·룩·비숍·나이트 중 하나로 반드시 바꾼다(기존 기물 수와 무관).
- 캐슬링(standard): 킹과 룩이 모두 한 번도 움직이지 않았고, 사이 칸이 모두 비었으며, 킹이 현재 체크 상태가 아니고, 킹이 지나가는 칸과 도착 칸이 공격받지 않을 때. 킹이 룩 쪽으로 2칸 이동하고 룩이 킹이 넘어간 칸으로 이동. 킹사이드: Ke1→g1, Rh1→f1. 퀸사이드: Ke1→c1, Ra1→d1(b1은 비어야 하지만 공격받아도 무관).
- 캐슬링(chess960): 결과 위치는 표준과 동일(킹사이드: 킹 g, 룩 f / 퀸사이드: 킹 c, 룩 d). 조건: 해당 킹·룩 미이동, 킹의 현재 칸~도착 칸 사이 모든 칸(양 끝 포함)과 룩의 현재 칸~도착 칸 사이 모든 칸이 그 킹과 룩을 제외하고 비어 있음, 킹이 현재 체크 아님, 킹이 지나가는 칸·도착 칸이 공격받지 않음. 킹이나 룩이 이미 도착 칸에 있을 수 있다(이동 0칸).
- 체크: 킹이 공격받는 상태. 자기 킹을 공격받게 두는 수(핀 된 기물 이동, 공격받는 칸으로 킹 이동 포함)는 불법.
### 5.3 턴 구조
- 차례인 플레이어는 합법 수 하나를 둔다. 패스 없음.
- 합법 수가 없으면: 체크 상태면 체크메이트(패배), 아니면 스테일메이트(무승부).
## 6. 승패와 점수 계산
- 승리: 체크메이트, 상대 기권, 상대 시간패(단 아래 예외), 상대 연결 끊김 시간 초과.
- 무승부:
1. 스테일메이트.
2. 기물 부족(데드 포지션의 결정적 부분집합, 자동): 킹 대 킹 / 킹+비숍 대 킹 / 킹+나이트 대 킹 / 킹+비숍(들) 대 킹+비숍(들)에서 모든 비숍이 같은 색 칸.
3. 3회 반복: 같은 국면(같은 차례, 같은 기물 배치, 같은 캐슬링 권리, 같은 앙파상 가능 여부 — 앙파상 칸은 실제로 합법적 앙파상 잡기가 가능할 때만 국면에 포함)이 3번째 나옴. `auto`면 즉시 무승부, `fide`면 차례인 플레이어가 클레임 가능, 5번째는 자동 무승부.
4. 50수 규칙: 양쪽 모두 50수(100 플라이) 동안 폰 이동·잡기 없음. `auto`면 즉시 무승부, `fide`면 클레임 가능, 75수(150 플라이)는 자동. 단 그 수가 체크메이트면 체크메이트 우선.
5. 무승부 합의.
6. 시간패 예외(FIDE 6.9): 시간이 다 된 쪽의 상대가 어떤 합법 수순으로도 체크메이트할 수 없으면 무승부. 판정 함수 `cannotMate(side)`: `side`가 킹만 있음 / 킹+나이트 1개만 있고 상대가 킹만 / 킹+비숍 1개만 있고 상대가 킹만 / `side`가 킹+같은 색 칸 비숍들만 있고 상대도 킹+같은 색 칸 비숍들만(또는 킹만). 이 외에는 메이트 가능으로 보수적으로 판단(→ 시간 초과한 쪽 패배). 예: 백이 시간 초과, 흑이 킹+나이트, 백이 킹+퀸이면 흑이 이론상 헬프메이트 가능하므로 흑 승.
- 점수 개념 없음. 결과 요약: "백 승 (체크메이트, 34수)".
- 대국 취소(`aborted`): 백 또는 흑이 첫 수를 `firstMoveSec` 안에 두지 않으면 결과 없이 취소(승패 기록 없음).
## 7. 지역 룰 / 하우스 룰 (옵션으로 켜고 끄기)
- `drawMode=auto`(기본): chess.com처럼 3회 반복과 50수를 클레임 없이 자동 무승부. 어린이·어르신이 "클레임" 개념을 몰라 무한 반복하는 일을 막기 위함.
- `drawMode=fide`: FIDE 9.2/9.3/9.6 그대로(클레임 버튼 제공 + 5회 반복·75수 자동).
- Chess960: 무작위 첫 배치. 오프닝 암기 부담을 없앤 변형.
- 터치 무브(손 댄 기물은 움직여야 함), 불법 수 둔 사람 패배 등 오프라인 규칙은 온라인에서 적용하지 않는다(불법 수는 서버가 거부).
## 8. 엔진 설계
### 8.0 라이브러리 vs 자체 구현 평가
| 후보 | 장점 | 단점 |
|---|---|---|
| chess.js (BSD-2-Clause, TypeScript) | 오래 쓰인 검증된 수 생성, FEN/PGN/SAN, `isCheckmate/isStalemate/isInsufficientMaterial/isThreefoldRepetition/isDrawByFiftyMoves` 제공, 서버·클라이언트 공용, 라이선스 자유로움 | Chess960 캐슬링 미지원(이슈 #67, #441 등 장기 미해결). 3회 반복 판정의 국면 동일성 기준, 기물 부족 기준을 우리 규칙과 맞춰 확인 필요 |
| chessops (TypeScript, lichess 개발자 제작) | Chess960 포함 각종 변형 지원, lichess에서 실사용 | GPL-3.0 이상. 클라이언트 번들에 포함하면 클라이언트 코드 공개 의무 발생 가능. 서버 전용으로 쓰면 배포가 아니므로 일반적으로 문제 없으나 법적 판단 필요 |
| 자체 구현 | 의존성·라이선스 없음, 960 포함 완전 통제 | 수 생성 버그 위험. perft 테스트로 검증 필수, 개발 시간 증가 |
- 권장: v1(standard)은 **chess.js를 서버에서만** 사용해 판정하고, 클라이언트는 서버 view의 `legalMoves`로 하이라이트(클라이언트 라이브러리 불필요 → 번들 경량화, 판정 이중화 불일치 방지). 대신 아래를 어댑터에서 우리 규칙으로 직접 판정한다: 반복 국면 키(앙파상 정규화), 50/75수, 기물 부족 목록, 시간패 예외 `cannotMate`.
- Chess960(후속 마일스톤): (a) chessops를 서버 전용으로 도입(GPL 적용 범위를 사용자/법률 검토 후) 또는 (b) 자체 구현 + perft 검증. 사용자가 오픈소스 공개를 원치 않고 법률 검토도 부담이면 (b). 이 문서의 상태·액션 정의는 두 방식 모두에 맞도록 FEN(960은 Shredder-FEN: 캐슬링 권리를 룩의 열 문자로 표기, 예 `HAha`)을 기준으로 한다.
- 어느 쪽이든 perft로 검증: 초기 국면 깊이 1~5 = 20 / 400 / 8,902 / 197,281 / 4,865,609, "Kiwipete" 국면(`r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1`) 깊이 1~4 = 48 / 2,039 / 97,862 / 4,085,603. 960은 공개된 chess960 perft 세트 사용.
### 8.1 상태(State)
```ts
type Color = 'white' | 'black';
interface ChessState {
options: ChessOptions;
players: Record<Color, PlayerId>;
startFen: string; // 960 배치 포함
chess960Index: number | null;
fen: string; // 현재 국면 (권위 있는 단일 진실)
moves: { uci: string; san: string; color: Color; at: number; fenAfter: string }[];
repetition: Record<string, number>; // 국면 키 -> 등장 횟수
phase: 'playing' | 'finished';
clock: { remainingMs: Record<Color, number>; turnStartedAt: number; started: Record<Color, boolean> };
undo: { usedBy: Record<Color, number>; pending: { by: Color; plies: 1 | 2 } | null };
draw: { pendingBy: Color | null; lastOfferPly: Record<Color, number> };
claimable: 'threefold' | 'fiftyMove' | null; // drawMode=fide에서 차례인 쪽이 클레임 가능한 사유
result: ChessResult | null;
rng: RngState;
}
// 국면 키 = FEN의 앞 4필드(배치, 차례, 캐슬링 권리, 앙파상 칸).
// 단 앙파상 칸은 합법적인 앙파상 잡기가 실제로 있을 때만 남기고 아니면 '-'로 정규화.
```
### 8.2 액션
| type | payload | 누가 / 언제 | 검증 조건 |
|---|---|---|---|
| `move` | `{ from: 'e2', to: 'e4', promotion?: 'q'\|'r'\|'b'\|'n' }` | 차례인 플레이어, `playing` | 합법 수 목록에 존재. 승진 수인데 `promotion` 없으면 거부("승진할 기물을 골라 주세요"). 승진 수가 아닌데 있으면 무시. 실패 사유 예: "그 기물은 그렇게 움직일 수 없어요", "킹이 공격받게 되어 둘 수 없어요", "지금은 상대 차례예요" |
| `castle` | `{ side: 'king' \| 'queen' }` | 차례인 플레이어 | 5.2 조건. 960에서 킹 이동과 혼동되는 경우(킹이 1칸 옆 룩 칸 등) 명시적으로 사용. standard에서는 `move e1g1`도 캐슬링으로 인정 |
| `claimDraw` | `{}` | 차례인 플레이어, `drawMode=fide` | `claimable != null` (FIDE: 클레임하는 수를 두기 직전 또는 직후 국면). 수락 없이 즉시 무승부 |
| `requestUndo` | `{}` | 플레이어 | `undo != off`, 횟수 남음, 대기 없음, 본인 수 존재. 1 또는 2 플라이 |
| `respondUndo` | `{ accept }` | 상대 | 수락 시 `moves` 끝에서 제거하고 `startFen`에서 재생해 `fen`·`repetition` 재구성. 시계는 되돌리지 않음 |
| `offerDraw` | `{}` | 플레이어 | `drawOffer=true`, 대기 없음, 거절 후 본인 3수 이상 |
| `respondDraw` | `{ accept }` | 상대 | 수락 → 무승부 |
| `cancelOffer` | `{}` | 요청자 | |
| `resign` | `{}` | 플레이어 | 언제든(첫 수 전이면 `aborted`로 처리) |
| `timeout` | `{}` | 시스템 | 8.5 |
- 수 처리 순서: 시계 차감(0 이하면 시간패 처리, 6장 예외 포함) → 합법성 → 적용 → 증가분 가산 → 종료 판정 순서: 체크메이트 > 스테일메이트 > 기물 부족 > (75수/5회 반복 자동) > (`auto`면 50수/3회 반복) → `claimable` 갱신.
- 대기 요청은 요청받은 쪽이 수를 두면 자동 거절.
- 이벤트: `moved`(SAN, 잡힌 기물, 체크 여부), `check`, `checkmate`, `stalemate`, `promoted`, `castled`, `enPassant`, `drawClaimable`, `gameEnded` 등.
### 8.3 공개/비공개 정보 (view)
- 공통 공개: `fen`, 기보(SAN), 마지막 수, 체크 여부, 시계, `deadline`, 잡은 기물 목록과 기물 점수 차(표시용: 퀸9 룩5 비숍3 나이트3 폰1), 대기 중인 요청, `claimable`, 결과.
- 차례인 플레이어에게: `legalMoves: { from; to; promotion?; castle? }[]`(하이라이트용). `hints=movesAndThreats`면 `threatenedSquares`(내 기물 중 공격받고 방어 안 된 칸).
- 차례가 아닌 플레이어: 프리무브 UI를 위해 자기 기물의 의사 합법 수를 클라이언트에서 계산하지 않고, v1은 프리무브 미지원(단순성·공정성).
- 관전자: `legalMoves`/`threatenedSquares` 없음.
- 제외: `rng`(960 배치는 셋업 직후 공개되므로 문제없지만 다음 대국 배치 예측 방지).
### 8.4 랜덤 요소 (시드 RNG 사용 지점)
1. `colorAssignment=random`의 색 결정.
2. `chess960` 배치 번호 0~959 선택.
대국 중에는 RNG를 쓰지 않는다.
### 8.5 타이머·시간 초과·연결 끊김 시 자동 행동
- 시계 시작: 각 색의 첫 수는 `firstMoveSec` 제한만 있고 본 시계를 차감하지 않는다(lichess 방식). 백이 첫 수를 두면 흑의 첫 수 제한이 시작되고, 흑이 첫 수를 두면 백의 본 시계가 시작된다.
- `deadline(state)`:
- 해당 색 첫 수 전: `turnStartedAt + firstMoveSec*1000`
- 피셔: `turnStartedAt + remainingMs[turn]`
- `none`: `turnStartedAt + idleLimitSec*1000`
- 종료: `null`
- `onTimeout(state, player)` → `{ type: 'timeout' }`. `apply`:
- 첫 수 제한 초과 → `aborted`(승패 없음).
- 그 외 → `player` 시간패. 단 상대가 `cannotMate`면 무승부(`timeoutVsInsufficient`).
- 자동 수는 두지 않는다(체스에서 무작위 수는 승패를 왜곡).
- 연결 끊김: 끊긴 플레이어의 차례에 `min(deadline, 끊김 + disconnectGraceSec)`에 `onTimeout`. 상대 차례 중에 끊겼다면 자기 차례가 되는 순간부터 유예 계산.
### 8.6 종료 조건과 결과(GameResult)
```ts
interface ChessResult {
ranking: { playerId: PlayerId; rank: 1 | 2 }[]; // 무승부면 둘 다 1, aborted면 빈 배열
winner: Color | null;
reason: 'checkmate' | 'resign' | 'timeLoss' | 'stalemate' | 'insufficientMaterial'
| 'threefold' | 'fivefold' | 'fiftyMove' | 'seventyFiveMove' | 'drawAgreed'
| 'timeoutVsInsufficient' | 'aborted';
pgn: string; // 태그(Variant, FEN 포함) + SAN 기보
moveCount: number; // 전체 수(풀무브)
summaryKo: string; // "흑 승 (체크메이트, 28수)"
}
```
## 9. UI/UX
- 모바일 세로: 상단 상대(잡은 기물, 시계), 가운데 정사각 판(폰 360px에서 칸 45px — 탭 정확도를 위해 칸 전체를 터치 영역으로), 하단 내 시계와 버튼 줄(무르기, 무승부, 기권, 기보, 규칙 보기). 판은 내 색이 아래로 오게 자동 회전.
- 조작: 기물 탭 → 이동 가능 칸 점 표시(잡기 칸은 테두리 링) → 도착 칸 탭. 드래그도 지원. 다른 내 기물 탭 시 선택 변경.
- 승진: 도착 시 큰 4개 버튼(퀸, 룩, 비숍, 나이트) 모달.
- 캐슬링: 킹 선택 시 캐슬링 도착 칸(standard: g1/c1, 960: 룩 칸도 탭 가능) 표시.
- 체크 시 킹 칸 빨간 배경 + "체크!" 말풍선, 체크메이트·스테일메이트 결과 모달에 이유 설명(초보용: "킹이 피할 곳이 없어요").
- 마지막 수 출발·도착 칸 강조, 이동 애니메이션 150ms 내외(저사양 고려).
- 규칙 보기: 기물별 움직임 애니메이션 카드, 특수 규칙(앙파상·캐슬링·승진) 그림 설명.
- 시계 10초 이하 시 빨간색 + 효과음(끌 수 있음).
- 관전자: 판 방향 전환 버튼, 기보 탐색(로컬).
## 10. 테스트 체크리스트
- [ ] perft: 초기 국면 깊이 1~4(가능하면 5), Kiwipete 깊이 1~3이 8.0의 수치와 일치(어댑터 경유로 검증).
- [ ] 캐슬링 금지 조건: 킹 체크 중, 지나가는 칸 공격받음, 도착 칸 공격받음, 룩 이동 이력, 킹 이동 이력. 퀸사이드에서 b1만 공격받는 경우는 허용.
- [ ] 앙파상: 2칸 전진 직후에만 가능, 한 수 늦으면 불가. 앙파상으로 자기 킹이 노출되는(가로 핀) 경우 불법.
- [ ] 승진: 4종 모두 가능, `promotion` 누락 시 거부, 잡으면서 승진.
- [ ] 체크메이트·스테일메이트 판정(예: 스칼라 메이트 4수, 퀸으로 인한 스테일메이트).
- [ ] 3회 반복: 앙파상 칸이 FEN에 있지만 실제 잡기 불가능한 경우 같은 국면으로 취급, 캐슬링 권리가 달라지면 다른 국면.
- [ ] 50수: `auto`는 100플라이 째 무승부, 단 그 수가 체크메이트면 메이트 우선. `fide`는 클레임 버튼 활성화, 150플라이 자동.
- [ ] 기물 부족: K vs K, KB vs K, KN vs K, 같은 색 비숍끼리 자동 무승부. KNN vs K는 자동 무승부 아님.
- [ ] 시간패 예외: 시간 초과한 쪽 상대가 킹만 → 무승부, 상대 킹+나이트이고 시간 초과한 쪽이 킹+퀸 → 상대 승.
- [ ] 첫 수 제한 초과 → `aborted`, 랭킹 비어 있음.
- [ ] 피셔 증가분: 수를 둔 뒤 가산, 0 이하로 도착한 수는 거부.
- [ ] Chess960: n=518이 표준 배치, 무작위 1000회 생성 시 비숍 반대 색·킹이 두 룩 사이 조건 항상 만족, 킹이 g열에 이미 있는 배치에서 킹사이드 캐슬링(킹 0칸 이동).
- [ ] 무르기: 1/2 플라이 복원 후 `repetition` 카운트 정확, 거절 시 무변화.
- [ ] 연결 끊김 유예 후 시간패 처리.
- [ ] 정보 누출: 관전자·비차례 플레이어 view에 `legalMoves`/`threatenedSquares` 없음, 모든 view에 `rng` 없음.
- [ ] 리플레이 결정성(같은 시드 → 같은 960 배치와 결과).
## 11. 참고 자료
- FIDE Laws of Chess (2023년 1월 1일 시행): https://handbook.fide.com/chapter/E012023 (3.8 캐슬링, 3.7 앙파상·승진, 5.2 스테일메이트·데드 포지션, 6.9 시간패 예외, 9.2 3회 반복, 9.3 50수, 9.6 5회 반복·75수)
- FIDE 부록 Chess960 규칙(Guidelines III): 같은 핸드북
- Wikipedia "Fischer random chess": https://en.wikipedia.org/wiki/Fischer_random_chess (Scharnagl 번호 체계)
- chess.js (BSD-2-Clause): https://github.com/jhlywa/chess.js , Chess960 미지원 이슈: https://github.com/jhlywa/chess.js/issues/67
- chessops (GPL-3.0-or-later): https://github.com/niklasf/chessops
- Chess Programming Wiki "Perft Results": https://www.chessprogramming.org/Perft_Results
## 12. 메모 (상표·법적 주의 등)
- "체스", "Chess"는 일반 명칭. "Chess960"/"Fischer Random"은 일반적으로 쓰이는 변형 명칭이지만 "피셔 랜덤" 대신 "체스960" 표기를 권장.
- 라이선스: chess.js는 BSD-2(저작권 고지 포함 필요). chessops 도입 시 GPL-3 의무(특히 클라이언트 배포) 검토 필요 — 사용자 결정 사항.
- 금전·베팅 요소 없음. 레이팅(Elo 등)은 범위 밖(방 단위 대국만).