如何验证战舰领域?

时间:2011-09-21 14:16:03

标签: java algorithm

我正在尝试使用以下规则验证battleship字段:

  • 船舶不要与侧面或角落接触;
  • 船只是直的;
  • 有1×4甲板船,2×3甲板,3×2甲板,4×1甲板船。

该字段表示为byte[10][10]数组。 我可以用什么算法来实现这个目标? 我使用的语言是Java,但任何语言都很好。

6 个答案:

答案 0 :(得分:9)

快速检查有效性:1×4甲板船,2×3甲板,3×2甲板,4×1甲板船只必须正好占用1 * 4 + 2 * 3 + 3 * 2 + 4 * 1 = 20个细胞。因此,如果您的字段不包含20个单元格,则它无效(船舶重叠或船舶不足)

现在,您需要验证每种类型的船舶的编号是否正确,并且船舶不会触及。您可以通过connected component analysis执行此操作。简单的两遍算法将在这里完成(链接中有伪代码和示例)。这将为您提供您所在领域中每个“blob”的大小,位置和形状。

从那里,你只需要迭代每个blob并检查它是垂直线还是水平线。这很简单 - 只计算blob的宽度(最大和最小列值之间的差异)和高度(最大和最小行值之间的差异)。其中一个必须等​​于1.如果不是,则两艘船正在接触,并且该场无效。

最后,检查每种船型的编号是否正确。如果不这样做,则该字段无效。如果你这样做,那么这个字段是有效的,你已经完成了。

修改

船舶也可以端到端接触,但这会减少船舶的总数(增加某种类型的船舶数量),从而无法进行最后一次测试。

编辑2

已更正使用正确的船舶规格。

答案 1 :(得分:2)

简单的算法。主要思想:每个“完整”字段必须分配给某艘船。

  1. 对于每个可能的船形状构造小矩阵,其保持其图案并记录其宽度和高度。每艘船的边界应为宽边1,以确保没有邻接。
  2. 对于每种可能的船形,都要经过战场并检查 基本模式 - 检查船是否在那里。
  3. 如果模式匹配,即船舶在那里,那么只需将所有基础方块标记为属于该船舶。宽度为1的空边距确保没有其他船只/战场边缘接触此船。
  4. 对所有可能的船型重复步骤2和3
  5. 穿过战场,检查每个方格是否被标记为属于某艘船。如果是,那么该字段是正确的。如果不是,则战场不正确。

答案 2 :(得分:2)

伪代码:

initialise the ship map with pairs of (size, amount of ships) values

initialise your map[12][12]:
  for every place at row and column coordinate of 0 or 11 (the border)
    mark it as visited
  for every other place
     mark it as not visited
     fill it with either ship or ocean tile from your input

for each row from 1 to 10
  for each column from 1 to 10
    if that place has not been visited yet
      mark that place as visited
      if that place is a ship tile
        check the places to the "right" (bigger column numbers)
          ... and bottom (bigger "row" numbers)
          until you hit a visited or ocean tile
        the amount of ship tiles checked (including the first) is current ship's length
        decrease the amount of ships of that length in the ship map by one
        mark all ship tiles of the current ship as visited
        mark all tiles surrounding those ship tiles as visited

if the ship map includes any pairs with non-zero (including negative) amount of ships
  the map is invalid
else
  the map is valid

答案 3 :(得分:1)

我不明白你需要什么: 但我认为战舰游戏中的船应具有基本结构:

Ship{
    //x, y: top, left of ship's position
    int: x;
    int: y;
    int: size;//[1,2,3,4]
    boolean: isHorizontal;//It means a ship is vertical or horizontal on the map.
}

如果您在数组中声明,则所有船只,例如:Ship[SHIP_NUMBER]: arrShip

有一些方法可以检查船只是否重叠

我可以告诉你其中一个:

  1. 如果您认为每艘船都是一个矩形,您可以检查是否存在两艘船相交。
  2. 如果您认为每艘船都在地图上设置,它将保留地图的位置,例如: 2-deck ship-horizontal shipmap[0][0] = 1map[0][1] = 1 。因此,您无法在单元格上设置船只。
  3. 检查船舶是否在地图外

    1. 您可以查看是否ship.x < 0 || ship.y < 0 || ship.x > 9 || ship.y > 9

答案 4 :(得分:0)

我认为用于表示董事会职位的更好的数据结构将大大简化项目。您定义Ship类型,其中包含三个字段:船的长度,船的方向,以及(取决于方向)其最高或最左边的方块。您将所需的所有船舶存储在一个列表中(它将有10个条目)。您可以通过向下移动列表来验证您的位置,将所有正方形标记为已占用,并将所有相邻的正方形标记为禁止。如果,当您放置船舶时,您必须将船舶放置在被占用或禁止的方格中,您知道您的位置无效。另一方面,如果您能够将所有船舶放置在没有冲突的情况下,您就知道通过施工可以使船板位置正确。

这样做的另一个好处是允许您一次放置一艘船,并立即报告无效配置,这意味着它几乎不需要更改用户界面来让玩家放置他们的船只。

答案 5 :(得分:0)

由于您最多有10艘船,而您的数据结构是byte数组,为什么不使用值0表示水域,使用值1到10表示船舶字段。

然后你可以迭代字段并检查周围的字段(你可以根据迭代方向进行优化,以便不检查相同的组合两次)。

如果遇到0值,请继续。

如果您获得值&gt; 0然后检查周围的字段是否包含0以外的值和字段的值(检测触摸船只)。

此外,如果周围的字段包含相同的值但触摸角落,则表示您发现了非法设置。 L形船舶也应违反非对角线规则。

最后要检查的是船是否可以包含洞。在这种情况下,只需存储您在每艘船上找到的一系列字段,并检查新检查的字段是否在该范围的旁边。这也会给你船只的数量,因为你可以在最后查询每艘船的航程长度。

考虑以下部分委员会:

    A B C D E F G H I J 
  _____________________
1 | 0 0 2 0 0 0 0 0 0 0
2 | 0 1 0 0 3 3 0 4 0 4
3 | 0 0 0 0 0 3 0 0 0 0

如果您现在检查B2的所有周围字段(值为1),您会发现值2,这是一个错误。

如果你检查E2,你会发现F3字段是对角线,尽管具有相同的值3 - >错误

如果检查H2,则得到H2-H2(长度为1)的范围,因为H2被空字段包围。如果您稍后检查J2,您会发现H和J之间的差异为2(1表示没问题),因此您发现了一个重复的船(或带有一个洞的船) - &gt;错误

基本上,这些规则可以表述如下(适用于非空单元格,有船舶的单元格):

  • 每个单元格的对角邻居必须为空(值为0)
  • 每个单元格的直接邻居必须具有值0或与单元格相同的值
  • 如果单元格的值已经在列表中,则它必须至少有一个具有相同值的直接邻居

这3条规则应该找到任何位置违规,如果你保持每艘船的范围在规则3中提到的列表中,你也可以验证船号限制。