You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何快速克隆数组以优化国际象棋AI走子回退的运行性能?

问题解答

首先直接回答你最关心的疑问:绝对不能直接用int[] piecesBackup = pieces的引用赋值方式做备份。
C#里数组是引用类型,这种写法只是把piecesBackup变量指向了和pieces同一块堆内存,并没有保存走子前的状态快照。后续执行MakeMove()修改数组内容时,两个变量访问的是同一份数据,备份会跟着走子操作一起被修改,最后执行pieces = piecesBackup根本回滚不到之前的状态,逻辑完全错误。


你当前代码性能差的核心原因

你现在的实现做了非常多冗余操作:

  • 备份时做一次全数组拷贝,恢复时又重新new新数组、再做一次全数组拷贝,一次走子+撤销流程平白多了一次内存分配和一次全量复制
  • Clone()方法存在类型转换开销,CopyTo()内部也有额外的参数校验,本身就不是性能最优的拷贝方式
  • 每次恢复都new新数组会产生大量短命小对象,GC回收的开销很多时候比数组拷贝本身还高

如果只是临时优化现有全量备份逻辑,直接改成下面的写法就能快很多:

// 全局提前初始化固定长度的备份数组,不要每次走子都重复创建
// 国际象棋棋盘固定8*8=64格,数组长度可以直接写死
private int[] piecesBackup = new int[64];

void ExecuteAndRollbackMove()
{
    // 备份:仅做一次全量拷贝,用BCL原生优化的Array.Copy方法
    Array.Copy(pieces, piecesBackup, pieces.Length);
    
    MakeMove();
    
    // 恢复:直接把备份内容拷回原数组,不需要new新数组
    Array.Copy(piecesBackup, pieces, pieces.Length);
}

这种改法不需要调整你现有逻辑,就能把拷贝相关的开销砍掉至少一半。


国际象棋AI场景下的最优方案:增量撤销

全量拷贝哪怕优化到极致,在AI搜索场景下依然是性能瓶颈——毕竟你做极大极小/α-β剪枝搜索时,哪怕单步只花1微秒,搜6层累积几十万次走子的开销也非常夸张。
所有成熟的国际象棋/象棋类AI都不会用全量拷贝棋盘的方式做回滚,而是用走子栈存储增量变更:

  • 执行MakeMove()的时候,不要提前备份整个数组,只需要把这一步走子实际修改的内容压入栈中:比如移动棋子的原位置、目标位置、有没有吃子(被吃棋子的类型和位置)、走子前王的将军状态、受攻击列表里变动的条目
  • 撤销走子的时候,根本不需要回滚整个数组,只需要弹出栈顶的增量记录,把改动过的几个位置改回原值就行
  • 普通走子一般只会改动2-4个棋盘位置的状态,对比每次拷贝64个甚至更多元素的全量拷贝,性能差距可以达到10~20倍,搜索深度越高,优势越明显。

内容的提问来源于stack exchange,提问作者Elia Giaccardi Old

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 23:42:26