如何不使用eval()实现棋盘棋子与方格对象的互相访问?
国际象棋棋盘性能优化方案
核心问题分析
当前实现中依赖eval()通过字符串名称获取对象,以及遍历方格查找关联对象的方式,导致深度预判走法时性能极差——计算深度2的400种走法耗时20秒。核心原因是eval()的动态解析开销极大,遍历查找也会带来不必要的时间消耗。
解决方案
1. 建立对象映射表(兼容现有逻辑的快速修改)
如果暂时无法调整现有对象的初始化流程,创建两个全局/模块级的映射对象,将字符串名称与实际对象直接关联:
// 存储所有方格对象,键为方格名称字符串 const squaresMap = { a1, a2, a3, ..., h8 // 填入所有已创建的方格对象 }; // 存储所有棋子对象,键为棋子名称字符串 const piecesMap = { whiteRook1, whiteRook2, whiteKing, ..., blackQueen // 填入所有已创建的棋子对象 };
替换所有eval()调用为映射表查找:
- 查询a1方格中棋子是否存活:
console.log(piecesMap[a1.occupiedBy].alive); // true
- 查询a1前方方格是否空闲:
console.log(squaresMap[a1.north1].occupiedBy !== 'none'); // false
这种方式将eval()的动态解析替换为O(1)的对象属性访问,性能会得到质的提升。
2. 初始化时直接存储对象引用(最优性能方案)
如果可以调整对象的初始化顺序,直接在对象属性中存储对方的引用而非字符串名称,完全消除字符串查找开销:
实现步骤:
- 先创建空的映射表(解决初始化顺序冲突问题):
const squares = {}; const pieces = {};
- 创建所有方格对象并存入映射表,后续统一设置相邻方格引用:
// 先创建所有方格框架 squares.a1 = { occupiedBy: null, north1: null, east1: null /* 其他属性 */ }; squares.a2 = { occupiedBy: null, south1: null, north1: null /* 其他属性 */ }; // ... 依次创建a3到h8的所有方格 // 统一设置相邻方格的引用 squares.a1.north1 = squares.a2; squares.a2.south1 = squares.a1; squares.a1.east1 = squares.b1; squares.b1.west1 = squares.a1; // ... 完成所有相邻方格的关联
- 创建棋子对象并与方格双向关联:
pieces.whiteRook1 = { square: squares.a1, value: 5, alive: true, // 其他属性 }; // 将棋子关联到对应方格 squares.a1.occupiedBy = pieces.whiteRook1;
访问方式:
- 查询a1方格中棋子是否存活:
console.log(squares.a1.occupiedBy.alive); // true
- 查询a1前方方格是否空闲:
console.log(squares.a1.north1.occupiedBy === null); // false
JS允许对象循环引用,只要不需要序列化这些对象(如存储到本地或网络传输),就不会有任何问题,这种方式的性能是最优的。
3. 避免遍历查找的补充技巧
如果需要通过棋子快速定位方格(或反之),可以给每个对象添加唯一标识属性(比如方格加squareId,棋子加pieceId),结合映射表实现O(1)的查找,彻底避免遍历64个方格的低效操作。
内容的提问来源于stack exchange,提问作者panup
相关产品推荐
相关产品推荐

