예제 소스
오목으로 이해하는 자기대국과 모방 학습 · 파일 59개
OmokBoard.tsx
"use client";
import { EMPTY, BLACK, WHITE, hoshiPoints, type Point, type Stone } from "@/lib/board";
import styles from "./OmokBoard.module.css";
type Props = {
board: Stone[];
size: number;
lastMove: Point | null;
pending: Point | null;
banned?: Point[];
onSelect: (r: number, c: number) => void;
interactive: boolean;
};
export function OmokBoard({
board,
size,
lastMove,
pending,
banned = [],
onSelect,
interactive,
}: Props) {
const hoshi = hoshiPoints(size);
const lastIdx = size - 1;
const cells = [];
for (let r = 0; r < size; r++) {
for (let c = 0; c < size; c++) {
const i = r * size + c;
const v = board[i];
const isStar = hoshi.some((p) => p.r === r && p.c === c);
const isLast = Boolean(lastMove && lastMove.r === r && lastMove.c === c);
const isPending = Boolean(pending && pending.r === r && pending.c === c);
const isBan = banned.some((p) => p.r === r && p.c === c);
cells.push(
<button
key={`${r}-${c}`}
type="button"
className={styles.cell}
style={{ gridColumn: c + 1, gridRow: r + 1 }}
disabled={!interactive || v !== EMPTY}
onClick={() => onSelect(r, c)}
aria-label={`${r},${c}`}
>
{isStar && v === EMPTY && !isPending ? <span className={styles.star} /> : null}
{v === BLACK ? <span className={`${styles.stone} ${styles.black}`} /> : null}
{v === WHITE ? <span className={`${styles.stone} ${styles.white}`} /> : null}
{isPending && v === EMPTY ? <span className={styles.ghost} /> : null}
{isBan && v === EMPTY && !isPending ? <span className={styles.ban} /> : null}
{isLast ? <span className={styles.mark} /> : null}
</button>,
);
}
}
return (
<div className={styles.frame}>
<div
className={styles.grid}
style={{
gridTemplateColumns: `repeat(${size}, 1fr)`,
gridTemplateRows: `repeat(${size}, 1fr)`,
}}
role="grid"
aria-label={`${size}×${size} 오목판`}
>
<svg
className={styles.lines}
viewBox={`0 0 ${size} ${size}`}
preserveAspectRatio="none"
>
{Array.from({ length: size }, (_, i) => (
<g key={i}>
<line x1={0.5} y1={i + 0.5} x2={lastIdx + 0.5} y2={i + 0.5} />
<line x1={i + 0.5} y1={0.5} x2={i + 0.5} y2={lastIdx + 0.5} />
</g>
))}
</svg>
{cells}
</div>
</div>
);
}