Почему не работает мой генератор градиентного шума? - PullRequest
0 голосов
/ 04 мая 2020

Я попытался создать программу, которая генерирует градиентный шум для генерации ландшафта. Он должен печатать массив чисел от 40 до 99, но на этом он останавливается:

    for(int k=16; k>1; k/=2)
        for(int y=Y; y<Y+16; y+=k+1)
            for(int x=X; x<X+16; x+=k+1)
            {
                tab[y+k/2][x]=rand()%(max(tab[y][x],tab[y+16][x])-min(tab[y][x],tab[y+16][x]))+min(tab[y][x],tab[y+16][x]);
                tab[y][x+k/2]=rand()%(max(tab[y][x],tab[y][x+16])-min(tab[y][x],tab[y][x+16]))+min(tab[y][x],tab[y][x+16]);
                tab[y+k/2][x+k/2]=rand()%(max(tab[y][x],tab[y+16][x+16])-min(tab[y][x],tab[y+16][x+16]))+min(tab[y][x],tab[y+16][x+16]);
            }

Когда я удаляю содержимое l oop, он не останавливается. Он хорошо компилируется, но возвращает -1 (0xFFFFFFFF)

Вот весь код:

#include<ctime>
#include<iostream>
using namespace std;
const short int Size=8;
short int tab[Size*16+1][Size*16+1];
void chunk(int X, int Y)
{
    srand(time(NULL));
    for(int k=16; k>1; k/=2)
        for(int y=Y; y<Y+16; y+=k+1)
            for(int x=X; x<X+16; x+=k+1)
            {
                tab[y+k/2][x]=rand()%(max(tab[y][x],tab[y+16][x])-min(tab[y][x],tab[y+16][x]))+min(tab[y][x],tab[y+16][x]);
                tab[y][x+k/2]=rand()%(max(tab[y][x],tab[y][x+16])-min(tab[y][x],tab[y][x+16]))+min(tab[y][x],tab[y][x+16]);
                tab[y+k/2][x+k/2]=rand()%(max(tab[y][x],tab[y+16][x+16])-min(tab[y][x],tab[y+16][x+16]))+min(tab[y][x],tab[y+16][x+16]);
            }
}
int main()
{
    srand(time(NULL));
    for(int i=0; i<Size; i+=16)
        for(int j=0; j<Size; j+=16)
            tab[16*i][16*j]=rand()%(100-40)+40;
    for(int x=0; x<Size*16+1; x+=16)
        for(int y=0; y<Size*16+1; y+=16)
            chunk(x,y);

    return 0;
}

Редактировать: он не работал из-за

rand()%(max(tab[y][x],tab[y+16][x])-min(tab[y][x],tab[y+16][x]))

элементов в массив может быть равен. Я также сделал несколько глупых ошибок при чтении массива, что привело к превышению его размера. Теперь он работает без ошибок, но показывает некоторые цифры ниже 40, что не должно происходить. Вот код после правок:

#include<ctime>
#include<iostream>
using namespace std;
const short int Size=1;
short int tab[Size*16+1][Size*16+1];
void chunk(int X, int Y)
{
    for(int k=16; k>1; k/=2)
        for(int y=Y; y<Y+16; y+=k)
            for(int x=X; x<X+16; x+=k)
            {
                if(Y!=Size*16)
                    if(tab[y][x]==tab[y+k][x])
                        tab[y+k/2][x]=tab[y][x];
                    else
                        tab[y+k/2][x]=rand()%(max(tab[y][x],tab[y+k][x])-min(tab[y][x],tab[y+k][x]))+min(tab[y][x],tab[y+k][x]);
                if(X!=Size*16)
                    if(tab[y][x]==tab[y][x+k])
                        tab[y+k/2][x]=tab[y][x];
                    else
                        tab[y][x+k/2]=rand()%(max(tab[y][x],tab[y][x+k])-min(tab[y][x],tab[y][x+k]))+min(tab[y][x],tab[y][x+k]);
                if(X!=Size*16||Y!=Size*16)
                if(tab[y][x]==tab[y+k][x+k])
                    tab[y+k/2][x]=tab[y][x];
                else
                    tab[y+k/2][x+k/2]=rand()%(max(tab[y][x],tab[y+k][x+k])-min(tab[y][x],tab[y+k][x+k]))+min(tab[y][x],tab[y+k][x+k]);
            }
}
int main()
{
    srand(time(NULL));
    for(int i=0; i<=Size*16; i+=16)
        for(int j=0; j<=Size*16; j+=16)
            tab[j][i]=rand()%60+40;
    for(int x=0; x<=Size*16; x+=16)
        for(int y=0; y<=Size*16; y+=16)
            chunk(x,y);

    for(int a=0; a<Size*16; a++){
        for(int b=0; b<Size*16; b++)
        {
            cout<<tab[b][a]<<' ';
            if(tab[b][a]<10)
                cout<<' ';
        }
        cout<<'\n';
    }
    return 0;
}

правка 2: Алгоритм записывает псевдослучайное значение между двумя выбранными значениями каждые 16 строк и столбцов в массив. Затем он перепрыгивает каждые 16 ячеек, чтобы поместить псевдослучайное значение между ячейками, которые уже заполнены следующим образом:

XOOOOOOO+OOOOOOF
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
+OOOOOOO+OOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOO
FOOOOOOOOOOOOOOF

X - проверяемая ячейка F - заполненные ячейки + - ячейки для заполнения 0 - пустые ячейки Алгоритм заполняет ячейки «+» псевдослучайным значением между значениями ячейки «X» и ячейки «F». Когда алгоритм перепрыгивает через все ячейки «F», он снова переходит на половину прыжка, как и раньше, и существующие ячейки «+» становятся ячейками «F». Это продолжается до тех пор, пока длина прыжка не станет равной 1, что означает, что массив заполнен.

Ответы [ 2 ]

0 голосов
/ 05 мая 2020

Самая большая проблема в расчете индексов, который вызывает доступ за пределы массива.

В следующем фрагменте я покажу возможную реализацию алгоритма, предполагая, что я понял вопрос.

#include <algorithm>
#include <array>
#include <iostream>
#include <iomanip>
#include <random>  // <- I won't use srand / rand

/*  Example of fill sequence (in 1D)
                                     start   step
1---------------1---------------1      0      16
1-------2-------1-------2-------1      8      16
1---3---2---3---1---3---2---3---1      4       8
1-4-3-4-2-4-3-4-1-4-3-4-2-4-3-4-1      2       4
154535452545354515453545254535451      1       2

1     <-2->    1     Dependencies 

^     \   /
2       2 
v     /   \

1              1

*/

template <class Gen>
int rand_between(int a, int b, Gen& gen)
{
    if (b < a)
        std::swap(a, b);
    std::uniform_int_distribution dist(a, b);
    return dist(gen);
}

template <class Gen>
int rand_between(int a, int b, int c, int d, Gen& gen)
{
    auto e = std::minmax({a, b, c, d});
    std::uniform_int_distribution dist(e.first, e.second);
    return dist(gen);
}

int main()
{
    std::random_device rd;
    std::seed_seq ss{rd(), rd(), rd()};
    std::mt19937 gen{ss};

    constexpr size_t first_step{ 16 };
    constexpr size_t repetitions{ 2 };
    constexpr size_t size{ first_step * repetitions + 1 };

    std::array<std::array<int, size>, size> m{};

    // First fill
    std::uniform_int_distribution dist(40, 99);
    for (size_t i{0}; i < size; i += first_step)
    {
        for (size_t j{0}; j < size; j += first_step)
        {
            m[i][j] = dist(gen);
        }
    }

    // Inner filling
    size_t half_step{ first_step / 2 };
    size_t step{ first_step };
    while (half_step > 0)
    {
        for (size_t i{0}; i < size; i += step)
        {
            for (size_t j{half_step}; j < size; j += step)
            {
                m[i][j] = rand_between(m[i][j - half_step], m[i][j + half_step], gen);
            }
            if (size <= i + half_step)
                break;
            for (size_t j{0}; j < size; j += step)
            {
                m[i + half_step][j] = rand_between(m[i][j], m[i + step][j], gen);
                if (j + step < size)
                {
                    m[i + half_step][j + half_step] = rand_between(
                        m[i][j], m[i + step][j], m[i][j + step], m[i + step][j + step], gen
                    );
                }
            }
        }
        step = half_step;
        half_step /= 2;
    }

    for (size_t i{0}; i < size; ++i)
    {
        for (size_t j{0}; j < size; ++j)
        {
            std::cout << std::setw(3) << m[i][j];
        }
        std::cout << '\n';
    }
}

Тестируемый здесь ;

0 голосов
/ 04 мая 2020

Похоже, вы выдыхаете свои массивы. в какой-то момент вы вызываете chunk со значением X, равным Size * 16

, тогда в подпрограмме у вас есть маленький x (кстати, дифференцирующая переменная только по заглавным буквам делает код трудным для чтения), доходящий до X + 16, так что простое нажатие на табуляцию [x, ...] уничтожит ваш массив, и у вас будет табуляция [x + 16, ...]

...