aboutsummaryrefslogtreecommitdiff
path: root/map.c
blob: 3a8ef8fb020b2517ab7a3437af274caf12062474 (plain) (blame)
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
#include <string.h>
#include <stdlib.h>
#include <curses.h>
#include <limits.h>
#include "map.h"
#include "config.h"
#include "stack.h"

Map empty_map(size_t width, size_t height) {
    Map map = malloc(sizeof(MapTile*) * height);
    if (map == NULL) return NULL;

    for (size_t row = 0; row < height; row++) {
        map[row] = malloc(sizeof(MapTile) * width);
        if (map[row] == NULL) return NULL;
        memset(map[row], 0, width*sizeof(MapTile)); 
    }

    return map;
}

unsigned int neighbours(Position neighbour_array[], Position pos, size_t width, size_t height, \
        char visited[height][width]) {
    //TODO: add thing for when visited is NULL
    size_t cur = 0;
    if (pos.x > 0 && !visited[pos.y][pos.x - 1]) {
        neighbour_array[cur].x = pos.x - 1;
        neighbour_array[cur].y = pos.y;
        cur += 1;
    }
    if (pos.x + 1 < width && !visited[pos.y][pos.x + 1]) {
        neighbour_array[cur].x = pos.x + 1;
        neighbour_array[cur].y = pos.y;
        cur += 1;
    }
    if (pos.y > 0 && !visited[pos.y - 1][pos.x]) {
        neighbour_array[cur].x = pos.x;
        neighbour_array[cur].y = pos.y - 1;
        cur += 1;
    }
    if (pos.y + 1 < height && !visited[pos.y + 1][pos.x]) {
        neighbour_array[cur].x = pos.x;
        neighbour_array[cur].y = pos.y + 1;
        cur += 1;
    }

    return cur;
}

Map rbt_maze_map(size_t width, size_t height, unsigned int seed) {
    size_t map_width  = width * 2 - 1,
           map_height = height * 2 - 1;
    Map map = empty_map(map_width, map_height);

    // Vertical walls
    for (size_t i = 1; i < map_width; i += 2) {
        for (size_t j = 0; j < map_height; j += 1) {
            map[j][i] = WALL;
        }
    }
    // Horizontal walls
    for (size_t i = 1; i < map_height; i += 2) {
        for (size_t j = 0; j < map_width; j += 1) {
            map[i][j] = WALL;
        }
    }

    Position beginning_cell = {width - 1, height - 1};

    char visited[height][width]; // 1 if visited, 0 if not
    memset(visited, 0, sizeof(char) * width * height);

    PositionStack ps = ps_new();
    ps_push(&ps, beginning_cell);
    visited[beginning_cell.y][beginning_cell.x] = 1;

    Position na[4];

    srand(seed);

    do {
        int nc = neighbours(na, ps_peek(ps), width, height, visited);
        if (nc > 0) {
            Position next = na[rand() % nc];
            Position prev = ps_peek(ps);
            ps_push(&ps, next);
            visited[next.y][next.x] = 1;
            map[(next.y * 2 + prev.y * 2) / 2][(next.x * 2 + prev.x * 2) / 2] = EMPTY;
        } else {
            (void)ps_pop(&ps);
        }
    } while (ps_peek(ps).x != beginning_cell.x || ps_peek(ps).y != beginning_cell.y) ;

    return map;
}

void draw_map(Map map, int width, int height, Position player_pos) {
    // Draw field
    char c; // The char for the current tile
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            int color_pair = 0; // The color pair of the current char 
            switch (map[i][j]) {
                case EMPTY: 
                    color_pair = COLOR_PAIR(EMPTY_COLOR);
                    c = EMPTY_CHAR; 
                    break;
                case GOAL: 
                    color_pair = COLOR_PAIR(GOAL_COLOR);
                    c = GOAL_CHAR; 
                    break;
                case WALL: 
                    color_pair = COLOR_PAIR(WALL_COLOR);
                    c = WALL_CHAR; 
                    break;

            }
            attron(color_pair);
            mvaddch(i + DRAW_MAP_OFFSET_Y, j + DRAW_MAP_OFFSET_X, c);
            attroff(color_pair);
        }
    }

    // Draw the player
    attron(COLOR_PAIR(PLAYER_COLOR));
    mvaddch(player_pos.y + DRAW_MAP_OFFSET_Y, player_pos.x + DRAW_MAP_OFFSET_X, PLAYER_CHAR);
    attroff(COLOR_PAIR(PLAYER_COLOR));
}