不确定的行为通过确定主义程序

Undefined behavior with determinist procedure

本文关键字:程序 不确定      更新时间:2023-10-16

我目前正在尝试在"生命游戏"想法之后实现"洞穴生成"作为2D数组。这个想法如下:

i的2D向量为0s和1s(分别代表空气和块),该速率用uniform_real_distribution随机生成的density(此处为0.45,因此数组的45%为1)。

之后,我们在数组上迭代 x 次。迭代看起来如下:

  1. 首先,我们将数组复制在新数组中。
  2. 第二,我们在 old 数组上迭代如下:我们查看我们所处街区附近的块数量,并且根据两件事,我们要这样做:如果当前的瓷砖是空气的,并且在其附近有4个以上的街区(-1,-1)到(1,1),则将其更改为新数组中的一个街区如果当前瓷砖是一个块,其附近的块少于3个块,请将其更改为新数组中的空气
  3. 复制旧数组中的新数组

问题是,即使我用确定性种子(有时1次)播种我的统一定律时,地图也将在两到三个迭代后完全填充块。我从字面上看了0个想法,为什么在查看我的代码很多小时之后,这就是为什么我在这里。有代码:

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(),因为所有行和列都是相等的大小)。当我等于-1时,您有一个范围的向量访问和未定义的行为。