M9: 게임 26종 30초 요약 카드·[?] 지금 할 수 있는 것 내용

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
EJClaw
2026-10-06 13:35:21 +09:00
parent 32e3e89d8d
commit 68edd9b434
102 changed files with 6555 additions and 1 deletions

View File

@@ -0,0 +1,77 @@
/** 체스 30초 규칙 요약 (docs/07 §5). */
import type { QuickCard } from '../types';
const GLYPH: Record<string, string> = { k: '♚', q: '♛', r: '♜', b: '♝', n: '♞', p: '♟' };
/** One piece as a text glyph (filled shape, coloured by side). `︎` keeps ♟ from turning into an emoji. */
function Piece({ t, x, y }: { t: string; x: number; y: number }) {
const white = t === t.toUpperCase();
return (
<text
x={x + 0.5}
y={y + 0.56}
fontSize={0.82}
textAnchor="middle"
dominantBaseline="central"
fontFamily="'Segoe UI Symbol', 'Noto Sans Symbols 2', 'DejaVu Sans', serif"
fill={white ? '#fbfbf8' : '#1b1b1b'}
stroke={white ? '#333' : '#000'}
strokeWidth={0.03}
>
{GLYPH[t.toLowerCase()]}
{'︎'}
</text>
);
}
/** Small chess board; `rows` use FEN letters (uppercase = white) and '.' for empty. */
function MiniBoard({ rows, dots = [], check, size = 150 }: { rows: string[]; dots?: [number, number][]; check?: [number, number]; size?: number }) {
const h = rows.length;
const w = rows[0]!.length;
const scale = size / Math.max(w, h);
return (
<svg viewBox={`0 0 ${w} ${h}`} width={w * scale} height={h * scale} aria-hidden style={{ borderRadius: 6 }}>
{rows.map((r, y) =>
r.split('').map((_, x) => <rect key={`${x}-${y}`} x={x} y={y} width={1} height={1} fill={(x + y) % 2 === 0 ? '#f0d9b5' : '#b58863'} />),
)}
{check && <rect x={check[0]} y={check[1]} width={1} height={1} fill="#ef4444" opacity={0.7} />}
{dots.map(([x, y]) => (
<circle key={`d${x}-${y}`} cx={x + 0.5} cy={y + 0.5} r={0.16} fill="rgba(20,85,30,0.55)" />
))}
{rows.map((r, y) => r.split('').map((c, x) => (c === '.' ? null : <Piece key={`p${x}-${y}`} t={c} x={x} y={y} />)))}
</svg>
);
}
const Arrow = () => (
<span aria-hidden style={{ fontSize: 28, fontWeight: 800 }}>
→
</span>
);
export const quickStart: QuickCard[] = [
{
pic: <MiniBoard rows={['R.k.', '.ppp']} check={[2, 0]} size={200} />,
alt: '흰 룩이 검은 킹을 공격하고, 킹은 자기 폰에 막혀 피할 곳이 없어요',
title: '킹을 꼼짝 못 하게',
text: '백이 먼저 두고 번갈아 한 수씩 둬요. 상대 킹을 공격해서 피할 곳이 없게 만들면(체크메이트) 이겨요.',
},
{
pic: <MiniBoard rows={['.....', '.....', '..N..', '.....', '.....']} dots={[[1, 0], [3, 0], [0, 1], [4, 1], [0, 3], [4, 3], [1, 4], [3, 4]]} size={150} />,
alt: '가운데 나이트 둘레로 ㄱ자 모양 여덟 칸에 점이 찍혀 있어요',
title: '기물마다 길이 달라요',
text: '기물을 누르면 갈 수 있는 칸에 점이 찍혀요. 그 칸을 누르면 움직여요. 상대 기물이 있는 칸으로 가면 잡아요.',
},
{
pic: (
<>
<MiniBoard rows={['.', 'P']} size={90} />
<Arrow />
<MiniBoard rows={['Q', '.']} size={90} />
</>
),
alt: '흰 폰이 끝 줄에 닿아 퀸으로 바뀌어요',
title: '폰이 끝까지 가면 변신',
text: '폰이 끝 줄에 닿으면 퀸 같은 강한 기물로 바뀌어요(승진). 내 킹이 공격받으면(체크) 꼭 먼저 피하거나 막아야 해요.',
},
];