aboutsummaryrefslogtreecommitdiff
path: root/src/maze_generator.c
blob: 3a2e3b2663b44d7b479d6166aca27fabdf9bf594 (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
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
#include <stdlib.h>
#include "maze_generator.h"
#include "utilities.h"
#include "maze.h"

static void remove_wall(int **graph, struct point a, struct point b)
{
    int diff_x = a.x - b.x;
    int diff_y = a.y - b.y;
    if (diff_y == 0)
    {
        if (diff_x == 1)
            graph[b.x][b.y] &= 3;
        else if (diff_x == -1)
            graph[a.x][a.y] &= 3;
    }
    else if (diff_x == 0)
    {
        if (diff_y == 1)
            graph[b.x][b.y] &= 5;
        else if (diff_y == -1)
            graph[a.x][a.y] &= 5;
    }
}

static void generate_maze_graph(int **graph, int width, int height, struct point point)
{
    //I've been here.
    graph[point.x][point.y] &= 6;
    struct point points[4];
    int index = 0;
    //Possibilities:
    if (point.x > 0)
        points[index++] = relative_point(point, -1, 0);
    if (point.x < width - 1)
        points[index++] = relative_point(point, 1, 0);
    if (point.y > 0)
        points[index++] = relative_point(point, 0, -1);
    if (point.y < height - 1)
        points[index++] = relative_point(point, 0, 1);
    //Shuffle:
    shuffle(points, index, sizeof(struct point));
    //Examine possibilities:
    index--;
    struct point new_point;
    while (index >= 0)
    {
        new_point = points[index];
        if ((graph[new_point.x][new_point.y] & 1) == 1)
        {
            //Remove wall:
            remove_wall(graph, point, new_point);
            //Go on:
            generate_maze_graph(graph, width, height, new_point);
        }
        index--;
    }
}

int generate_maze(struct maze *maze)
{
    if (!is_valid_maze_size(maze->width) || !is_valid_maze_size(maze->height))
        return -1;
    //Init graph:
    int graph_width = ((maze->width - 2) + 1) / 2;
    int graph_height = ((maze->height - 2) + 1) / 2;
    char mem[sizeof_2d(graph_width, graph_height, sizeof(int))];
    init2d((void **)mem, graph_width, graph_height, sizeof(int));
    int **graph = (int **)mem;
    for (int x = 0; x < graph_width; x++)
        for (int y = 0; y < graph_height; y++)
            graph[x][y] = 7;
    //Generate graph:
    struct point starting_point;
    starting_point.x = 0;
    starting_point.y = 0;
    generate_maze_graph(graph, graph_width, graph_height, starting_point);
    //Convert:
    for (int x = 0; x < graph_width; x++)
    {
        for (int y = 0; y < graph_height; y++)
        {
            int real_x = (2 * x) + 1;
            int real_y = (2 * y) + 1;
            int is_last_x = x == maze->width - 2;
            int is_last_y = y == maze->height - 2;
            maze->map[real_x][real_y] = 0;
            if (!is_last_x)
                maze->map[real_x + 1][real_y] = (graph[x][y] & 4) == 4;
            if (!is_last_y)
                maze->map[real_x][real_y + 1] = (graph[x][y] & 2) == 2;
            if (!(is_last_x || is_last_y))
                maze->map[real_x + 1][real_y + 1] = 1;
        }
    }
    //Set sides:
    for (int x = 0; x < maze->width; x++)
    {
        maze->map[x][0] = 1;
        maze->map[x][maze->height - 1] = 1;
    }
    for (int y = 0; y < maze->height; y++)
    {
        maze->map[0][y] = 1;
        maze->map[maze->width - 1][y] = 1;
    }
    //Set start and end:
    maze->starting_point.x = 1;
    maze->starting_point.y = 1;
    maze->end_point.x = maze->width - 2;
    maze->end_point.y = maze->height - 2;
    return 0;
}