fix: 代码审查修复 — serde camelCase/CSP/TS检查/replay/undo/AI禁手/星位/未使用依赖

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-31 12:51:53 +08:00
parent bb4f393229
commit ffcc7a7675
27 changed files with 9032 additions and 181 deletions
+23 -5
View File
@@ -1,5 +1,5 @@
import { useEffect, useRef, useCallback } from 'react';
import { useGameStore } from '../../store/gameStore';
import { useEffect, useRef, useCallback, useMemo } from 'react';
import { useGameStore, buildReplayBoard } from '../../store/gameStore';
import {
computeBoardDimensions,
canvasToBoard,
@@ -15,8 +15,26 @@ export default function BoardCanvas() {
const placePiece = useGameStore((s) => s.placePiece);
const aiMove = useGameStore((s) => s.aiMove);
const moves = useGameStore((s) => s.moves);
const replayStep = useGameStore((s) => s.replayStep);
const lastMove = moves.length > 0 ? moves[moves.length - 1].position : null;
// 复盘模式下根据 replayStep 重建棋盘
const displayBoard = useMemo(() => {
if (mode === 'Replay') {
return buildReplayBoard(boardSize, moves, replayStep);
}
return board;
}, [mode, board, boardSize, moves, replayStep]);
// 复盘模式下的最后一手
const displayLastMove = useMemo(() => {
if (mode !== 'Replay') {
return moves.length > 0 ? moves[moves.length - 1].position : null;
}
if (replayStep > 0 && replayStep <= moves.length) {
return moves[replayStep - 1].position;
}
return null;
}, [mode, moves, replayStep]);
const render = useCallback(() => {
const canvas = canvasRef.current;
@@ -31,8 +49,8 @@ export default function BoardCanvas() {
ctx.scale(dpr, dpr);
const cfg = computeBoardDimensions(boardSize, rect.width, rect.height);
renderBoard(ctx, board, cfg, lastMove);
}, [board, boardSize, lastMove]);
renderBoard(ctx, displayBoard, cfg, displayLastMove);
}, [displayBoard, boardSize, displayLastMove]);
useEffect(() => {
render();
+22 -6
View File
@@ -6,6 +6,26 @@ export interface RenderConfig {
boardSize: number;
}
/**
* 根据棋盘大小动态生成星位坐标。
* 标准五子棋/围棋星位: 四角和中心及边中点。
* 9x9 起可用,更小的棋盘仅使用中心点。
*/
export function computeStarPoints(boardSize: number): [number, number][] {
if (boardSize < 9) {
const mid = Math.floor(boardSize / 2);
return [[mid, mid]];
}
const a = Math.min(3, Math.floor(boardSize / 4));
const b = Math.floor(boardSize / 2);
const c = boardSize - 1 - a;
return [
[a, a], [a, b], [a, c],
[b, a], [b, b], [b, c],
[c, a], [c, b], [c, c],
];
}
export function computeBoardDimensions(boardSize: number, canvasWidth: number, canvasHeight: number): RenderConfig {
const maxBoardPixelSize = Math.min(canvasWidth, canvasHeight) * 0.85;
const cellSize = Math.floor(maxBoardPixelSize / (boardSize - 1));
@@ -64,12 +84,8 @@ export function renderBoard(
ctx.stroke();
}
// 星位
const starPoints = [
[3, 3], [3, 7], [3, 11],
[7, 3], [7, 7], [7, 11],
[11, 3], [11, 7], [11, 11],
];
// 星位 — 根据棋盘大小动态计算
const starPoints = computeStarPoints(boardSize);
ctx.fillStyle = '#8B7355';
for (const [r, c] of starPoints) {
if (r < boardSize && c < boardSize) {