为游戏领域创建算法

时间:2015-09-15 13:54:57

标签: algorithm logic

我目前正在搜索检查每个字段是否可访问的方法,如果有的话,如果有办法到达每个字段而不使用字段两次。 我目前的想法是尝试从各个方向开始,并使用旧场作为新墙。如果机器人卡住,他会重新启动并进入另一个方向。但我不确定这是否会起作用。 性能如何?这甚至有效吗?

世界/墙壁和机器人的位置是随机的。 机器人不能使用他之前使用的场地。

这是一个示例图像。 enter image description here

4 个答案:

答案 0 :(得分:2)

根据您的输入,您可以使用breadth first search algorithm搜索具有机器人起始位置的世界作为树的根。通常使用BFS,您可以记住在此特定情况下您已经看到的“节点”或磁贴。当算法终止时,您可以检查访问节点列表是否等于您想要访问的节点列表。

我认为你可以这样做,如果你知道的每个瓷砖是相邻的节点(例如参考)。

答案 1 :(得分:1)

所有单元格的可达性都很容易,只需一个布尔矩阵即可达到"对于每个细胞,从机器人起始位置开始传播连接信息,确保所有细胞最终被标记。这与世界大小呈线性关系,所以没有问题。

对于非冗余路径,基本上你需要一个启发式算法,因为正如在其他答案中已经提到的那样,哈密顿路径问题是NP。然后编写搜索空间的BFS或DFS遍历,寻找获胜路径。

我使用了以下启发式游戏,它可以很好地扩展到#34;棋盘马"国际象棋和#34;骑士"你必须覆盖国际象棋棋盘上的所有位置。如果你在拓扑结构中看它,它实际上和你的问题一样。

所以,启发式:

  • 在每个单元格中计算您可以摆脱它的方式。将此信息存储在矩阵中。所以一个中间的细胞得到4个,一个靠近墙壁的细胞只有3个等...
  • 在DFS的每个决策点,选择下一个单元格作为退出数量最少的单元格(这是启发式的核心)
  • 如果两个相邻的单元格位于1个出口退出,则回溯,问题在该分支上已经死亡
  • 当您输入相邻单元格的单元格减量出口时

冲洗并重复

这只是指导探索,如果你运气不好,探索仍然是高度复杂的。

直观地说,现在去出口较少的地区是件好事,因为以后再回到它们会更加困难。具有1个退出规则的2个单元格只是一个优化,但它可以修剪大的子树,这是好的。如果根据放置测试的位置检测到具有0个出口的未访问单元格,也可以回溯。

我有这种启发式方法,即使在比传统的8x8更大的棋盘上也能轻松吐出许多解决方案。

答案 2 :(得分:0)

此问题可以建模为图表中的连接问题,我们可以在迷宫上运行一次深度优先搜索,并找到从起始位置可到达的每个位置,如果任何位置不是墙/块而未访问在运行DFS之后,您无法从迷宫中任何路径的起始位置到达此位置。

基本上,您需要将游戏中的每个位置表示为图形中的节点,其中每个节点都有标记它的北,东,南和西墙。当您想要通过边缘访问相邻位置时,只有当相邻位置的墙壁没有朝向您想要的方向时,才能这样做。所以你需要做的就是修改DFS算法,这样你就只能在没有墙的情况下访问/调用相邻节点上的dfs。

void explore(Node position)
{
    position.visited = true

    while(position.hasUnvisitedDirection())
    {
        //random unvisited direction
        int direction   =   position.getDirection();

        if(direction == WEST && !west(node).visited && !position.westWall)
            explore(west(node));

        if(direction == EAST && !east(node).visited && !position.eastWall)
            explore(east(node));

        if(direction == SOUTH && !south(node).visited && !position.southWall)
            explore(south(node));

        if(direction == NORTH && !north(node).visited && !position.northWall)
            explore(north(node));

    }
}

在这里,我们对DFS进行了修改,因为我们在每个访问的位置选择一个随机的未访问位置。 east(Node)north(Node)等调用将分别返回传递节点的东,北位置 - 注意网格中的边缘情况(如果您将图形建模为非常直观)一个二维数组)。

接下来我们要检查图形是否只有一个强连接组件,如果我们的DFS中只有一个跳转就是这种情况,即在深度优先搜索林和每个位置都有一棵树将从我们的起始位置到达,这是你想要的。否则,运行DFS后未访问的节点将无法访问,如果算法返回false,您可以检查这些位置。所以以下内容应该实现这一点:

boolean isConnected(Graph g, Node startPosition)
{
    int jumps   =   0;
    for (Node node : g.nodes())
    {
        if(!node.visited)
        {
            jumps++;
            if(jumps > 1) return false;
            else explore(position);
        }
    }

    return true;
}

Depth first search可用于generate并解决迷宫,如上所示。

答案 3 :(得分:0)

我已经实施了类似here之类的东西来解决一个被称为“骑士之旅”的谜题"。我相信这个问题应该包含相同的逻辑,并进行一些小的修改。

我不会谈论遍历,而是试图让这一点更加普遍 - 从任何特定的角度来回答问题"什么是下一个最好的举措?"你想进一步思考并问:"最具限制因素是什么?"在这种情况下,基于您的下一个可用移动的最大限制因素是每个移动可以有多少移动。您下一个可用的每个动作都有自己的一组下一个可用动作。下一个可用移动次数最少的下一个可用移动是您最受限制的因素。

所以,例如,让我们说我可以移动x,y和z。 x和z都有2个下一个可用的移动,y有3个下一个可用的移动 - 你想要移动到x或z(它不应该是你决定的,所以你可以像我在我的代码中那样随机化它)。

为什么这有意义?再考虑一下 - 下一个可用的移动(在我们的例子中是x,y和z)是你必须在某个时刻得到的所有点! x,y和z的下一个可用移动也可以被认为是 BACK 到x,y或z的方式。由于回到x和z的方法较少,你现在也可以去其中一个。例如,如果x只有1个下一个可用移动(所有其他条件不变),则x将是您唯一有效的选项(作为优化,您可以立即转到x的下一个可用移动,因为您知道只有1)。

我提供的代码有很多你不需要关注的东西,但它应该是自包含的,所以你应该能够将它弹出到JSFiddle或html页面,它应该可以工作。与您的问题相关的功能是getPossibleMovesgetAvailableMovesgetBestNextMove(以及这些函数调用的任何函数)。 getPossibleMoves函数中的插值点内容与D3相关,而不是您需要担心的内容。该函数根据允许骑士如何移动的规则,从一个点(具有x和y属性)简单地计算所有可能的移动,然后简单地评估每个点以查看它们是否在边界内。修改此功能以适应您的机器人允许的移动并不是太难,您还需要更新检查该点是否在边界内的功能,也不允许存在有墙的点。< / p>

免责声明:我将这些代码放在一起以获得乐趣,因此它未经过优化,或者无论如何都是JavaScript中编码实践的优秀示例

另请注意,这只是解决此问题的一种方法。当然还有其他方法可以解决它,但这是我所知道的最简单的方法。