c++ - 具有确定性程序的未定义行为

标签 c++ arrays vector 2d procedural-generation

我目前正在尝试按照“生命游戏”的想法将“洞穴生成”实现为二维数组。思路如下:

我有一个 0 和 1 的二维 vector (分别代表空气和 block ),它是用 uniform_real_distributiondensity 随机生成的(这里是 0.45,所以 45%数组将为 1)。

在此之后,我们在数组上迭代 x 次。迭代如下所示:

  1. 首先,我们将数组复制到一个新数组上。
  2. 其次,我们按如下方式在 old 数组上进行迭代:我们查看我们所在街区附近的街区数量,并根据两件事执行此操作: 如果当前方 block 是空气并且在它的邻域 (-1,-1) 到 (1,1) 不包括他自己有超过 4 个 block ,将它更改为 NEW ARRAY 中的 block 如果当前图 block 是一个 block 并且其邻域中的 block 少于 3 个,则将其更改为 NEW ARRAY 中的空气
  3. 将新数组复制到旧数组中

问题是,即使我用确定性种子为统一法则播种,有时(1 次超过 3 次),经过两到三次迭代后, map 也会完全被 block 填满。在看了我的代码好几个小时之后,我几乎没有什么想法,这就是我来这里的原因。有代码:

cavefactory.h

#ifndef CAVEFACTORY_H_
#define CAVEFACTORY_H_

#include <vector>

namespace cavegenerator {

// define cave_t as a 2d vector of integers
using cave_t = std::vector<std::vector<int>>;

// constants
namespace DEFAULT {

constexpr unsigned short int WIDTH = 64;
constexpr unsigned short int HEIGHT = 64;
constexpr float DENSITY = 0.45;
constexpr unsigned short int BIRTH_LIMIT = 4;
constexpr unsigned short int DEATH_LIMIT = 3;

} // namespace DEFAULT


class CaveFactory {
    public:
        CaveFactory(unsigned short int width = DEFAULT::WIDTH,
                                unsigned short int height = DEFAULT::HEIGHT,
                                float density = DEFAULT::DENSITY);

        // makes a cave with the desired number of iterations and parameters
    static cave_t MakeCave(unsigned short int width = DEFAULT::WIDTH,
                                                    unsigned short int height = DEFAULT::HEIGHT,
                                                    float density = DEFAULT::DENSITY,
                                                    int iterations = 3,
                                                    unsigned short int bl = DEFAULT::BIRTH_LIMIT,
                                                    unsigned short int dl = DEFAULT::DEATH_LIMIT);

        // implemented in case of generalization of cave(more than two blocks)
        bool isSolid(int i, int j);

        cave_t getCave();

        void Print();
        void Iterate( unsigned short int bl = DEFAULT::BIRTH_LIMIT,
                                    unsigned short int dl = DEFAULT::DEATH_LIMIT );

    private:
    cave_t cave_;

    int NumberOfNeighbours(int i, int j);

    void Initialize(float density = DEFAULT::DENSITY);


};

} // namespace cavegenerator

#endif // CAVEFACTORY_H_

cavefactory.cc

#include "cavefactory.h"
#include <random>
#include <iostream>
#include <ctime>
#include <algorithm>


namespace cavegenerator {


CaveFactory::CaveFactory(unsigned short int width, unsigned short int height, float density) {
    cave_.resize(width);
  for (auto &i : cave_) {
    i.resize(height);
  }
  Initialize(density);
}

bool CaveFactory::isSolid(int i, int j) {
    return (cave_[i][j] == 1);
}

int CaveFactory::NumberOfNeighbours(int x, int y) {
    int num = 0;

  for (int i = -1; i < 2; i++) {
        for (int j = -1; j < 2; j++) {
      if ( i == 0 && j == 0 ) continue; // we don't want to count ourselve

      // if out of bounds, add a solid neighbour
      if ( x + i >= (int)cave_.size() || x + i < 0 || y + j >= (int)cave_[i].size() || y + j < 0) {
                ++num;
            } else if (isSolid(x+i, y+j)) {
                ++num;
            }
        }
    }

    return num;
}

cave_t CaveFactory::getCave() {
    return cave_;
}

void CaveFactory::Print() {
    for (auto &i : cave_) {
        for (auto &j : i) {
            std::cout << ((j==1) ? "x" : " ");
        }
        std::cout << "\n";
  }
  return;
}

cave_t CaveFactory::MakeCave(unsigned short int width,
                                unsigned short int height,
                                float density,
                                int iterations,
                                unsigned short int bl,
                                unsigned short int dl)
{

    CaveFactory cave(width, height, density);
  for (int i = 0; i < iterations; i++) {
        cave.Iterate(bl, dl);
  }

  return cave.getCave();
}


// Initlialize the cave with the specified density
void CaveFactory::Initialize(float density) {
  std::mt19937 rd(4);
  std::uniform_real_distribution<float> roll(0, 1);

  for (auto &i : cave_) {
        for (auto &j : i) {
            if (roll(rd) < density) {
                j = 1;
            } else {
                j = 0;
            }
        }
  }
}

// for each cell in the original cave, if the cell is solid:
// if the number of solid neighbours is under the death limit, we kill the block
// if the cell is air, if the number of solid blocks is above the birth limit we place a block
void CaveFactory::Iterate(unsigned short int bl, unsigned short int dl) {
  cave_t new_cave = cave_;

  for (int i = 0; i < (int)cave_.size(); i++) {
        for (int j = 0; j < (int)cave_[0].size(); j++) {

      int number_of_neighbours = NumberOfNeighbours(i, j);
      if (isSolid(i, j) && number_of_neighbours < dl) {
                new_cave[i][j] = 0;
      } else if (!isSolid(i,j) && number_of_neighbours > bl) {
                new_cave[i][j] = 1;
      }
      }
  }

  std::copy(new_cave.begin(), new_cave.end(), cave_.begin());
}



} // namespace cavegenerator

main.cc

#include <iostream>
#include <vector>
#include <random>
#include <ctime>
#include <windows.h>

#include "cavefactory.h"



int main() {

  cavegenerator::CaveFactory caveEE;
  caveEE.Print();


for(int i = 0; i < 15; i++) {
        caveEE.Iterate();
        Sleep(600);
        system("cls");
        caveEE.Print();
  }
  return 0;
}

我知道 windows.h 是个坏习惯,我只是用它来调试。

我希望有人能让我明白,也许这只是我不知道的正常行为?

非常感谢。

最佳答案

NumberOfNeighbours中的(int)cave_[i].size()不正确,应该是(int)cave_[x+i].size ()(或 (int)cave_[0].size() 因为所有行和列的大小都相等)。当 i 等于 -1 时,您有越界 vector 访问和未定义的行为。

关于c++ - 具有确定性程序的未定义行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54953215/

相关文章:

c++ - vector 内存分配策略

c++ - 可以在 C++ 中实现 XOR 链表而不会导致未定义的行为吗?

c++ - 有人可以解释以下语法及其功能吗?

c++ - 删除队列对象数组

arrays - Groovy 和 json : How to get the length of an array from json?

vector - 样式点向量作为 Openlayers 中的标记?

c++ - 哎呀沮丧

c++ - 如何重载 '<' 运算符以比较同一类的对象?

perl - 这是构建利用数组的 Perl 哈希的正确方法吗?

c++ - 递归期间数组的行为