aboutsummaryrefslogtreecommitdiff
path: root/src/maze.c
blob: 76775b28879236b424354cb76483c80406dce2fb (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
114
115
116
117
118
119
120
121
122
123
124
#include "maze.h"
#include "grid.h"
#include "position.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int is_pos_empty(Grid grid, Position pos)
{
	return strcmp(grid_get(grid, pos), " ") != 0;
}

void add_neighbour(Position neighbours[3], unsigned int *neighbour_cnt,
				   Position neighbour_pos)
{
	neighbours[*neighbour_cnt] = neighbour_pos;
	(*neighbour_cnt)++;
}

void get_neighbours(Grid grid, Position pos, Position neighbours[3],
					unsigned int *neighbour_cnt)
{
	if (pos.y != 1U)
	{
		Position pos_down = position_create(pos.x, pos.y - 2U);

		if (is_pos_empty(grid, pos_down))
			add_neighbour(neighbours, neighbour_cnt, pos_down);
	}

	if (pos.y != grid.dimens.height - 2U)
	{
		Position pos_up = position_create(pos.x, pos.y + 2U);

		if (is_pos_empty(grid, pos_up))
			add_neighbour(neighbours, neighbour_cnt, pos_up);
	}

	if (pos.x != 1U)
	{
		Position pos_left = position_create(pos.x - 2U, pos.y);

		if (is_pos_empty(grid, pos_left))
			add_neighbour(neighbours, neighbour_cnt, pos_left);
	}

	if (pos.x != grid.dimens.width - 2U)
	{
		Position pos_right = position_create(pos.x + 2U, pos.y);

		if (is_pos_empty(grid, pos_right))
			add_neighbour(neighbours, neighbour_cnt, pos_right);
	}
}

unsigned int get_maze_size(Grid grid)
{
	return ((grid.dimens.width - 1U) / 2U) * ((grid.dimens.height - 1U) / 2U);
}

int is_whole_maze_visited(Grid grid, unsigned int visited_pos_cnt)
{
	return visited_pos_cnt == get_maze_size(grid) - 1U;
}

void grid_to_maze(Grid grid, Position start_pos)
{
	PositionStack *path = pos_stack_create(get_maze_size(grid));

	pos_stack_push(path, start_pos);

	unsigned int visited_pos_cnt = 0U;
	while (1)
	{
		Position pos = pos_stack_peek(path);

		grid_set(grid, pos, " ");

		Position neighbours[3];
		unsigned int neighbour_cnt = 0U;

		get_neighbours(grid, pos, neighbours, &neighbour_cnt);

		if (neighbour_cnt == 0U)
		{
			if (is_whole_maze_visited(grid, visited_pos_cnt))
				break;

			// Go back a step
			pos_stack_pop(path);
			continue;
		}

		visited_pos_cnt++;

		Position next_pos = neighbours[rand() % neighbour_cnt];

		Position between_pos = position_create(pos.x, pos.y);

		if (next_pos.y != pos.y)
		{
			if (next_pos.y > pos.y)
				between_pos.y += 1U;
			else
				between_pos.y -= 1U;
		}

		if (next_pos.x != pos.x)
		{
			if (next_pos.x > pos.x)
				between_pos.x += 1U;
			else
				between_pos.x -= 1U;
		}

		grid_set(grid, between_pos, " ");

		pos_stack_push(path, next_pos);

		// grid_print(grid);
	}

	pos_stack_destroy(path);
}