- 개요, 조사(BGA·한국 인기 보드게임·UI/UX), 아키텍처, 실시간 프로토콜, 안정성·보안, 계정, 로비·방, UI/UX, 데이터 모델, 게임 엔진, 테스트, 배포·운영, 로드맵(M0~M9), 사용자 결정 항목 - 게임별 규칙·엔진 설계·UI·테스트 체크리스트 26종 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
11 KiB
11 KiB
리버시 (오셀로) (othello)
마일스톤: M2 · 인원: 최소 2 ~ 최대 2명 · 예상 시간: 약 10~15분 · 난이도: 쉬움
1. 개요
- 8×8 판에서 상대 돌을 내 돌 사이에 끼우면 뒤집어 내 색으로 만드는 2인 게임. 끝났을 때 자기 색 돌이 더 많으면 승리. 한국에서는 "오셀로"라는 이름으로 잘 알려져 있고 규칙 설명이 1분이면 끝나 어린이·어르신 모두에게 적합하다.
- 인원 근거: 원작이 흑·백 2인 게임. 최소 2, 최대 2.
- 규칙 기준: 세계오셀로연맹(WOF) 공식 규칙.
- 완전 정보 게임. view에서 제외할 것은 RNG 상태뿐.
- 표시 이름은 상표 문제로 "리버시"를 권장(12장).
2. 모드와 옵션
| 옵션 키 | 설명 | 선택지 | 기본값 |
|---|---|---|---|
colorAssignment |
흑백 결정 | random / hostBlack / hostWhite / alternate |
random |
emptyToWinner |
종료 시 빈칸을 승자 점수에 더함(WOF 대회 방식, 승패에는 영향 없음 — 점수 표시만 바뀜) | true / false |
false |
timeControl.kind |
시간 방식 | none / perMove / fischer |
perMove |
timeControl.perMoveSec |
한 수당 제한 | 10 / 20 / 30 / 60 | 30 |
timeControl.baseSec / incSec |
전체 시간 / 수당 추가 | 3+2, 5+3, 10+5 | 5+3 |
timeoutPolicy |
perMove 시간 초과 처리 |
autoMove(무작위 합법 수) / lose |
autoMove |
idleLimitSec |
none 무응답 한도 |
120 / 300 / 600 | 300 |
undo |
무르기 허용 횟수(상대 동의) | off / 1 / 3 / unlimited |
3 |
drawOffer |
무승부 제안 | true / false |
true |
showLegalMoves |
둘 수 있는 칸 표시 | true / false |
true |
showFlipCount |
둘 수 있는 칸에 뒤집히는 개수 숫자 표시(초보 도움말) | true / false |
false |
disconnectGraceSec |
연결 끊김 유예 | 30 / 60 / 120 | 60 |
3. 구성물
- 8×8 판(64칸). 돌은 칸 안에 놓는다.
- 한 면이 흑, 다른 면이 백인 원판 돌 64개(엔진에서는 개수 제한 없음 — 칸 수가 상한).
- 좌표: 열 a
h(왼→오), 행 18(위→아래, 오셀로 표준 표기). 내부(x, y)0~7, 표시'abcdefgh'[x] + (y+1).
4. 준비(셋업)
colorAssignment로 흑백 결정.- 가운데 4칸에 배치: d4 백, e4 흑, d5 흑, e5 백.
- 흑이 먼저 둔다. 시작 시 흑의 합법 수는 d3, c4, f5, e6 네 곳.
5. 진행 규칙
- 합법 수: 빈칸
p에 내 돌을 놓았을 때, 8방향(가로·세로·대각) 중 적어도 한 방향에서p바로 옆부터 상대 돌이 1개 이상 연속되고 그 끝에 내 돌이 있는 경우. - 착수 처리: 위 조건을 만족하는 모든 방향에 대해, 사이에 낀 상대 돌을 전부 내 색으로 뒤집는다. 뒤집힌 돌로 인해 새로 끼워지는 돌은 연쇄로 뒤집지 않는다(한 수에서 놓은 돌 기준의 직선만).
- 뒤집을 수 있는 칸이 있으면 반드시 그중 한 곳에 둬야 한다(자발적 패스 없음).
- 패스: 차례인 플레이어에게 합법 수가 하나도 없으면 자동으로 차례가 상대에게 넘어간다(서버가 처리, 플레이어 행동 불필요). 이벤트
passed를 남긴다. - 종료: 양쪽 모두 합법 수가 없으면(판이 가득 찬 경우 포함) 즉시 종료.
- 예시: 시작 직후 흑이 d3에 두면 d4 백이 흑으로 뒤집힌다(d3–d4–d5 세로). 흑 4, 백 1.
6. 승패와 점수 계산
- 점수 = 종료 시 판 위 자기 색 돌 수.
- 많은 쪽 승리, 같으면 무승부.
emptyToWinner=true(WOF 대회 방식): 빈칸이 남은 채 끝났으면 빈칸 수를 승자 점수에 더한다. 무승부면 빈칸을 반씩 나눈다(빈칸 수는 무승부 시 항상 짝수). 예: 흑 40, 백 20, 빈칸 4 → 표시 점수 44 : 20. 승패는 동일.- 그 외 종료: 기권, 시간패, 무승부 합의.
- 기권·시간패로 끝나도 결과에 당시 돌 수를 함께 기록.
7. 지역 룰 / 하우스 룰 (옵션으로 켜고 끄기)
- 가운데 4칸 초기 배치를 직접 놓는 옛 방식(초기 4수를 번갈아 가운데 4칸에 두는 리버시 원형 규칙)은 지원하지 않는다. 표준 대각 배치 고정.
- 6×6, 10×10 판 변형은 v1 미지원(추후
boardSize옵션 후보). - 빈칸을 승자에게 주는 대회 점수 방식은 옵션.
8. 엔진 설계
8.1 상태(State)
type Color = 'black' | 'white';
type Cell = 0 | 1 | 2;
interface OthelloState {
options: OthelloOptions;
board: Cell[]; // 64, index = y*8 + x
players: Record<Color, PlayerId>;
turn: Color;
phase: 'playing' | 'finished';
moves: ({ kind: 'place'; color: Color; x: number; y: number; flipped: number[]; auto: boolean }
| { kind: 'pass'; color: Color })[]; // 자동 패스도 기록(무르기·리플레이용)
clock: { remainingMs: Record<Color, number>; turnStartedAt: number; autoMoveStreak: Record<Color, number> };
undo: { usedBy: Record<Color, number>; pending: { by: Color; plies: number } | null };
draw: { pendingBy: Color | null; lastOfferPly: Record<Color, number> };
result: OthelloResult | null;
rng: RngState;
}
8.2 액션
| type | payload | 누가 / 언제 | 검증 조건 |
|---|---|---|---|
place |
{ x, y } |
차례인 플레이어, playing |
판 안, 빈칸, 뒤집히는 돌이 1개 이상("여기에 두면 뒤집을 돌이 없어요") |
requestUndo |
{} |
플레이어 | 횟수 남음, 대기 없음, 본인 착수 존재. 무를 범위 = 기록의 끝에서부터 본인의 마지막 place까지(그 사이 자동 패스 포함) |
respondUndo |
{ accept } |
상대 | 수락 시 moves를 처음부터 재생해 판 복원, 차례 = 요청자. 시계 유지 |
offerDraw / respondDraw / cancelOffer |
플레이어 | 거절 후 본인 3수 이후 재제안 | |
resign |
{} |
플레이어 | 언제든 |
timeout |
{} |
시스템 | 8.5 |
place처리 후: 상대에게 합법 수가 있으면 차례 넘김. 없고 나에게 있으면 상대 자동 패스 기록 후 다시 내 차례. 둘 다 없으면 종료.- 시계:
fischer는 착수 시 차감 후 증가분 가산. 자동 패스는 시간이 들지 않으며 다시 차례가 온 플레이어의turnStartedAt = now. - 이벤트:
placed(뒤집힌 칸 목록 — 애니메이션용),passed,gameEnded.
8.3 공개/비공개 정보 (view)
- 공통 공개: 판, 차례, 돌 수, 기보, 마지막 수, 시계,
deadline, 대기 요청, 결과. - 차례인 플레이어에게만:
legalMoves: { x, y, flips: number }[](showLegalMoves/showFlipCount옵션에 따라 클라이언트가 표시). - 관전자:
legalMoves없음(해설 모드 필요 시 추후). - 제외:
rng.
8.4 랜덤 요소 (시드 RNG 사용 지점)
colorAssignment=random.timeoutPolicy=autoMove의 자동 착수: 모서리(a1, h1, a8, h8)가 합법이면 그중 무작위, 아니면 전체 합법 수 중 균등 무작위. 모서리 우선은 시간 초과 당한 쪽이 지나치게 불리해지지 않게 하는 최소한의 배려.
8.5 타이머·시간 초과·연결 끊김 시 자동 행동
deadline(state):perMove→turnStartedAt + perMoveSec*1000,fischer→turnStartedAt + remainingMs[turn],none→turnStartedAt + idleLimitSec*1000, 종료 →null.onTimeout(state, player)→{ type: 'timeout' }.apply:perMove + autoMove: 자동 착수(auto: true), streak +1, 3연속이면 시간패.- 그 외: 시간패.
- 연결 끊김: 끊긴 플레이어 차례에
min(deadline, 끊김 + disconnectGraceSec)에onTimeout.
8.6 종료 조건과 결과(GameResult)
interface OthelloResult {
ranking: { playerId: PlayerId; rank: 1 | 2 }[];
winner: Color | null;
reason: 'noMoves' | 'resign' | 'timeLoss' | 'drawAgreed';
discs: { black: number; white: number; empty: number };
displayScore: { black: number; white: number }; // emptyToWinner 반영
summaryKo: string; // "흑 승 40 : 24"
}
9. UI/UX
- 모바일 세로: 상단 상대(돌 수, 시계), 가운데 8×8 판(폰 360px에서 칸 약 44px — 칸 전체가 터치 영역, 48px에 근접하므로 한 번 탭 착수 허용), 하단 내 정보와 버튼.
- 둘 수 있는 칸은 작은 반투명 점.
showFlipCount면 숫자. - 착수 시 뒤집히는 돌을 놓은 돌에서 가까운 순서로 순차 회전 애니메이션(전체 400ms 이내).
- 자동 패스 시 "둘 곳이 없어서 차례가 넘어갔어요" 토스트(상대 화면에도).
- 돌 수 막대(흑/백 비율)를 상단에 상시 표시.
- 규칙 보기: 끼워서 뒤집기 3단계 그림, 패스 설명, 모서리 팁(선택).
- PC: 판 좌측, 기보·채팅 우측.
10. 테스트 체크리스트
- 초기 배치(d4 백, e4 흑, d5 흑, e5 백)와 흑의 첫 합법 수 4개(d3, c4, f5, e6).
- 8방향 각각 뒤집기, 한 수에 여러 방향 동시 뒤집기.
- 연쇄 뒤집기 없음(뒤집힌 돌이 만든 새 끼움은 뒤집지 않음).
- 뒤집을 돌이 없는 빈칸 착수 거부, 판 밖·이미 찬 칸 거부.
- 자동 패스: 상대 합법 수 없음 → 패스 기록 후 내 차례 유지.
- 양쪽 합법 수 없음 → 판이 다 차지 않아도 종료(예: 한 색이 전멸).
- 동점 무승부,
emptyToWinner점수 표시(승리·무승부 각각). - 무르기: 자동 패스가 끼어 있는 경우에도 정확히 본인 마지막 착수 전으로 복원.
autoMove: 모서리 우선, 같은 시드에서 같은 선택, 3연속 시간패.fischer시간패, 증가분 가산.- 연결 끊김 유예 후 처리, 재접속 시 해제.
- 정보 누출: 관전자·비차례 플레이어 view에
legalMoves없음, 모든 view에rng없음. - 리플레이 결정성.
11. 참고 자료
- World Othello Federation 공식 규칙: https://www.worldothello.org/about/about-othello/othello-rules/official-rules/english (초기 배치, 흑 선, 합법 수, 패스, 종료, 다수 승리)
- Wikipedia "Reversi": https://en.wikipedia.org/wiki/Reversi (오셀로/리버시 역사, 대회의 빈칸 승자 귀속 관행)
- 위키백과 「오셀로 (보드 게임)」: https://ko.wikipedia.org/wiki/%EC%98%A4%EC%85%80%EB%A1%9C_(%EB%B3%B4%EB%93%9C_%EA%B2%8C%EC%9E%84)
12. 메모 (상표·법적 주의 등)
- "Othello"/"오셀로"는 상표(현재 일본 MegaHouse 및 Othello Co. 계열이 보유)이므로 서비스 표시 이름은 일반 명칭 "리버시"를 권장한다. 규칙 설명에서 "오셀로와 같은 규칙" 정도의 비교 서술은 지명적 사용으로 보통 허용되나, 로고·트레이드 드레스(초록 판 + 특정 디자인) 모방은 피한다. 최종 표시 이름은 사용자 결정 사항.
- 게임 id
othello는 내부 식별자일 뿐 UI에 노출하지 않는다(필요하면reversi로 변경 가능). - 금전·베팅 요소 없음.