aboutsummaryrefslogtreecommitdiff
path: root/cavegen.c
blob: 9c3a4af9489d286cdb8e3a649b3d137feefb1815 (plain)
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
#include "cavegen.h"

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

#define MAX_STEPS   200
#define NUM_WALKERS 100

enum direction {
    UP,
    LEFT,
    RIGHT,
    DOWN,
    NUM_DIRS,
};

void create_cave(
    enum tile_type **map, struct point **open_tiles, int *num_open_tiles,
    struct point *up, struct point *down
)
{
    // create a map consisting entirely of walls
    *map = malloc(sizeof(enum tile_type) * HEIGHT * WIDTH);
    for (int i = 0; i < HEIGHT; ++i) {
        for (int j = 0; j < WIDTH; ++j) {
            (*map)[i * WIDTH + j] = WALL;
        }
    }

    // start in the middle of the screen
    int start_x = WIDTH / 2;
    int start_y = HEIGHT / 2;

    // make the starting point GROUND
    (*map)[start_y * WIDTH + start_x] = GROUND;
    *open_tiles        = malloc(sizeof(struct point) * HEIGHT * WIDTH);
    *num_open_tiles    = 1;
    (*open_tiles)[0].x = start_x;
    (*open_tiles)[0].y = start_y;

    for (int i = 0; i < NUM_WALKERS; ++i) {
        // get a random open point
        struct point curr_point = (*open_tiles)[rand() % *num_open_tiles];

        int x_pos = curr_point.x;
        int y_pos = curr_point.y;

        // iterate until the walk exits the array or MAX_STEPS is reached
        for (int j = 1; j < MAX_STEPS - 1 && x_pos < WIDTH - 1 && x_pos >= 1 &&
                        y_pos < HEIGHT - 1 && y_pos >= 1;
             ++j) {
            // add new open point if the current point is still a wall
            if ((*map)[y_pos * WIDTH + x_pos] == WALL) {
                (*open_tiles)[*num_open_tiles].x = x_pos;
                (*open_tiles)[*num_open_tiles].y = y_pos;
                ++(*num_open_tiles);
            }

            (*map)[y_pos * WIDTH + x_pos] = GROUND; // assign ground

            // move in a random direction
            enum direction dir = rand() % NUM_DIRS;
            switch (dir) {
            case UP : --y_pos; break;
            case LEFT : --x_pos; break;
            case RIGHT : ++x_pos; break;
            case DOWN : ++y_pos; break;
            default : exit(EXIT_FAILURE); // should not occur
            }
        }
    }

    // assign the up stair and remove from open tiles
    int in            = rand() % *num_open_tiles;
    *up               = (*open_tiles)[in];
    (*open_tiles)[in] = (*open_tiles)[*num_open_tiles - 1];
    --(*num_open_tiles);
    (*map)[up->y * WIDTH + up->x] = UP_STAIR;

    // assign the down stair and remove from open tiles
    in                = rand() % *num_open_tiles;
    *down             = (*open_tiles)[in];
    (*open_tiles)[in] = (*open_tiles)[*num_open_tiles - 1];
    --(*num_open_tiles);
    (*map)[down->y * WIDTH + down->x] = DOWN_STAIR;
}