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

战舰游戏中获取有效新坐标解决越界报错问题

战舰游戏随机放置船只越界问题及修复方案

随机放置战舰时出现越界报错:

Uncaught TypeError: Cannot set properties of undefined (setting '4')

已实现placeHorizontal和placeVertical函数,希望坐标无效时获取新坐标重新放置,但暂未实现getNewCoords函数,相关代码如下:

Gameboard代码

const Gameboard = () => {
  const rows = 10
  const columns = 10
  const board = []
  const missedCoord = []
  const shipArr = []
  const attackCoord = []

  const getBoard = () => [...board]

  const Water = () => {
    let isHit = false
    const hit = () => {
      isHit = true
    };
    return {
      type: "water",
      hit,
      get isHit() {
        if (isHit) {
          return "BLOOP! Miss."
        }
        return "Ship hit!"
      }
    }
  }

  for (let i = 0; i < rows; i += 1) {
    board[i] = []
    for (let j = 0; j < columns; j += 1) {
      board[i][j] = Water()
    }
  }

  // Need to reduce array amount to a single value
  const cellCount = getBoard().reduce((row, col) => row + col.length, 0)

  const validCoords = (x, y) => {
    if (x < 0) {
      return false
    }
    if (x > 9) {
      return false
    }
    if (y < 0) {
      return false
    }
    if (y > 9) {
      return false
    }
    return true
  }

  const getNewCoords = (x, y) => {

  }

  const placeHorizontal = (x, y, ship) => {
    const shipsLength = ship.getLength()
    const currentBoard = getBoard()

    // Loop through ships length
    for (let i = 0; i < shipsLength; i += 1) {
      // Change ship.name back to ship
      currentBoard[x][y + i] = ship.name
      shipArr.push(ship)
    }
    return true
  }

  const placeVertical = (x, y, ship) => {
    const check = validCoords(x, y)
    if (!check) {
      const newXandY = getNewCoords(x, y)
      return placeVertical(newXandY)
    }
    const shipsLength = ship.getLength()
    const currentBoard = getBoard()

    // Loop through ships length
    for (let i = 0; i < shipsLength; i += 1) {
      // Change ship.name back to ship
      currentBoard[x + i][y] = ship.name
      shipArr.push(ship)
    }
    return true
  }

  function canShipBeHitAgain(x, y) {
    const coords = [x, y]
    const coordStr = JSON.stringify(coords)
    const attackCoordStr = JSON.stringify(attackCoord[0])

    if (coordStr === attackCoordStr) {
      console.log("Cannot hit same spot!")
      return false
    }
    return true
  }

  function receiveAttack(x, y) {
    const water = Water()
    const currentBoard = getBoard()

    if (currentBoard[x][y].hit() && canShipBeHitAgain(x, y)) {
      attackCoord.push([x, y])
      return true
    }
    water.hit()
    missedCoord.push([x, y])
    return false
  }

  function allSunk() {
    shipArr.every((ship) => {
      if (!ship.isSunk()) {
        console.log("All ships are not sunk.")
        return false
      }
      return console.log("All ships are sunk!")
    })
    return true
  }
  return {
    placeVertical,
    placeHorizontal,
    getBoard,
    cellCount,
    receiveAttack,
    allSunk,
    canShipBeHitAgain,
    validCoords
  }
}

AI/电脑放置逻辑代码

const createComputer = () => {
  const computerGameboard = Gameboard()
  // const getCompBoard = computerGameboard.getBoard()

  const placeShipHorizontal = (ship) => {
    let x;
    let y;
    do {
      x = Math.floor((Math.random() * 9));
      y = Math.floor((Math.random() * 9));
    }
    while (computerGameboard.placeHorizontal(x, y, ship) === false);
    computerGameboard.placeHorizontal(x, y, ship)
    return true
  }

  const placeShipVertical = (ship) => {
    let x;
    let y;
    do {
      x = Math.floor((Math.random() * 9));
      y = Math.floor((Math.random() * 9));
    }
    while (computerGameboard.placeVertical(x, y, ship) === false);
    computerGameboard.placeVertical(x, y, ship)
    return true
  }

  const setEnemyBoard = (player) => player.getPlayerBoard

  return {
    computerGameboard,
    setEnemyBoard,
    placeShipHorizontal,
    placeShipVertical
  }
}

const computer = createComputer()
computer.setEnemyBoard(player)
const testShip = createShip(3, "1")
const testShip2 = createShip(3, "2")

computer.placeShipVertical(testShip)
computer.placeShipHorizontal(testShip2)

问题分析与修复方案

1. 报错根源

当前placeHorizontal和placeVertical仅检查初始坐标是否有效,未验证整个船只放置范围是否在棋盘内。例如横向放置时,若y + 船长度 - 1 > 9,则currentBoard[x][y+i]会访问到undefined的数组索引,触发报错。同时,放置函数未检查目标位置是否已被占用,会导致船只重叠。

2. 修复步骤

(1)更新有效性检查逻辑

新增检查整个船只放置范围的函数,替换原validCoords:

// 检查横向放置是否合法:坐标在棋盘内,且目标位置未被占用
const canPlaceHorizontal = (x, y, shipLength) => {
  if (x < 0 || x > 9) return false;
  if (y + shipLength - 1 > 9) return false;
  for (let i = 0; i < shipLength; i++) {
    if (board[x][y+i].type !== "water") return false;
  }
  return true;
};

// 检查纵向放置是否合法:坐标在棋盘内,且目标位置未被占用
const canPlaceVertical = (x, y, shipLength) => {
  if (y < 0 || y > 9) return false;
  if (x + shipLength - 1 > 9) return false;
  for (let i = 0; i < shipLength; i++) {
    if (board[x+i][y].type !== "water") return false;
  }
  return true;
};
(2)修复放置函数

修改placeHorizontal和placeVertical,先做合法性检查,无效则返回false,让电脑的do-while循环重新生成坐标:

const placeHorizontal = (x, y, ship) => {
  const shipLength = ship.getLength();
  if (!canPlaceHorizontal(x, y, shipLength)) return false;

  for (let i = 0; i < shipLength; i += 1) {
    board[x][y + i] = ship; // 建议直接存储ship对象,方便后续攻击判断
  }
  shipArr.push(ship); // 移出循环,避免重复添加同一艘船
  return true;
};

const placeVertical = (x, y, ship) => {
  const shipLength = ship.getLength();
  if (!canPlaceVertical(x, y, shipLength)) return false;

  for (let i = 0; i < shipLength; i += 1) {
    board[x + i][y] = ship;
  }
  shipArr.push(ship);
  return true;
};
(3)实现getNewCoords(可选)

若需单独生成合法随机坐标,可实现如下:

const getNewCoords = () => {
  return {
    x: Math.floor(Math.random() * 10),
    y: Math.floor(Math.random() * 10)
  };
};

如果要在placeVertical中使用该函数,需修正递归调用的参数:

const placeVertical = (x, y, ship) => {
  const shipLength = ship.getLength();
  if (canPlaceVertical(x, y, shipLength)) {
    // 放置逻辑...
    return true;
  }
  const newCoords = getNewCoords();
  return placeVertical(newCoords.x, newCoords.y, ship);
};
(4)修复电脑放置逻辑的坐标范围

原代码中Math.random() *9仅生成0-8的坐标,改为Math.random() *10覆盖0-9的完整棋盘:

const placeShipHorizontal = (ship) => {
  let x;
  let y;
  do {
    x = Math.floor(Math.random() * 10);
    y = Math.floor(Math.random() * 10);
  } while (!computerGameboard.placeHorizontal(x, y, ship));
  return true;
};

const placeShipVertical = (ship) => {
  let x;
  let y;
  do {
    x = Math.floor(Math.random() * 10);
    y = Math.floor(Math.random() * 10);
  } while (!computerGameboard.placeVertical(x, y, ship));
  return true;
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 05:09:51