【问题标题】:how to mathematically have array border without actually increasing the array size?如何在不实际增加数组大小的情况下在数学上具有数组边框?
【发布时间】:2021-03-04 21:26:48
【问题描述】:

所以我有一个由 64 个方格组成的一维数组表示的游戏板,我想知道一个棋子何时试图逃出边界。

例如: 假设国际象棋中的国王在 X 上:

0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 X 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

用方向向量很容易计算出被攻击的方格:

-9, -8, -7,
-1,      1,
 7,  8,  9

0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 1 1 1 0 0
0 0 0 1 X 1 0 0
0 0 0 1 1 1 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

如果他在棋盘的上边缘或下边缘: 我只是添加一个 if 来检查 square + directionvector[i] > 63 或 正方形 + 方向向量[i]

所以:

0 0 0 1 X 1 0 0
0 0 0 1 1 1 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

当它位于侧边缘时,问题就来了:

0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 1
1 0 0 0 0 0 1 X
1 0 0 0 0 0 1 1
1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

如您所见,它将“跳”到错误的地方。

你知道有什么方法可以检查吗? 谢谢

【问题讨论】:

    标签: arrays vector chess


    【解决方案1】:

    在您的程序开始时,您可以预先计算每个棋子和每个方格的合法移动并将它们存储在某个地方。

    假设您的方格从 0 到 63 编号,那么KING_MOVES[i] 将存储国王在方格i 上的合法移动(其中i 的范围从 0 到 63)。例如,KING_MOVES[0] = { 1, 8, 9 }KING_MOVES[31] = { 22, 23, 30, 38, 39 }。同样,对于角落里的骑士,KNIGHT_MOVES[0] = { 10, 17 }

      0  1  2  3  4  5  6  7
      8  9 10 11 12 13 14 15
     16 17 18 19 20 21 22 23
     24 25 26 27 28 29 30 31
     32 33 34 35 36 37 38 39
     40 41 42 43 44 45 46 47
     48 49 50 51 52 53 54 55
     56 57 58 59 60 61 62 63
    

    每个方格的合法步数是不同的(国王在中心有 8 步,但在角落只有 3 步)。您可以单独存储合法移动的数量(例如NUM_KING_MOVES[31] = 5),也可以使用 -1 或 64 等特殊值终止每个列表。

    要预先计算这些列表,您可以将每个一维数字转换为一对(行、列)坐标,并通过边界检查简单地生成移动。对于 31 格上的国王,您将 31 转换为(第 3 行,第 7 列)。当向右移动时,你最终在(第 3 行,第 8 列),这是非法的,所以你放弃了这一步。当移动到左上角时,您最终会到达(第 2 行,第 6 列),这是合法的,因此您将其转换回一维表示:2 * 8 + 6 = 22。将此移动附加到 @ 987654330@等等。

    这为您提供了两全其美的优势:更快、更短的移动生成代码,不会因填充而在每个板上浪费内存。缺点是需要几 KB 的额外内存。

    如果您要走这条路,您还可以查看bitboards 以获得更快的移动生成。

    【讨论】:

    • 我真的不明白你的意思,你是如何以这种方式产生动作的? KING_MOVES = { 1, 8, 9 } 在移动方面是什么意思
    • 我已经扩展了答案以展示预计算的工作原理。我希望现在更好!
    • 加泰罗尼亚语 francau 那是 fucin 天才!!!非常感谢!
    【解决方案2】:

    您可以从单元格索引中获取行号为i / 8(下限),并使用它来检查例如向右或向左一步传递到另一行。

    例如在这里,在一个四列板上,从位置 7 向“右侧”走,我们到位置 8。它们的行号是 7 / 4 = 18 / 4 = 2,所以我们换到另一行。

    ....
    ...7
    8...
    ....
    

    但对角线移动更难做到这一点,因为你希望它们改变行。最后,这几乎只是将板子变成了一个二维数组,而步长偏移量变成了二维值,您可以在其中以明显的方式检查溢出。

    IMO,原则上你所要求的对于一维板是不可能的。将棋盘定义为一维向量(类似地,将偏移定义为一维偏移),则棋盘内没有边缘,也没有什么可以逃脱的。而不是这个:

    .ab.
    ....
    ...c
    d...
    

    你真的只有这个:

    .ab........cd...
    

    很明显cdab 一样相邻。

    【讨论】:

    • 是的,你可能是对的,但我想到了一种可行的方法 - 我将这块放在一个带边框的新数组中,并在那里进行所有计算,完成后我只是将它转移回普通板 :) 无论如何感谢您的回答,我一定会尝试的!
    猜你喜欢
    • 2015-12-30
    • 1970-01-01
    • 1970-01-01
    • 2011-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-13
    • 1970-01-01
    相关资源
    最近更新 更多