/* 此代码是一个React组件,用于实现一个五子棋游戏的棋盘。该棋盘能够响应用户点击,将点击位置转换为棋子坐标,并根据游戏状态更新棋盘上的棋子。 它使用了React的hooks,Redux来管理状态,以及axios来与服务器通信。该组件还负责展现棋子的历史记录以及高亮最后一个落子位置。棋盘和棋子的样式通过CSS实现。 */ // 引入React的核心功能 import React, { useState, useEffect } from "react"; // 引入Redux的hook,用于派发action和选择器 import { useDispatch, useSelector } from 'react-redux'; // 引入Redux store中的动作 import { movePiece, tempMove } from '../store/gameSlice'; // 引入CSS样式文件 import './board.css'; // 引入背景图片 import bg from '../assets/bg.jpg'; // 引入棋盘大小的配置 import { board_size } from '../config'; // 引入游戏状态的常量 import { STATUS } from '../status'; // 引入axios库用于发起HTTP请求 import axios from 'axios'; // 定义Board组件 const Board = () => { // 使用Redux的hook来获取dispatch方法 const dispatch = useDispatch(); // 使用Redux的hook来从store中选取需要的游戏数据 const { board, currentPlayer, history, status, size, loading, winner, depth, index } = useSelector((state) => state.game); // 定义点击棋盘的事件处理函数 const handleClick = async (i, j) => { // 如果游戏正在加载或者不在游戏中,则不处理点击 if (loading || status !== STATUS.GAMING) { console.log(loading, status); console.log(' loading || status !== STATUS.GAMING '); return; } // 如果点击的位置没有棋子 if (board[i][j] === 0) { // 如果深度小于等于0,需要与服务器通信 if (depth <= 0) { try { // 先在本地进行临时移动 dispatch(tempMove([i, j])) // 向服务器发送步骤信息,并等待响应 const response = await axios.post('https://zjowowen-gomoku.hf.space/gomoku_server_ui/', { command: 'step', argument: [i, j, depth], // [i,j] 表示玩家点击的动作,当depth<=0时,根据 depth 确定 Agent Type uid: ':1' // 如果需要的话,这里应填入玩家的唯一标识符 }); // 服务器响应的数据,这里假设服务器返回的 Agent 动作格式为 {'i': x, 'j': y } const agentAction = response.data.result.action; // 使用服务器返回的动作更新Redux store dispatch(movePiece({ position: [i, j, agentAction.i, agentAction.j], depth: depth })); } catch (error) { // 如果通信失败,则打印错误信息 console.error('Error communicating with the server: ', error.response || error); } } else { // 如果不需要与服务器通信,直接在本地执行移动 dispatch(tempMove([i, j])) dispatch(movePiece({ position: [i, j], depth })); console.log('depth > 0 '); } } }; // 使用effect hook来处理胜利者的出现 useEffect(() => { // 如果有胜利者出现,弹出提示框 if (winner === 1 || winner === -1) { window.alert(winner === 1 ? '黑棋获胜' : '白棋获胜') } }, [winner]); // 计算单个棋盘格子的样式 const cellStyle = { width: `${375 / board_size}px`, height: `${375 / board_size}px`, }; // 渲染棋盘组件 return (
{/* 遍历棋盘数组,渲染每一行 */} {board.map((row, i) => (
{/* 遍历棋盘的每一列,渲染每一个格子 */} {row.map((cell, j) => { // 根据格子位置给格子添加不同的边界样式 let cellClassName = 'cell'; if (i === 0) { cellClassName += ' top'; } if (i === board_size - 1) { cellClassName += ' bottom'; } if (j === 0) { cellClassName += ' left'; } if (j === board_size - 1) { cellClassName += ' right'; } // 根据格子内棋子的状态给棋子添加不同的样式 let pieceClassname = 'piece'; if (cell === 1) { pieceClassname += ' black'; } else if (cell === -1) { pieceClassname += ' white'; } // 判断当前格子是否为最后落子的格子 let isLastCell = false; const lastMove = history[history.length - 1]; if (lastMove && (lastMove.i === i && lastMove.j === j)) { isLastCell = true; } // 如果显示历史记录索引,则计算当前棋子的序号 let number = 0; if (index) { for(let x = 0; x < history.length; x++) { if (history[x].i === i && history[x].j === j) { number = x + 1; break; } } } // 渲染每一个格子,包括棋子和最后落子的标记 return (
handleClick(i, j)}> {cell == 0 ? '' :
{ number === 0 ? '' : number}
} {isLastCell &&
}
) })}
))}
); }; // 导出Board组件以便在其他文件中使用 export default Board;