Bug Summary

File:src/mapgen/gram_simple.c
Location:line 280, column 17
Description:Division by zero

Annotated Source Code

1#include "system.h"
2
3#include "defs.h"
4#include "struct.h"
5#include "../src/global.h"
6#include "proto.h"
7
8#include "mapgen/mapgen.h"
9
10#define MIN_ROOM_WIDE6 6
11
12/* Minimum surface of a room */
13static const int Smin = 100;
14
15/* Dimensions of the dungeon */
16static int dim_x_init;
17static int dim_y_init;
18
19/* Worst y/x and x/y ratios accepted. */
20#define WORST_ROOM_RATIO2.0 2.0
21
22enum cut_axis {
23 CUT_HORIZONTALLY = 0,
24 CUT_VERTICALLY = 1,
25 DO_NOT_CUT = 2
26};
27
28/** Check if the two proposed room sizes satisfy the minimal surface criteria or not.
29 */
30static int check_surf(int w_creator, int h_creator, int w_newroom, int h_newroom)
31{
32 if ((w_creator * h_creator > Smin) && (h_newroom * w_newroom > Smin))
33 return 1;
34
35 return 0;
36}
37
38/**
39 * Try to cut a room of dimensions dim_x and dim_y, horizontally or vertically
40 * depending on the value of vert, with a ratio r.
41 *
42 * This function picks a ratio for the cut and sets r accordingly.
43 */
44static int trycut(int dim_x, int dim_y, int *r, enum cut_axis vert)
45{
46 /*
47 * Example computation for a vertical cut :
48 *
49 * x1 + x2 = dim_x
50 * x1 = r * x
51 * x2 = (1-r) * x
52 * log(x1/y) <= b, b constant
53 * log(x1/y) >= -b
54 *
55 * => y/(a * x) <= r <= a * y/x
56 * and 1-(ya)/x <= r <= 1 - y/(ax)
57 *
58 * with a = exp(b)
59 */
60 float rmin = 1, rmin2 = 1, rmax = 0, rmax2 = 0;
61
62 switch (vert) {
63 case CUT_HORIZONTALLY:
64 rmax = WORST_ROOM_RATIO2.0 * (float)dim_x / dim_y;
65 rmin2 = (1.0 / WORST_ROOM_RATIO2.0) * dim_x / dim_y;
66 break;
67 case CUT_VERTICALLY:
68 rmax = WORST_ROOM_RATIO2.0 * (float)dim_y / dim_x;
69 rmin2 = (1.0 / WORST_ROOM_RATIO2.0) * dim_y / dim_x;
70 break;
71 default:
72 ;
73 }
74
75 rmin = 1 - rmax;
76 rmax2 = 1 - rmin2;
77
78 rmax = rmax > rmax2 ? rmax2 : rmax;
79 rmin = rmin < rmin2 ? rmin2 : rmin;
80
81 if (rmax < rmin) {
82 // No cut possible this way
83 return 0;
84 }
85 // Pick a cut ratio
86 *r = 100.0 * (rmin + (rmax - rmin) * ((float)rand() / (float)RAND_MAX2147483647));
87
88 return 1;
89}
90
91/**
92 * Make a decision about a cut in a room: whether to cut at all,
93 * what way to cut, and at what position
94 */
95static enum cut_axis cut(int dim_x, int dim_y, int *r)
96{
97 enum cut_axis ret = DO_NOT_CUT;
98 // linear probability of cut
99 float chancetocut = (1 / (dim_x_init * dim_y_init)) * dim_x * dim_y - (Smin / (dim_x_init * dim_y_init - Smin));
100 float p = rand() % 10000 + 1;
101
102 // Test whether to cut at all
103 if (p / 10000 < chancetocut) {
104 return DO_NOT_CUT;
105 }
106 // Pick a random direction to cut along
107 ret = rand() % 2;
108
109 // Try to cut along this direction
110 if (!trycut(dim_x, dim_y, r, ret)) {
111 // If we cannot, try the other direction
112 if (!trycut(dim_x, dim_y, r, !ret))
113 return DO_NOT_CUT;
114 else
115 ret = !ret;
116 }
117 // Rooms have a minimal edge size
118 switch (ret) {
119 case CUT_HORIZONTALLY:
120 if ((*r / 100.0 * dim_y) < MIN_ROOM_WIDE6 || ((100.0 - *r) / 100.0 * dim_y) < MIN_ROOM_WIDE6)
121 return DO_NOT_CUT;
122 break;
123 case CUT_VERTICALLY:
124 if ((*r / 100.0 * dim_x) < MIN_ROOM_WIDE6 || ((100.0 - *r) / 100.0 * dim_x) < MIN_ROOM_WIDE6)
125 return DO_NOT_CUT;
126 break;
127 default:
128 ;
129 }
130
131 return ret;
132}
133
134static void deriv_P(int id)
135{
136 int p;
137 int prop;
138 int x = rooms[id].x;
139 int y = rooms[id].y;
140 int creator = id;
141 int dim_x = rooms[creator].w;
142 int dim_y = rooms[creator].h;
143 int newroom;
144 p = cut(dim_x, dim_y, &prop);
145
146 int w_creator = dim_x;
147 int h_creator = dim_y;
148 int w_newroom = dim_x;
149 int h_newroom = dim_y;
150 int x_newroom = x;
151 int y_newroom = y;
152
153 /*
154 Two rules :
155 P -> P h P | P -> P v P
156
157 h horizontal cut
158 v vertical cut
159 */
160 switch (p) {
161 case CUT_HORIZONTALLY:
162 h_creator = rooms[creator].h * prop / 100.0;
163
164 h_newroom = dim_y - h_creator - 1;
165 y_newroom = y + h_creator + 1;
166 break;
167 case CUT_VERTICALLY:
168 w_creator = rooms[creator].w * prop / 100.0;
169
170 w_newroom = dim_x - w_creator - 1;
171 x_newroom = x + w_creator + 1;
172 break;
173 default:
174 return;
175 }
176
177 if (!check_surf(w_creator, h_creator, w_newroom, h_newroom)) {
178 return;
179 }
180
181 newroom = mapgen_add_room(x_newroom, y_newroom, w_newroom, h_newroom);
182
183 rooms[creator].w = w_creator;
184 rooms[creator].h = h_creator;
185
186 mapgen_draw_room(newroom);
187 mapgen_draw_room(creator);
188 deriv_P(id);
189 deriv_P(newroom);
190}
191
192static void adj(struct cplist_t *cplist, int *nx, int *ny)
193{
194 static const int dx[] = {0, 0, -1, 1};
195 static const int dy[] = {-1, 1, 0, 0};
196 if (cplist->t != UP && cplist->t != DOWN && cplist->t != LEFT && cplist->t != RIGHT) {
197 *nx = 0;
198 *ny = 0;
199 }
200 *nx = cplist->x + dx[cplist->t];
201 *ny = cplist->y + dy[cplist->t];
202}
203
204static int set_internal_door(int room1, int room2)
205{
206 int i;
207 for (i = 0; i < rooms[room1].num_doors; i++) {
208 if (rooms[room1].doors[i].room == room2) {
209 rooms[room1].doors[i].internal = 1;
210 return 1;
211 }
212 }
213
214 return 0;
215}
216
217/**
218 * Join two rooms by breaking the wall between them
219 */
220void fusion(int id, int cible)
221{
222 int new_owner;
223 struct cplist_t cplist[100];
224 int correct_directory[100];
225
226 memset(correct_directory, -1, 100 * sizeof(int));
227 memset(cplist, -1, 100 * sizeof(struct cplist_t));
228
229 int nb_max;
230 nb_max = find_connection_points(id, cplist, 0);
231 int k = 0;
232 int l = 0; //index du tableau correct_directory
233 while (k < nb_max) {
234 if (cplist[k].r == cible) {
235 correct_directory[l] = k;
236 l++;
237 }
238 k++;
239 }
240
241 // Owner of the new space should be that room whose side length
242 // is equal to the length of the deleted wall
243 if (l == rooms[id].w || l == rooms[id].h)
244 new_owner = id;
245 else
246 new_owner = cible;
247 int x, y;
248 for (k = 0; k < l; k++) {
249 x = cplist[correct_directory[k]].x;
250 y = cplist[correct_directory[k]].y;
251 mapgen_put_tile(x, y, TILE_PARTITION, new_owner);
252 }
253
254 // Find the door between the given rooms and set its internal flag
255 if (l && !set_internal_door(id, cible))
256 set_internal_door(cible, id);
257}
258
259static void add_rel(int x, int y, enum connection_type type, int r, int cible)
260{
261 MakeConnect(x, y, type);
262 if ((((rooms[r].x != rooms[cible].x) || (rooms[r].w != rooms[cible].w)) && (type == UP || type == DOWN))
263 || (((rooms[r].y != rooms[cible].y) || (rooms[r].h != rooms[cible].h)) && (type == RIGHT || type == LEFT))) {
264 if (!(rand() % 4))
265 fusion(r, cible);
266 }
267}
268
269static void bulldozer(unsigned char *seen, int r)
270{
271 struct cplist_t cplist[300];
272 int max_connections = find_connection_points(r, cplist, 3);
1
'max_connections' initialized here
273 if (!max_connections)
2
Assuming 'max_connections' is 0
3
Taking true branch
274 error_message(__FUNCTION__, "Room %d does not have any connection points.", PLEASE_INFORM | IS_FATAL, r);
275
276 // Mark the room as seen by a bulldozer
277 seen[r] = 1;
278
279 // Pick a random connection to do
280 int i = rand() % max_connections;
4
Division by zero
281 int x2 = cplist[i].x;
282 int y2 = cplist[i].y;
283 adj(&cplist[i], &x2, &y2);
284
285 // if the rooms are already connected we do not create a new connection and stop the bulldozer
286 if (mapgen_are_connected(r, cplist[i].r))
287 return;
288
289 // else we create a connection
290 add_rel(cplist[i].x, cplist[i].y, cplist[i].t, r, cplist[i].r);
291
292 // and move the bulldozer to the next room
293 bulldozer(seen, mapgen_get_room(x2, y2));
294}
295
296static void launch_buldo()
297{
298 int r, i, recalculate_components;
299 unsigned char seen[total_rooms];
300 unsigned char connected_to_room_0[total_rooms];
301 memset(seen, 0, total_rooms);
302
303 // Start bulldozers so that every room has been seen
304 for (r = 0; r < total_rooms; r++) {
305 if (!(seen[r])) {
306 bulldozer(seen, r);
307 }
308 }
309
310 // Check whether the graph is connected.
311 // If it is not, ensure connectivity by connecting each vertex from
312 // a component that is not 0's to 0's whenever possible, until we have
313 // connectivity.
314 while (!mapgen_is_connected(connected_to_room_0)) {
315 recalculate_components = 0;
316 // Find the first room that is not connected to room 0
317 for (i = 1; i < total_rooms && !recalculate_components; i++) {
318 if (!connected_to_room_0[i]) {
319 // See if we can connect it to a room that belongs to 0's connected component
320 int n;
321 struct cplist_t neigh[100];
322 int nbconn, prevneigh = -1;
323 nbconn = find_connection_points(i, neigh, 3);
324 for (n = 0; n < nbconn; n++) {
325 if (neigh[n].r == prevneigh) {
326 continue;
327 } else {
328 int next = 0;
329 while (n + next < nbconn && neigh[n + next].r == neigh[n].r)
330 next++;
331
332 int pick = n + rand() % next;
333
334 n = pick;
335 }
336
337 prevneigh = neigh[n].r;
338
339 if (connected_to_room_0[neigh[n].r]) {
340 add_rel(neigh[n].x, neigh[n].y, neigh[n].t, i, neigh[n].r);
341
342 if (!(rand() % 3)) {
343 recalculate_components = 1;
344 }
345
346 break;
347 }
348 }
349 }
350 }
351 }
352}
353
354int generate_dungeon_gram(int dim_x, int dim_y)
355{
356 dim_x_init = dim_x;
357 dim_y_init = dim_y;
358 total_rooms = 0;
359
360 // Create first room
361 mapgen_add_room(1, 1, dim_x - 2, dim_y - 2);
362 mapgen_draw_room(0);
363
364 // Recursively cut
365 deriv_P(0);
366
367 // Make connections between rooms
368 launch_buldo();
369 return 0;
370}