Spaces:
Sleeping
Sleeping
| /* | |
| 这段代码定义了一个React组件Control,它是一个用户界面控制面板,用于启动和结束游戏、悔棋、设置AI的一些参数等。 | |
| 它使用react-redux的useDispatch和useSelector来与Redux状态管理库交互,允许它派发动作并获取状态。 | |
| 这个组件有以下几个部分: | |
| 按钮组: 提供开始游戏、悔棋和认输的操作。 | |
| 设置项: 允许用户设置AI是否先手、AI的类型(深度)、是否显示序号。 | |
| 状态显示: 显示当前的评分、搜索深度、搜索路径和历史步骤。 | |
| 组件中使用了antd库的Button、Switch和Select组件来创建用户界面。 | |
| */ | |
| // 引入React和CSS样式文件 | |
| import React from 'react'; | |
| import './control.css'; | |
| // 引入Redux的钩子函数,用于状态管理和动作派发 | |
| import { useDispatch, useSelector } from 'react-redux'; | |
| // 引入游戏状态管理的动作 | |
| import { startGame, endGame, undoMove, setAiFirst, setDepth, setIndex } from '../store/gameSlice'; | |
| // 引入游戏的配置信息,如棋盘大小 | |
| import { board_size } from '../config'; | |
| // 引入antd库中的组件供我们使用 | |
| import { Button, Switch, Select } from 'antd'; | |
| // 引入游戏的状态常量 | |
| import { STATUS } from '../status'; | |
| // 引入React的钩子函数,用于记忆函数,以避免不必要的重新渲染 | |
| import { useCallback } from 'react'; | |
| // 定义Control组件 | |
| function Control() { | |
| // 使用dispatch发送动作到Redux的store | |
| const dispatch = useDispatch(); | |
| // 通过useSelector从Redux的store中获取游戏状态数据 | |
| const { loading, winner, status, history, aiFirst, depth, index, score, path, currentDepth } = | |
| useSelector((state) => state.game); | |
| // useCallback是React的一个钩子,用于缓存函数,以便在组件的重新渲染之间保持函数的引用不变,除非依赖项发生变化。 | |
| // 这里创建了一个start函数,该函数在调用时会调用dispatch函数并发送一个startGame动作,这个动作带有关于棋盘大小、AI是否先手和AI深度的参数。 | |
| // useCallback的第二个参数是依赖项数组,只有当这些依赖项发生变化时,函数start才会被重新创建。 | |
| const start = useCallback(() => { | |
| dispatch(startGame({board_size, aiFirst, depth})); | |
| }, [dispatch, board_size, aiFirst, depth]); | |
| // 缓存结束游戏的函数 | |
| const end = useCallback(() => { | |
| dispatch(endGame()); | |
| }, [dispatch]); | |
| // 缓存悔棋的函数 | |
| const undo = useCallback(() => { | |
| dispatch(undoMove()); | |
| }, [dispatch]); | |
| // 缓存改变AI先手的函数 | |
| const onFirstChange = useCallback((checked) => { | |
| dispatch(setAiFirst(checked)); | |
| }, [dispatch]); | |
| // 缓存改变AI深度的函数 | |
| const onDepthChange = useCallback((value) => { | |
| dispatch(setDepth(value)); | |
| }, [dispatch]); | |
| // 缓存改变序号显示的函数 | |
| const onIndexChange = useCallback((checked) => { | |
| dispatch(setIndex(checked)); | |
| }, [dispatch]); | |
| // 渲染组件 | |
| return ( | |
| <div className="controle"> | |
| <div className="buttons"> | |
| {/* 开始按钮,当游戏正在加载或不在空闲状态时禁用*/} | |
| <Button className="button" type="primary" onClick={start} disabled={loading || status !== STATUS.IDLE}>开始</Button> | |
| {/* 悔棋按钮,当游戏正在加载或不在游戏进行状态或没有历史步骤时禁用*/} | |
| <Button className="button" type="primary" onClick={undo} disabled={loading || status !== STATUS.GAMING || history.length === 0}>悔棋</Button> | |
| {/* 认输按钮,当游戏正在加载或不在游戏进行状态时禁用*/} | |
| <Button className="button" type="primary" onClick={end} disabled={loading || status !== STATUS.GAMING}>认输</Button> | |
| </div> | |
| <div className="setting"> | |
| {/* AI先手开关*/} | |
| <div className="setting-item"> | |
| AI 先手: <Switch defaultChecked={aiFirst} onChange={onFirstChange} disabled={loading} /> | |
| </div> | |
| {/* AI类型选择器,包含不同深度的AI选项*/} | |
| <div className="setting-item"> | |
| AI 类型: | |
| <Select | |
| defaultValue={String(depth)} | |
| style={{ width: 200 }} | |
| onChange={onDepthChange} | |
| disabled={loading} | |
| options={[ | |
| // 选项中的value代表AI的深度,label是显示给用户看的类型名称 | |
| { value: '-2', label: 'Random' }, | |
| { value: '-1', label: 'RuleBot' }, | |
| { value: '0', label: 'AlphaZero' }, | |
| { value: '2', label: 'AB-2' }, | |
| { value: '4', label: 'AB-4' }, | |
| // 注释掉的是其他可能的AI类型选项,这些被替换为更专业的名称了 | |
| // { value: '2', label: '弱智' }, | |
| // { value: '4', label: '简单' }, | |
| // { value: '6', label: '普通' }, | |
| // { value: '8', label: '困难' }, | |
| ]} | |
| /> | |
| </div> | |
| {/* 序号开关,控制是否显示序号*/} | |
| <div className="setting-item"> | |
| 显示棋子步数: <Switch defaultChecked={index} onChange={onIndexChange} /> | |
| </div> | |
| </div> | |
| {/* 状态显示区域,显示当前评分、深度、路径和历史步骤 */} | |
| <div className="status"> | |
| <div className="status-item">评分:{score}</div> | |
| <div className="status-item">深度: {currentDepth}</div> | |
| <div className="status-item">路径: {JSON.stringify(path)}</div> | |
| {/* 历史步骤是一个数组,这里将其转换为JSON字符串显示,并且只显示每个步骤的(i, j)坐标 */} | |
| <div className="status-item">历史: {JSON.stringify(history.map(h => [h.i, h.j]))}</div> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| // 导出Control组件,使其可以在其他文件中被引入和使用 | |
| export default Control; | |