aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.h2
-rw-r--r--main.c11
-rw-r--r--map.c75
-rw-r--r--map.h9
-rw-r--r--maps/diagonal22
-rw-r--r--path.c59
-rw-r--r--path.h3
-rw-r--r--priority_queue.c17
-rw-r--r--priority_queue.h2
-rw-r--r--structs.h2
10 files changed, 185 insertions, 17 deletions
diff --git a/config.h b/config.h
index 096f612..a540c5c 100644
--- a/config.h
+++ b/config.h
@@ -10,6 +10,8 @@
#define WALL_CHAR '#'
#define START_CHAR_1 'S'
#define START_CHAR_2 'T'
+#define CURSOR_CHAR_1 '<'
+#define CURSOR_CHAR_2 '>'
#define DRAW_MAP_OFFSET_X 2
#define DRAW_MAP_OFFSET_Y 1
diff --git a/main.c b/main.c
index b7044a6..016b4e2 100644
--- a/main.c
+++ b/main.c
@@ -37,6 +37,8 @@ void initialize_colors(void) {
init_pair(WALL_COLOR, COLOR_WHITE, COLOR_WHITE);
init_pair(START_COLOR, -1, COLOR_RED);
init_pair(PATH_COLOR, COLOR_RED, COLOR_RED);
+ init_pair(FRONTIER_COLOR, COLOR_BLUE, COLOR_BLUE);
+ init_pair(CURSOR_COLOR, -1, COLOR_RED);
}
void init_ncurses(void) {
@@ -78,13 +80,14 @@ int main(int argc, char **argv) {
int offset_x = 0, offset_y = 0;
- draw_map(map, width, height, offset_x, offset_y, start_pos, end_pos, NULL, NULL);
+ draw_map(map, width, height, offset_x, offset_y, start_pos, end_pos, NULL, NULL, NULL, NULL);
+ //print_map_out(map, width, height);
char visited[height][width];
- Path path = breadth_first_search_path_4dir(map, width, height, start_pos, end_pos, visited);
+ Path path = breadth_first_search_path_8dir(map, width, height, start_pos, end_pos, visited, 1);
while (1) {
- draw_map(map, width, height, offset_x, offset_y, start_pos, end_pos, path, visited);
+ draw_map(map, width, height, offset_x, offset_y, start_pos, end_pos, NULL, path, visited, NULL);
char c = getch();
switch (c) {
case 'h': offset_x -= 2; break;
@@ -95,7 +98,7 @@ int main(int argc, char **argv) {
if (is_maze) {
//FIXME: free it all before generating a new one
map = rbt_maze_map(mwidth, mheight, (unsigned int) time(NULL));
- path = breadth_first_search_path_4dir(map, width, height, start_pos, end_pos, visited);
+ path = breadth_first_search_path_8dir(map, width, height, start_pos, end_pos, visited, 1);
}
break;
case 'q': endwin(); return 0;
diff --git a/map.c b/map.c
index b0671ae..735a00c 100644
--- a/map.c
+++ b/map.c
@@ -8,6 +8,7 @@
#include "stack.h"
#include "error.h"
#include "path.h"
+#include "priority_queue.h"
Map empty_map(size_t width, size_t height) {
Map map = malloc(sizeof(MapTile*) * height);
@@ -22,6 +23,7 @@ Map empty_map(size_t width, size_t height) {
return map;
}
+/* Honestly, what a shitty fucking way to implement this */
unsigned int neighbours_4dir(Position neighbour_array[], Position pos, size_t width, size_t height, \
char visited[height][width]) {
size_t cur = 0;
@@ -49,6 +51,54 @@ unsigned int neighbours_4dir(Position neighbour_array[], Position pos, size_t wi
return cur;
}
+unsigned int neighbours_8dir(Position neighbour_array[], Position pos, size_t width, size_t height, \
+ char visited[height][width]) {
+ 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;
+ }
+
+ if (pos.x > 0 && pos.y > 0 && !visited[pos.y - 1][pos.x - 1]) {
+ neighbour_array[cur].x = pos.x - 1;
+ neighbour_array[cur].y = pos.y - 1;
+ cur += 1;
+ }
+ if (pos.x + 1 < width && pos.y > 0 && !visited[pos.y - 1][pos.x + 1]) {
+ neighbour_array[cur].x = pos.x + 1;
+ neighbour_array[cur].y = pos.y - 1;
+ cur += 1;
+ }
+ if (pos.x + 1 < width && pos.y + 1 < height && !visited[pos.y + 1][pos.x + 1]) {
+ neighbour_array[cur].x = pos.x + 1;
+ neighbour_array[cur].y = pos.y + 1;
+ cur += 1;
+ }
+ if (pos.x > 0 && pos.y + 1 < height && !visited[pos.y + 1][pos.x - 1]) {
+ neighbour_array[cur].x = pos.x - 1;
+ 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;
@@ -145,7 +195,8 @@ Map file_plaintext_map(char *filename, size_t *width, size_t *height, Position *
/* FIXME: I don't think we need DRAW_MAP_OFFSET_{X,Y} anymore
* Although, at the same time, it does make less magic values, so I guess it's fine */
/* TODO: Maybe add an option to render with ▄? that doubles the resolution, but requires us to use ncursesw, probably. */
-void draw_map(Map map, size_t width, size_t height, int offset_x, int offset_y, Position start, Position goal, Path path, char visited[height][width]) {
+/* TODO: so many fucking arguments lmao. Break it down into several functions? */
+void draw_map(Map map, size_t width, size_t height, int offset_x, int offset_y, Position start, Position goal, Position *cursor, Path path, char visited[height][width], PositionPQ *frontier) {
(void)path;
/* I think it flickers less when we do that */
wnoutrefresh(stdscr);
@@ -203,6 +254,20 @@ void draw_map(Map map, size_t width, size_t height, int offset_x, int offset_y,
attroff(color_pair);
}
}
+
+ /* Render the frontier */
+ if (frontier != NULL) {
+ attron(COLOR_PAIR(FRONTIER_COLOR));
+ while (frontier->next != NULL) {
+ mvaddch(frontier->pos.y + DRAW_MAP_OFFSET_Y + offset_y, frontier->pos.x*2 + DRAW_MAP_OFFSET_X + offset_x, ' ');
+ mvaddch(frontier->pos.y + DRAW_MAP_OFFSET_Y + offset_y, frontier->pos.x*2 + DRAW_MAP_OFFSET_X + 1 + offset_x, ' ');
+ frontier = frontier->next;
+ }
+ mvaddch(frontier->pos.y + DRAW_MAP_OFFSET_Y + offset_y, frontier->pos.x*2 + DRAW_MAP_OFFSET_X + offset_x, ' ');
+ mvaddch(frontier->pos.y + DRAW_MAP_OFFSET_Y + offset_y, frontier->pos.x*2 + DRAW_MAP_OFFSET_X + 1 + offset_x, ' ');
+
+ attroff(COLOR_PAIR(FRONTIER_COLOR));
+ }
/* Draw path */
if (path != NULL) {
@@ -227,6 +292,14 @@ void draw_map(Map map, size_t width, size_t height, int offset_x, int offset_y,
mvaddch(goal.y + DRAW_MAP_OFFSET_Y + offset_y, goal.x*2 + DRAW_MAP_OFFSET_X + offset_x, GOAL_CHAR_1);
mvaddch(goal.y + DRAW_MAP_OFFSET_Y + offset_y, goal.x*2 + DRAW_MAP_OFFSET_X + 1 + offset_x, GOAL_CHAR_2);
attroff(COLOR_PAIR(GOAL_COLOR));
+
+ /* Draw the cursor */
+ if (cursor != NULL) {
+ attron(COLOR_PAIR(CURSOR_COLOR));
+ mvaddch(cursor->y + DRAW_MAP_OFFSET_Y + offset_y, cursor->x*2 + DRAW_MAP_OFFSET_X + offset_x, CURSOR_CHAR_1);
+ mvaddch(cursor->y + DRAW_MAP_OFFSET_Y + offset_y, cursor->x*2 + DRAW_MAP_OFFSET_X + 1 + offset_x, CURSOR_CHAR_2);
+ attroff(COLOR_PAIR(CURSOR_COLOR));
+ }
attroff(A_BOLD);
doupdate();
diff --git a/map.h b/map.h
index 09e5c90..d940357 100644
--- a/map.h
+++ b/map.h
@@ -4,7 +4,7 @@
#include <stddef.h>
#include "structs.h"
#include "path.h"
-
+#include "priority_queue.h"
/* Returns an empty map of given size */
Map empty_map(size_t width, size_t height);
@@ -12,6 +12,9 @@ Map empty_map(size_t width, size_t height);
/* Stores all the existing 4dir neighbours of pos in neighbour_array and returns their amount */
unsigned int neighbours_4dir(Position neighbour_array[], Position pos, size_t width, size_t height, \
char visited[height][width]);
+/* Stores all the existing 8dir neighbours of pos in neighbour_array and returns their amount */
+unsigned int neighbours_8dir(Position neighbour_array[], Position pos, size_t width, size_t height, \
+ char visited[height][width]);
/* https://en.wikipedia.org/wiki/Maze_generation_algorithm#Randomized_depth-first_search
* WARNING: width and height are not the width and height of the returned map!
@@ -35,8 +38,8 @@ Map rbt_maze_map(size_t width, size_t height, unsigned int seed);
Map file_plaintext_map(char *filename, size_t *width, size_t *height, Position *start_pos, Position *end_pos);
/* Draw the map. Bet you didn't expect that.
- * path could be NULL to draw a map with no path */
-void draw_map(Map map, size_t width, size_t height, int offset_x, int offset_y, Position start, Position goal, Path path, char visited[height][width]);
+ * path could be NULL to draw a map with no path. So can cursor, frontier and visited */
+void draw_map(Map map, size_t width, size_t height, int offset_x, int offset_y, Position start, Position goal, Position *cursor, Path path, char visited[height][width], PositionPQ *frontier);
void print_map_out(Map map, size_t width, size_t height);
diff --git a/maps/diagonal b/maps/diagonal
new file mode 100644
index 0000000..de08a51
--- /dev/null
+++ b/maps/diagonal
@@ -0,0 +1,22 @@
+20x20
+.#@x
+#...................
+.#..................
+..#.................
+...#................
+....#..........x....
+.....#..............
+......#.............
+.......#............
+........#...........
+.........#..........
+..........#.........
+...........#........
+............#.......
+.............#......
+..............#.....
+...............#....
+................#...
+.....@...........#..
+..................#.
+...................#
diff --git a/path.c b/path.c
index e2d42c5..adce6b2 100644
--- a/path.c
+++ b/path.c
@@ -1,14 +1,25 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <curses.h>
#include "path.h"
#include "map.h"
#include "structs.h"
#include "priority_queue.h"
+int anim(Map map, size_t width, size_t height, Position start, Position end, Position *cur, char visited[height][width], PositionPQ *frontier) {
+ draw_map(map, width, height, 0, 0, start, end, cur, NULL, visited, frontier);
+ mvprintw(height+2, 0, "cur: %zu %zu", cur->x, cur->y);
+ /* TODO: input, automatic mode */
+ switch (getch()) {
+ case 'q':
+ return -1;
+ }
+ return 0;
+}
/* BLOODY FUCK IT WORKS */
-Path breadth_first_search_path_4dir(Map map, size_t width, size_t height, Position start, Position end, char visited[height][width]) {
+Path breadth_first_search_path_4dir(Map map, size_t width, size_t height, Position start, Position end, char visited[height][width], char should_anim) {
Path path = malloc(sizeof(PathNode)*height);
if (path == NULL) return NULL;
@@ -40,6 +51,52 @@ Path breadth_first_search_path_4dir(Map map, size_t width, size_t height, Positi
ppq_insert(&frontier, na[i], 0);
path[na[i].y][na[i].x].parent = cur;
}
+
+ if (should_anim) {
+ if (anim(map, width, height, start, end, &cur, visited, frontier) == -1) return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+Path breadth_first_search_path_8dir(Map map, size_t width, size_t height, Position start, Position end, char visited[height][width], char should_anim) {
+ Path path = malloc(sizeof(PathNode)*height);
+ if (path == NULL) return NULL;
+
+ for (size_t row = 0; row < height; row++) {
+ path[row] = malloc(sizeof(PathNode) * width);
+ if (path[row] == NULL) return NULL;
+ memset(path[row], 0, width * sizeof(PathNode));
+ }
+
+ PositionPQ *frontier = ppq_new(start, 0);
+
+ memset(visited, 0, height * width * sizeof(char));
+
+ while (frontier != NULL) {
+ Position cur = ppq_pop(&frontier);
+ visited[cur.y][cur.x] = 1;
+
+ if (cur.x == end.x && cur.y == end.y) {
+ return path; /* Found path */
+ }
+
+ Position na[8];
+ unsigned int nc = neighbours_8dir(na, cur, width, height, visited);
+
+ for (unsigned int i = 0; i < nc; i++) {
+ /* The Russian constitution doesn't allow walking on walls */
+ if (map[na[i].y][na[i].x] == WALL) continue;
+
+ if (ppq_insert(&frontier, na[i], 0) != 3) {
+ path[na[i].y][na[i].x].parent = cur;
+ }
+ }
+
+ if (should_anim) {
+ if (anim(map, width, height, start, end, &cur, visited, frontier) == -1) return NULL;
+ }
}
return NULL;
diff --git a/path.h b/path.h
index 5b7392b..d4efe6d 100644
--- a/path.h
+++ b/path.h
@@ -4,7 +4,8 @@
#include "structs.h"
#include "map.h"
-Path breadth_first_search_path_4dir(Map map, size_t width, size_t height, Position start, Position end, char visited[height][width]);
+Path breadth_first_search_path_4dir(Map map, size_t width, size_t height, Position start, Position end, char visited[height][width], char should_anim);
+Path breadth_first_search_path_8dir(Map map, size_t width, size_t height, Position start, Position end, char visited[height][width], char should_anim);
Path astar_path_4dir(Map map, size_t width, size_t height, Position start, Position end);
size_t manhattan_distance(Position a, Position b);
diff --git a/priority_queue.c b/priority_queue.c
index 472f5c3..d2517a6 100644
--- a/priority_queue.c
+++ b/priority_queue.c
@@ -12,35 +12,40 @@ PositionPQ *ppq_new(Position pos, size_t priority) {
return ppq;
}
-/* FIXME: this is shitty */
-void ppq_insert(PositionPQ **ppq, Position pos, size_t priority) {
+/* FIXME: insted of `return n` introduce some defines with error codes,
+ * or an enum I don't care */
+int ppq_insert(PositionPQ **ppq, Position pos, size_t priority) {
+ //printf("Inserting %zu %zu\n", pos.x, pos.y);
PositionPQ *start = *ppq;
if ((*ppq) == NULL) {
(*ppq) = ppq_new(pos, priority);
- return;
+ return 1;
}
PositionPQ *n = ppq_new(pos, priority);
if (start->priority > priority) {
n->next = start;
start = n;
- return;
+ return 2;
}
PositionPQ *temp = *ppq;
while(temp->next != NULL && temp->next->priority <= priority) {
if (temp->pos.x == pos.x && temp->pos.y == pos.y && temp->priority <= priority) {
- return; /* pos is already at the start of ppq with a fine priority */
+ return 3; /* pos is already in ppq with a fine priority */
}
temp = temp->next;
}
+ if (temp->pos.x == pos.x && temp->pos.y == pos.y && temp->priority <= priority) {
+ return 3; /* pos is already in ppq with a fine priority */
+ }
n->next = temp->next;
temp->next = n;
- return;
+ return 4;
}
Position ppq_pop(PositionPQ **ppq) {
diff --git a/priority_queue.h b/priority_queue.h
index 1f933e7..2ac580e 100644
--- a/priority_queue.h
+++ b/priority_queue.h
@@ -19,7 +19,7 @@ typedef struct PositionPQNode_s PositionPQ;
PositionPQ *ppq_new(Position pos, size_t priority);
/* Insert a pos with priority into a given PositionPQ */
-void ppq_insert(PositionPQ **ppq, Position pos, size_t priority);
+int ppq_insert(PositionPQ **ppq, Position pos, size_t priority);
/* Remove and return the position with the lowest priority */
Position ppq_pop(PositionPQ **ppq);
diff --git a/structs.h b/structs.h
index 2c461fc..fa8982b 100644
--- a/structs.h
+++ b/structs.h
@@ -23,6 +23,8 @@ enum Colors_e {
WALL_COLOR = 4,
START_COLOR = 5,
PATH_COLOR = 6,
+ FRONTIER_COLOR = 7,
+ CURSOR_COLOR = 8,
};
/* A map is a 2D array of MapTiles.