Files
joke-app/docs/games/chess.md
EJClaw 4cb71d8cbe 위협 가이드 제거: 오목 위험 자리, 체스·장기 위험 기물 경고, 바둑 단수 경고
- 오목: 상대 3·4를 막으라는 빨간 동그라미·노란 점선(hints 옵션, view.hints, threatHints) 삭제
- 체스·장기: hints 'movesAndThreats'(주황 점선 위험 기물) 삭제 → 'off' / 'moves'만 남김
- 바둑: atariWarning 옵션과 atariWarnings(깜빡이는 단수 돌) 삭제
- 도움말 문구·설정 화면·docs 정리, 테스트는 "어떤 view에도 위협 표시 없음"으로 바꿈
- 갈 수 있는 칸 점, 금수 ×, 둘 수 없는 점 같은 규칙 표시는 그대로

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 15:34:58 +09:00

22 KiB
Raw Blame History

체스 (chess)

마일스톤: M2 · 인원: 최소 2 ~ 최대 2명 · 예상 시간: 블리츠 약 10분, 래피드 약 2040분 · 난이도: 보통어려움

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 / 사용자 지정(190분, 060초) 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 moves
disconnectGraceSec 연결 끊김 유예 30 / 60 / 120 60

3. 구성물

  • 8×8 칸(64칸), a1이 흑색 칸(백 기준 왼쪽 아래가 어두운 칸).
  • 각 색: 킹 1, 퀸 1, 룩 2, 비숍 2, 나이트 2, 폰 8.
  • 좌표: 열 ah(백 기준 왼→오), 행 18(백 쪽부터). 기보는 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 턴 구조

  • 차례인 플레이어는 합법 수 하나를 둔다. 패스 없음.
  • 합법 수가 없으면: 체크 상태면 체크메이트(패배), 아니면 스테일메이트(무승부).

5.4 Chess960 입력과 표기

  • 입력: (1) 킹 → 자기 캐슬링 룩 칸(960 방식, UCI_Chess960과 같음), (2) 킹 → 도착 칸(g/c열). 단 (2)는 그 칸이 보통의 킹 1칸 이동이기도 하면 보통 이동으로 본다(예: 킹 b1에서 c1은 Kc1). 그때는 (1)이나 castle 액션(버튼)으로 캐슬링한다. 킹이 이미 도착 칸에 있으면(킹 g1, 룩 h1) (1)·castle만 가능.
  • standard에서는 킹 → 룩 칸은 캐슬링이 아니다(거부: "그 기물은 그렇게 움직일 수 없어요").
  • 기보: SAN은 O-O / O-O-O. 저장 UCI는 킹 칸 + 룩 칸(예 b1h1). PGN 태그 Variant "Chess960", SetUp "1", FEN(Shredder-FEN).
  • 시작 번호 n은 setup에서 색 정하기 다음에 시드 RNG로 뽑는다(그래서 standard 대국의 RNG 순서는 예전과 같다). n = 518은 표준 배치지만 960 규칙(룩 칸 캐슬링 입력, Shredder-FEN)으로 진행한다.
  • 저장 형식: stateVersion 2. v1(옵션에 variant 없음, chess960Index 없음)은 migrate가 variant: 'standard', chess960Index: null로 채운다. 끝난 대국은 마이그레이션되지 않으므로 코드는 chess960Index가 없으면 standard로 읽는다.

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 테스트로 검증 필수, 개발 시간 증가
  • 결정(M9): 자체 구현(packages/games/src/chess/movegen.ts)으로 standard와 Chess960을 한 생성기로 처리한다. M2~M8은 chess.js를 서버에서만 썼고, 지금 chess.js는 테스트 전용 devDependency(비교 검증용)다. 클라이언트는 그대로 서버 view의 legalMoves로만 하이라이트한다(클라이언트에 규칙 코드 없음). 반복 국면 키(앙파상 정규화), 50/75수, 기물 부족 목록, 시간패 예외 cannotMate는 어댑터(rules.ts)에서 우리 규칙으로 판정한다.
  • 생성기 구조: 0x88 판, make/unmake. 캐슬링 권리를 "색·방향별 룩 칸"으로 저장해 standard와 960이 같은 코드를 탄다. FEN 입력은 KQkq(X-FEN: 가장 바깥 룩)와 Shredder-FEN(HAha)을 모두 받고, 출력은 standard는 KQkq, 960은 Shredder-FEN.
  • 예전 저장 대국 호환: 앙파상 칸 저장·출력, SAN(모호성 표기, +/#)을 chess.js 1.4와 똑같이 맞췄다. 그래서 chess.js 시절에 저장된 fen·fenAfter·반복 키가 글자 하나까지 같다(비교 테스트로 확인).
  • 검증(chess.perft.test.ts): perft — 초기 국면 깊이 14 = 20 / 400 / 8,902 / 197,281(깊은 실행에서 56 = 4,865,609 / 119,060,324), Kiwipete 13 = 48 / 2,039 / 97,862(깊은 실행에서 4 = 4,085,603), chessprogramming 36번 국면, 핀·앙파상 함정 국면, 960은 공개 Chess960 perft 세트(fischer.epd) 12개 국면과 X-FEN 5개 국면 깊이 34(깊은 실행 45). 깊은 실행은 PERFT_DEEP=1 bun test chess.perft(약 1~2분). 또 무작위 대국에서 매 수 chess.js와 합법 수 집합·SAN·FEN·체크/메이트/스테일메이트·기물 부족·50수·3회 반복 판정을 비교한다.

8.1 상태(State)

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? }[](하이라이트용).
  • 차례가 아닌 플레이어: 프리무브 UI를 위해 자기 기물의 의사 합법 수를 클라이언트에서 계산하지 않고, v1은 프리무브 미지원(단순성·공정성).
  • 관전자: legalMoves 없음.
  • 제외: 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)

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: 내 룩 칸, 그리고 킹이 갈 g/c열 칸(그 칸이 보통 킹 이동과 겹치지 않을 때)을 모두 표시하고, 판 아래에 "노란 테두리 칸을 누르세요" 안내. 960은 옆 패널에 [캐슬링: 킹 쪽 (O-O)] / [캐슬링: 퀸 쪽 (O-O-O)] 버튼도 둔다. 960 대국은 옆 패널에 "체스960 · 시작 배치 n번"을 보여 준다.
  • 체크 시 킹 칸 빨간 배경 + "체크!" 말풍선, 체크메이트·스테일메이트 결과 모달에 이유 설명(초보용: "킹이 피할 곳이 없어요").
  • 마지막 수 출발·도착 칸 강조, 이동 애니메이션 150ms 내외(저사양 고려).
  • 규칙 보기: 기물별 움직임 애니메이션 카드, 특수 규칙(앙파상·캐슬링·승진) 그림 설명.
  • 시계 10초 이하 시 빨간색 + 효과음(끌 수 있음).
  • 관전자: 판 방향 전환 버튼, 기보 탐색(로컬).

10. 테스트 체크리스트

  • perft: 초기 국면 깊이 14(가능하면 5), Kiwipete 깊이 13이 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이 표준 배치, 960개 번호 모두 비숍 반대 색·킹이 두 룩 사이 조건 만족·서로 다름, 킹이 g열에 이미 있는 배치에서 킹사이드 캐슬링(킹 0칸 이동), 룩 경로·킹 경로·도착 칸 막힘/공격, 룩이 도착 칸을 가리던 경우, 권리 상실, 무르기 후 권리 복원, 무작위 960 대국(chess.test.ts), perft(chess.perft.test.ts).
  • 무르기: 1/2 플라이 복원 후 repetition 카운트 정확, 거절 시 무변화.
  • 연결 끊김 유예 후 시간패 처리.
  • 정보 누출: 관전자·비차례 플레이어 view에 legalMoves 없음, 모든 view에 rng 없음.
  • 리플레이 결정성(같은 시드 → 같은 960 배치와 결과).

11. 참고 자료

12. 메모 (상표·법적 주의 등)

  • "체스", "Chess"는 일반 명칭. "Chess960"/"Fischer Random"은 일반적으로 쓰이는 변형 명칭이지만 "피셔 랜덤" 대신 "체스960" 표기를 권장.
  • 라이선스: chess.js는 BSD-2(저작권 고지 포함 필요). chessops 도입 시 GPL-3 의무(특히 클라이언트 배포) 검토 필요 — 사용자 결정 사항.
  • 금전·베팅 요소 없음. 레이팅(Elo 등)은 범위 밖(방 단위 대국만).