M9: 게임 26종 30초 요약 카드·[?] 지금 할 수 있는 것 내용
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
51
apps/web/src/games/chess/help.ts
Normal file
51
apps/web/src/games/chess/help.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
/** 체스 [?] "지금 할 수 있는 것" (docs/07 §5). Pure: only reads the client view. */
|
||||
import type { ChessView } from '@bg/games/chess';
|
||||
import type { PublicUser } from '@bg/shared/lite';
|
||||
|
||||
const COLOR_KO = { white: '백', black: '흑' } as const;
|
||||
|
||||
/** Material lead as shown next to the player bars ("+3"). */
|
||||
function material(v: ChessView): string {
|
||||
if (v.materialDiff === 0) return '';
|
||||
const lead = v.materialDiff > 0 ? 'white' : 'black';
|
||||
return `기물 점수는 ${COLOR_KO[lead]}이 ${Math.abs(v.materialDiff)}점 앞서요(퀸 9, 룩 5, 비숍·나이트 3, 폰 1).`;
|
||||
}
|
||||
|
||||
export function helpNow(v: ChessView, _me: string | null, players: Record<string, PublicUser>): string {
|
||||
if (v.phase === 'finished') return `게임이 끝났어요. ${v.result?.summary ?? ''}`.trim() + '\n결과 창에서 [한 판 더]를 누르면 다시 할 수 있어요.';
|
||||
const turnNick = players[v.players[v.turn]]?.nickname ?? COLOR_KO[v.turn];
|
||||
const mat = material(v);
|
||||
if (!v.myColor) {
|
||||
const check = v.checkSquare ? ` ${COLOR_KO[v.turn]} 킹이 체크(공격)를 받고 있어요.` : '';
|
||||
return [`${turnNick}님(${COLOR_KO[v.turn]}) 차례예요.${check} 상대 킹을 피할 곳 없이 잡히게 만들면(체크메이트) 이겨요.`, mat].filter(Boolean).join('\n');
|
||||
}
|
||||
const mine = COLOR_KO[v.myColor];
|
||||
if (v.undo.pending && v.undo.pending.by !== v.myColor)
|
||||
return `상대가 ${v.undo.pending.plies}수 무르기를 부탁했어요. [수락]을 누르면 기물이 되돌아가고(시계는 그대로), [거절]을 누르면 그대로 계속해요.`;
|
||||
if (v.draw.pendingBy && v.draw.pendingBy !== v.myColor) return '상대가 무승부를 제안했어요. [수락]하면 이 판은 비기고 끝나요. 계속하려면 [거절]을 눌러 주세요.';
|
||||
if (v.myColor !== v.turn) {
|
||||
const lines = [`상대(${turnNick}님) 차례예요. 상대가 둘 때까지 기다려 주세요. 나는 ${mine}이에요.`];
|
||||
if (v.checkSquare) lines.push('내가 상대 킹에 체크를 걸었어요. 상대는 킹을 지켜야 해요.');
|
||||
if (v.undo.pending || v.draw.pendingBy) lines.push(`내 ${v.undo.pending ? '무르기 요청' : '무승부 제안'}에 상대가 답하기를 기다리는 중이에요. 그만두려면 [요청 취소]를 눌러요.`);
|
||||
if (mat) lines.push(mat);
|
||||
return lines.join('\n');
|
||||
}
|
||||
const lines: string[] = [];
|
||||
if (v.checkSquare) lines.push('체크예요! 내 킹이 공격받고 있어요(빨갛게 빛나는 칸). 킹을 피하거나, 사이를 막거나, 공격한 기물을 잡는 수만 둘 수 있어요.');
|
||||
else lines.push(`내 차례예요(${mine}).`);
|
||||
lines.push(
|
||||
v.hints === 'off'
|
||||
? '움직일 기물을 누른 뒤 갈 칸을 누르거나, 기물을 끌어다 놓아요.'
|
||||
: '움직일 기물을 누르면 갈 수 있는 칸에 점이 찍혀요(잡을 수 있는 칸은 동그라미). 그 칸을 누르거나 끌어다 놓아요.',
|
||||
);
|
||||
if (!v.started[v.myColor]) lines.push(`첫 수는 ${v.firstMoveSec}초 안에 둬야 해요. 안 두면 대국이 취소돼요.`);
|
||||
const legal = v.legalMoves ?? [];
|
||||
if (legal.some((m) => m.promotion))
|
||||
lines.push(v.autoQueen ? '폰을 끝 줄로 보내면 자동으로 퀸이 돼요(승진).' : '폰을 끝 줄로 보내면 퀸·룩·비숍·나이트 중 무엇으로 바꿀지 고르는 창이 떠요(승진). 보통은 퀸이에요.');
|
||||
if (legal.some((m) => m.castle)) lines.push('지금 캐슬링을 할 수 있어요. 킹을 누르면 캐슬링할 칸도 표시돼요.');
|
||||
if (v.threatened?.length) lines.push('주황 점선 네모가 쳐진 내 기물은 지켜 주는 기물 없이 공격받고 있어요. 조심하세요.');
|
||||
if (v.drawMode === 'fide' && v.claimable)
|
||||
lines.push(`[⚖ 무승부 주장]을 누르면 상대 동의 없이 바로 비길 수 있어요(${v.claimable === 'threefold' ? '같은 국면 3번' : '50수 동안 폰 이동·잡기 없음'}).`);
|
||||
if (mat) lines.push(mat);
|
||||
return lines.join('\n');
|
||||
}
|
||||
Reference in New Issue
Block a user