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

适用于转换为2D坐标的数据结构及棋盘possibleCells数组格式化咨询

嘿,作为JS新手能想到优化数据结构来提升维护性,这点超棒!我来给你捋捋怎么解决这个问题~

一、优化possibleCells数组的格式化方案

核心思路:按攻击模式分组存储

把零散的相对坐标按攻击规则类型归类,比如直线攻击、斜线攻击、跳跃攻击(像国际象棋马的走法),每个类型用对象描述规则,这样一眼就能看懂棋子的攻击逻辑,维护起来也方便。

具体格式示例

根据不同棋子的攻击逻辑,我们可以把possibleCells设计成对象数组,每个对象对应一种攻击模式:

1. 直线/斜线无限攻击(比如车、象)

适合攻击范围沿固定方向延伸,直到棋盘边界或被阻挡的棋子:

// 车的攻击范围(上下左右直线无限步)
const rookPossibleCells = [
  {
    type: "straight", // 攻击类型:直线
    directions: [[-1, 0], [1, 0], [0, -1], [0, 1]], // 四个方向的单位步长
    maxSteps: Infinity // 最大步数:无限(直到边界)
  }
];

// 象的攻击范围(四条斜线无限步)
const bishopPossibleCells = [
  {
    type: "diagonal", // 攻击类型:斜线
    directions: [[-1, -1], [-1, 1], [1, -1], [1, 1]],
    maxSteps: Infinity
  }
];

2. 固定跳跃式攻击(比如马、兵)

适合攻击位置是离散的固定相对坐标,没有连续延伸的情况:

// 马的攻击范围(8种跳法)
const knightPossibleCells = [
  {
    type: "jump", // 攻击类型:跳跃
    positions: [[-2, -1], [-2, 1], [-1, -2], [-1, 2], [1, -2], [1, 2], [2, -1], [2, 1]] // 所有相对坐标
  }
];

// 兵的攻击范围(假设只能斜向前1步攻击)
const pawnPossibleCells = [
  {
    type: "jump",
    positions: [[1, -1], [1, 1]] // 假设y轴向下为正,兵在上方,攻击斜下方
  }
];

3. 混合攻击模式(比如后,兼具车和象的攻击)

直接把两种模式的对象放进数组就行,扩展性拉满:

// 后的攻击范围(直线+斜线)
const queenPossibleCells = [
  { type: "straight", directions: [[-1,0], [1,0], [0,-1], [0,1]], maxSteps: Infinity },
  { type: "diagonal", directions: [[-1,-1], [-1,1], [1,-1], [1,1]], maxSteps: Infinity }
];

为什么这样格式化更实用?

  • 可读性强:不用盯着一堆零散坐标猜逻辑,看type和参数就知道棋子怎么攻击
  • 维护方便:要修改攻击范围,直接改对应模式的参数就行,比如把兵的攻击步数改成2,只需要调整positions数组
  • 转换函数复用:可以写一个通用的转换函数,根据不同的type自动处理攻击范围计算(后面会给例子)
二、适合2D坐标的优质数据结构(JS新手友好)

作为新手,优先选容易理解、操作简单的结构,下面三种最常用:

1. 二维数组(Matrix)

最直观的棋盘结构,直接对应行列坐标,比如board[row][col],每个元素存储单元格的状态(比如是否有棋子、棋子类型):

// 初始化一个8x8的棋盘
const board = Array(8).fill(null).map(() => Array(8).fill(null));

// 给(2,3)位置放一个车
board[2][3] = { type: "rook", color: "white" };

// 获取(2,3)的棋子
const piece = board[2][3];

优点:新手容易理解,坐标访问速度快,适合棋盘大小固定的情况。

2. 对象映射(Object Map)

用字符串格式的坐标作为键,存储有棋子的位置,适合稀疏棋盘(大部分格子是空的):

const board = {};

// 给(2,3)位置放车
board["2,3"] = { type: "rook", color: "white" };

// 获取(2,3)的棋子
const piece = board["2,3"];

// 遍历所有有棋子的位置
for (const coord in board) {
  const [x, y] = coord.split(",").map(Number);
  console.log(`位置(${x},${y})有棋子:`, board[coord]);
}

优点:不用初始化整个棋盘,节省内存,适合大棋盘场景。

3. ES6 Map数据结构

和对象映射类似,但更灵活,支持迭代和复杂键(不过通常还是用字符串坐标):

const board = new Map();

// 给(2,3)位置放车
board.set("2,3", { type: "rook", color: "white" });

// 获取(2,3)的棋子
const piece = board.get("2,3");

// 遍历所有有棋子的位置
for (const [coord, piece] of board) {
  const [x, y] = coord.split(",").map(Number);
  console.log(`位置(${x},${y})有棋子:`, piece);
}

优点:比普通对象更安全(不会有原型链污染问题),迭代更方便,适合需要频繁添加/删除棋子的场景。

三、通用转换函数示例(把possibleCells转成绝对攻击坐标)

基于上面格式化的possibleCells,写一个通用函数,输入当前坐标、possibleCells和棋盘大小,就能算出所有攻击位置:

function getAttackPositions(currentX, currentY, possibleCells, boardSize) {
  const attackPositions = [];
  const { width, height } = boardSize;

  for (const pattern of possibleCells) {
    if (pattern.type === "jump") {
      // 处理跳跃式攻击:直接计算每个相对坐标的绝对位置
      for (const [dx, dy] of pattern.positions) {
        const newX = currentX + dx;
        const newY = currentY + dy;
        // 检查是否在棋盘范围内
        if (newX >= 0 && newX < width && newY >= 0 && newY < height) {
          attackPositions.push([newX, newY]);
        }
      }
    } else if (pattern.type === "straight" || pattern.type === "diagonal") {
      // 处理直线/斜线攻击:沿方向一步步延伸,直到边界
      for (const [dx, dy] of pattern.directions) {
        let step = 1;
        while (step <= pattern.maxSteps) {
          const newX = currentX + dx * step;
          const newY = currentY + dy * step;
          // 超出棋盘就停止当前方向
          if (newX < 0 || newX >= width || newY < 0 || newY >= height) break;
          // 添加攻击位置
          attackPositions.push([newX, newY]);
          // 如果需要考虑棋子阻挡(比如国际象棋规则),可以在这里加判断:
          // if (board[newY][newX] !== null) break;
          step++;
        }
      }
    }
  }

  return attackPositions;
}

// 用法示例:计算车在(3,3)位置的攻击范围(8x8棋盘)
const attackPositions = getAttackPositions(3, 3, rookPossibleCells, { width: 8, height: 8 });
console.log(attackPositions); // 输出所有车能攻击到的坐标

这样一来,不管是什么棋子,只要按格式定义好possibleCells,就能用这个函数算出攻击范围,完全不用重复写逻辑~

内容的提问来源于stack exchange,提问作者Gallaxhar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 09:01:33