Форум программистов, компьютерный форум, киберфорум
Алгоритмы
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.67/21: Рейтинг темы: голосов - 21, средняя оценка - 4.67
0 / 0 / 0
Регистрация: 13.12.2020
Сообщений: 9

Процедурная генерация леса

05.01.2021, 23:08. Показов 4848. Ответов 24
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем привет.
Я любитель программист.

Дано: 2д карта, сетка квадратная.
Карта представлена графом.
Карта пустая, то есть из каждой ячейки можно попасть в соседнюю

Есть задача расставить на ней лес.
Моя проблема в том, что я не понимаю какой теоретический базис нужно освоить, чтобы решить эту задачу. А именно ту задачу, как нарисовать этот лес нужной формы.

У меня есть некоторые требования к лесу, который я сформулировал:
1. Максимальное количество клеток леса в одной "кучке" - не более 100
2. Максимальная протяжённость - не более 10 клеток что в высоту, что в ширину
3. Нельзя расставить лес так, чтобы на карте получились области, куда нельзя попасть.
4. На границах леса должны присутствовать такие формы этой границы, которые бы позволяли положить туда одноклеточный объект, и лес закрывал бы его впритык хотябы 5 клетками.


Пока пришло в голову только думать самому, лезть куда-то в геометрию. Но мне бы получить вектор куда идти изучать. Гугление навело только на общие алгоритмы, основанные на шумах, которые к моему случаю не применимы, так как мне важно соблюдать эти обязательные требования. На англоязычных ресурсах наткнулся как раз на мысль, что надо сформировать требования и пожелания, и придумать алгоритм самостоятельно, что я и пытаюсь сделать.

Заранее спасибо.
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
05.01.2021, 23:08
Ответы с готовыми решениями:

Процедурная генерация
Делаю процедурную генерацию лабиринта на основе псевдослучайных чисел. Не понимаю почему на определённой итерации перестаёт "прорывать...

Процедурная генерация
Доброго времени суток, форумчане. Как сделать переходы между комнатами? Читал о применении алгоритмов поиска пути, в частности А*....

Процедурная генерация комнатного лабиринта
Скрипт создает на сцене некоторое количество комнат со случайным положением и случайным размером.Некоторые комнаты граничат между собой.Как...

24
1472 / 827 / 140
Регистрация: 12.10.2013
Сообщений: 5,456
07.01.2021, 19:43
Студворк — интернет-сервис помощи студентам
Еще влияет размер массива. 300 на 300 пикселей все картинки.
Массив 10 на 10 убивает весь…хз почему. Может алгоритмический баг где-то.
Массив 50 на 50.
Название: ScreenShot01388.jpg
Просмотров: 87

Размер: 18.2 Кб
Массив 100.
Название: ScreenShot01389.jpg
Просмотров: 89

Размер: 19.2 Кб
Массив 200.
Название: ScreenShot01390.jpg
Просмотров: 89

Размер: 21.3 Кб
Массив 300.
Название: ScreenShot01391.jpg
Просмотров: 89

Размер: 13.6 Кб
Какойто баг, как вытянуты капли. Может из-за неправильного шума..хз. Детализация растет от разрешения, ну и больше точек с зарядом сложнее форма. Можно хоть буквы писать. Или придумайте свой клеточный автомат, хз как там правила придумывают.
0
1472 / 827 / 140
Регистрация: 12.10.2013
Сообщений: 5,456
07.01.2021, 23:53
Лучший ответ Сообщение было отмечено Vilgelmstein как решение

Решение

Вот новый код, вроде более правильный, добавил остановку если картинка не меняется. Код вообще С++ но там нет никаких классов и прибахов ООП кроме нескольких функций. Может быть по идее переведен на любой язык хоть асм…
Сделано на glut в Visual Studio 2008 express.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
#include <gl/glut.h>
#include <iostream> 
#include <iomanip>
#include <math.h>
#include <stdlib.h>
using namespace std;
 
const int imSiz=300; // размер картинки
const int arSiz=100; // размер квадратного массива
int rnd=12; //число сид генератора
 
 
float pts[arSiz+2][arSiz+2][2]={0}; //хранит 2д вектора рисуемых точек
bool pix[arSiz+2][arSiz+2]={0}; //хранит состояния пикселей есть/нет
bool buf[arSiz+2][arSiz+2]={0}; //буферный массив хранит результат свертки
 
 
//функция возвращает значение заряда от точки
float charge(float x,float x1,float y,float y1,float a,float b)
{
return a*exp(-b*((x-x1)*(x-x1)+(y-y1)*(y-y1)));
}
 
 
 
bool render_complete=0; //флаг завершения рендера
int iter=0; //подсчет итераций
bool BufNeRavenPix=1; //флаг остановки итераций если картнка не меняеться
 
//========================================================
//рисует квадраты
void DrawPixelArray()
{
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_POINTS);
    for(int x = 1; x < arSiz+1; x++)
    {
        for (int y =1; y < arSiz+1; y++)
        {
            float color;
            if(pix[x][y])
            {
                color=1.0f;
            }
            else
            {
                color=0.0f;
            }
            glColor3f(color, color, color);
            glVertex2f(pts[x][y][0],pts[x][y][1]);
        }
    }
    glEnd();
    render_complete=1;
}
//рисует квадраты
//========================================================
 
 
 
 
 
 
//========================================================
//клеточный автомат, ядро свертки 3 на 3
void Conv3x3() 
{
    for(int x = 1; x < arSiz+1; x++)
    {
        for (int y = 1; y < arSiz+1; y++)
        {
            int sum=
            pix[x-1][y+1]+
            pix[x][y+1]+
            pix[x+1][y+1]+
            
            pix[x-1][y]+
            pix[x+1][y]+
 
            pix[x-1][y-1]+
            pix[x][y-1]+
            pix[x+1][y-1];
 
            if(sum>4)
            {
                buf[x][y]=1;
            }
            else if(sum<4)
            {
                buf[x][y]=0;
            }
            else if(sum==4)
            {
                buf[x][y]=pix[x][y];
            }
        }
    }
    //остановка итераций если состояния пикселей в buf равны  состояниям в pix
    //копируем buf в pix
    BufNeRavenPix=1;
    for(int x = 1; x < arSiz+1; x++)
    {
        for (int y = 1; y < arSiz+1; y++)
        {
            if (pix[x][y]!=buf[x][y] && BufNeRavenPix)
            {
                //cout <<"BufNeRavenPix--------"<<endl;
                BufNeRavenPix=0;
            }
            pix[x][y]=buf[x][y];
        }
    }
 
    if(!BufNeRavenPix)
    {
        DrawPixelArray();
    }
    else
    {
        cout <<"Image not changed, STOP"<<endl;
    }
}
//клеточный автомат, ядро свертки 3 на 3
//========================================================
 
 
//========================================================
// копируем строки и столбцы для зацикливания XY области для свертки 3 на 3.
void CopyRowColumn() 
{
    //копируем строки
    for(int y = 1; y < arSiz+1; y++)
    {
        pix[arSiz+1][y]=pix[1][y];
        pix[0][y]=pix[arSiz][y];
    }
    //копируем строки
 
 
    //копируем столбцы
    for(int x = 0; x < arSiz+2; x++)
    {
        pix[x][arSiz+1]=pix[x][1];
        pix[x][0]=pix[x][arSiz];
    }
    //копируем столбцы
    if(iter==0)
    {
        DrawPixelArray(); //нулевая итерация пропуск свертки
    }
    else
    {
        Conv3x3();
    }
 
}
// копируем строки и столбцы для зацикливания XY области для свертки 3 на 3.
//========================================================
 
 
//========================================================
//расчет заряда в центре каждого пикселя
void  StartGenArr()
{
srand(rnd); //установка числа сид генератора
    for(int x = 1; x < arSiz+1; x++)
    {
        for (int y = 1; y < arSiz+1; y++)
        {
        //сумма заряодов всех точек
        float sum=
        charge(pts[x][y][0],-0.22f,pts[x][y][1],-0.31f,1.0f,10.0f)+
        charge(pts[x][y][0], 0.28f,pts[x][y][1],-0.57f,1.0f,24.0f)+ 
        charge(pts[x][y][0], 0.51f,pts[x][y][1],-0.14f,1.0f,27.0f)+
        charge(pts[x][y][0],-0.23f,pts[x][y][1], 0.64f,1.0f,18.0f)+
        charge(pts[x][y][0],-0.61f,pts[x][y][1],-0.6f, 1.0f,22.0f)+
        charge(pts[x][y][0], 0.48f,pts[x][y][1], 0.63f,1.0f,27.0f)+
        charge(pts[x][y][0], 0.12f,pts[x][y][1], 0.17f,1.0f,20.0f);
        //-------
            if(sum>1.0f)
            {
                pix[x][y]=1;
            }
            else if((double)rand()/RAND_MAX>sum)
            {
                pix[x][y]=0;
            }
            else
            {
                pix[x][y]=1;
            }   
        //-----------
        }
    }
CopyRowColumn();
//DrawPixelArray();
}
//========================================================
 
 
 
//========================================================
//находит 2д вектора рисуемых квадратов
void FindPtsCoord() 
{
float dx=2.0f/(arSiz-1);
float dy=2.0f/(arSiz-1);
float x0=-1.0f;
float y0=-1.0f;
    for(int x = 1; x < arSiz+1; x++)
    {
 
        for (int y = 1; y < arSiz+1; y++)
        {
            pts[x][y][0]=x0; 
            pts[x][y][1]=y0; 
            if(y0<1.0)
            {
                y0=y0+dy;
            }
            else
            {
                y0=-1.0f;
            }
        }
 
        if(x0<1.0)
        {
            x0=x0+dx;
        }
        else
        {
            x0=-1.0f;
        }
    }
StartGenArr();
}
//находит 2д вектора рисуемых квадратов
//========================================================
 
 
 
 
//=========================================================
//таймер  проверяет готов ли рендер, если да то обновляет экран и запуск таймера
void TimerFunction(int value)
{
    if(render_complete) 
    {
        glutSwapBuffers();
        render_complete=0;  
        cout << "iter="<<iter<<endl;
        iter++;
        glutTimerFunc(16, TimerFunction, 1);
        CopyRowColumn();
    }
}
//таймер  проверяет готов ли рендер, если да то обновляет экран и запуск таймера
//=========================================================
 
 
void SetupGL() 
{
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f);
    glScalef(0.99f,0.99f,1.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glClearColor(0, 0, 0, 0);
    glPointSize(float(imSiz)/(arSiz+arSiz*1));
}
 
int main(int argc, char** argv) 
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(imSiz, imSiz); 
    glutInitWindowPosition(500, 200);
    glutCreateWindow("Forest gen");
    SetupGL();
    FindPtsCoord();
    glutTimerFunc(30, TimerFunction, 1);
    glutMainLoop();
    return 0;
}
Точки тут
C++
1
2
        charge(pts[x][y][0],-0.22f,pts[x][y][1],-0.31f,1.0f,10.0f)+
        charge(pts[x][y][0], 0.28f,pts[x][y][1],-0.57f,1.0f,24.0f)+
1
0 / 0 / 0
Регистрация: 13.12.2020
Сообщений: 9
08.01.2021, 00:49  [ТС]
Спасибо за труд. Пойду разбираться и переписывать.
0
0 / 0 / 0
Регистрация: 13.12.2020
Сообщений: 9
13.01.2021, 00:24  [ТС]
Вроде как получается.
Но есть одна вещь которую я не могу понять в точках, и это непонимание мешает мне доделать то что я хочу.

Вот пример

charge(pts[x][y][0],-0.22f,pts[x][y][1],-0.31f,1.0f,10.0f)

-0.22 и -0.31 это что за координаты? и почему они дробные
и почему они все во всех точках меньше единицы.
я методом тыка, думая что это точка от которой мы считаем центр нашей плюшки, ставил 2;2 находясь в квадрате 0..5 по x и y, но оно так как я хотел не работало.
поясните пожалуйста, если не сложно.
0
1472 / 827 / 140
Регистрация: 12.10.2013
Сообщений: 5,456
13.01.2021, 10:49
Цитата Сообщение от Vilgelmstein Посмотреть сообщение
-0.22 и -0.31 это что за координаты? и почему они дробные
Это координаты отбалды заданной точки от которой заряд. Там их штук 7.
Цитата Сообщение от Vilgelmstein Посмотреть сообщение
почему они все во всех точках меньше единицы.
Так в проге просто координаты заданы от -1 до 1.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
13.01.2021, 10:49

Что такое процедурная генерация?)
Приветствую уважаемые форумчане! Задумался я под вечер грядущий о написании интересной программки.. Допустим, имеется объект назовем...

Процедурная анимация
у объекта Generic есть анимация, как ее менять через скрипт? например как выбрать нужную кость и сместить по Y относительно анимации?

Процедурная вселенная
Видел где то толи тему, толи раздел &quot;процедурная вселенная&quot;. Там разбирались алгоритмы автоматической случайной генерации карт игровых...

Процедурная декомпозиция
Выполнить процедуру декомпозиции программного комплекса, выполняющего действия с одномерным массивом: 1.Ввод; 2.Инвертирование; ...

Процедурная вселенная
Нужны примеры исходников функций: 1. Динамически рассчитывающей среднюю высоту над уровнем моря участка поверхности абстракной планеты....


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
25
Ответ Создать тему
Новые блоги и статьи
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
[EasyBuilder Pro] Памятка по разработке для панелей Weintek
ФедосеевПавел 26.08.2026
Памятка по разработке для панелей Weintek ВВЕДЕНИЕ Ранее, при реализации проектов основное внимание уделял разработке управляющей программы для контроллера, а панели оператора доставалось время. . .
Модель по догадкам
anaschu 25.08.2026
Прошло две недели. Я уже рассказывал, как разговаривал с сотрудниками у сортировки и как понял, что главная ветка — не про приёмку, а про отбор. Но тогда я думал, что понял механику. На этой неделе я. . .
Запись в регистр сведений независимо от заполненности табличной части
Maks 25.08.2026
Реализация из решения ниже выполнена на нетиповом документе с несколькими табличными частями, разработанного в КА2. Задача: Обеспечить запись документа в регистр сведений независимо от. . .
Ноутбук Альфария
kumehtar 24.08.2026
Встретился тут в сети ноутбук Альфария, примарха Альфа-Легиона. Хотя возможно, это ноутбук Омегона, разумеется. Ну как вам?
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru