c++ 为什么我在数组中对图块进行评分的功能不起作用?

8wigbo56  于 2023-03-25  发布在  其他
关注(0)|答案(3)|浏览(106)

我正在为我的大学编程项目写一个小roguelike游戏。我想尝试实现一个简单的寻路机制,这将涉及到用从0开始向上的数字填充平铺Map,数字是到玩家的距离。这将允许怪物找到到玩家的最短路径。这是我想出的算法:

void monster_vision(int player_x, int player_y, int score = 0)
{
    if (map[player_x][player_y] == '.')
    {
        map[player_x][player_y] = score;
    }
    else
        return;

    monster_vision(player_x - 1, player_y, score + 1);
    monster_vision(player_x + 1, player_y, score + 1);
    monster_vision(player_x, player_y - 1, score + 1);
    monster_vision(player_x, player_y + 1, score + 1);
}

正如我所说,这只是要素的单文件草稿,Map的类型为std::array<std::array<char, map_size>, map_size,最初在边缘填充#,内部填充点
我希望Map看起来像这样:例如,如果map的大小设置为5,函数调用为:monster_vision(2,2)

#####
#212#
#101#
#212#
#####

我得到的结果是

#####
#218#
#307#
#456#
#####

根据我的理解,一些递归调用一定会以某种方式重叠,但我认为我放置的保护应该足以防止写入已经得分的单元格。

8fq7wneg

8fq7wneg1#

下面是一个使用std::deque实现bfs的实现:

void computeDistances(Pos pos) {
    reset();
    std::deque<std::tuple<Pos, C>> q;
    q.emplace_back(pos,0);
    while (!q.empty()) {
      auto const [p, score] = q.front();
      q.pop_front();
      if (!(*this)[p]) {
        (*this)[p] = score;
        if (p[0] > 0) q.emplace_back(Pos{static_cast<C>(p[0]-1),p[1]}, score+1);
        if (p[1] > 0) q.emplace_back(Pos{p[0],static_cast<C>(p[1]-1)}, score+1);
        if (p[0] < N-1) q.emplace_back(Pos{static_cast<C>(p[0]+1),p[1]}, score+1);
        if (p[1] < N-1) q.emplace_back(Pos{p[0],static_cast<C>(p[1]+1)}, score+1);
      }
    }
    (*this)[pos] = 0;
  }

它依赖于这些助手:

using C = std::uint16_t;
  using Pos = std::array<C,2>;
  std::array<std::array<C, N>, N> map;

  C& operator[](Pos pos) {
    return map[pos[0]][pos[1]];
  }

  void reset() {
    std::fill(begin(map[0]), end(map[0]), 0);
    std::fill(begin(map), end(map), map[0]);
  }

请注意,您不需要'#'字符形式的边界守卫,因为您知道棋盘的大小。相反,零分用于标记未访问的单元格。不幸的是,这引入了大量的分支条件,可以进一步改进。
Here is a complete demo .

wljmcqd8

wljmcqd82#

问题是你的算法是递归的。想象一下它实际上是做什么的,它在你的Map中设置值0(如果.),那么它调用monster_vision作为下一个坐标,但值为1。现在魔术发生了。你仍然在第二次调用monster_vision,但是现在它再次调用monster_vision(深度2)用于下一个位置,但是值2,等等。
因此,对monster_vision的四个调用在代码中彼此在下面,它们不是按顺序调用的。这个顺序是迭代的,只有当你在所有四个“方向”上遇到第一个非.时才会被打破......这正是你所观察到的。
迭代算法听起来不错,但不会起作用。
根据你的游戏逻辑,你必须决定你想如何计算距离/得分,eidogg.怪物可以对角线移动吗?
我建议一个简单的纯x/y运动和:

// map dimension is nx in first dimension and ny in second dimension here
void monster_vision(int player_x, int player_y)
{
    for (int i=0; i<nx; ++i) 
      for (int j=0; j<ny; ++j) {
         map[player_x][player_y] = std::abs(player_x-i) + std::abs(player_y-j);
}

然而,正如在评论中所指出的,在这个特定的情况下和许多其他情况下,预先计算距离可能没有好处。

but5z9lq

but5z9lq3#

变化

if (map[player_x][player_y] == '.')

if (map[player_x][player_y] == '.' || map[player_x][player_y]-char('0') > score)

以便在更快访问的情况下而不仅仅是在第一次访问的情况下也设置新的分数。

相关问题