#include #include #include #include #include "path.h" #include "map.h" #include "structs.h" #include "priority_queue.h" #include "error.h" /* TODO: somehow get offsets back to main */ int anim(Map map, size_t width, size_t height, Position start, Position end, Position *cur, char visited[height][width], PositionPQ *frontier) { static int offset_y = 0, offset_x = 0; while (1) { draw_map(map, width, height, offset_x, offset_y, start, end, cur, NULL, visited, frontier); mvprintw(height+2 + offset_y, offset_x, "cur: %zu %zu", cur->x, cur->y); switch (getch()) { case 'h': offset_x -= 2; break; case 'l': offset_x += 2; break; case 'j': offset_y += 1; break; case 'k': offset_y -= 1; break; case 'q': return -1; default: return 0; } } return 0; } /* BLOODY FUCK IT WORKS */ Path breadth_first_search_path(int dirs, Map map, size_t width, size_t height, Position start, Position end, char visited[height][width], char should_anim) { /* The function to use to find neighbours */ unsigned int (*neighbours)(Position[], size_t[], Position, size_t, size_t, char[height][width]) = NULL; switch (dirs) { case 4: neighbours = &neighbours_4dir; break; case 8: neighbours = &neighbours_8dir; break; default: error("Tried to call breadth_first_search_path with wrong direction amount\n"); } 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) { ppq_free(frontier); if (should_anim) { clear(); } return path; /* Found path */ } Position na[dirs]; unsigned int nc = neighbours(na, NULL, 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) != PPQ_INSERT_ALREADY) { path[na[i].y][na[i].x].parent = cur; } } if (should_anim) { if (anim(map, width, height, start, end, &cur, visited, frontier) == -1) { clear(); return NULL; } } } if (should_anim) { clear(); } return NULL; } /* FIXME: THIS IS NOT YET DIJKSTRA!!! don't use for now (WIP) */ Path dijkstra_path(int dirs, Map map, size_t width, size_t height, Position start, Position end, char visited[height][width], char should_anim) { return NULL; /* The function to use to find neighbours */ unsigned int (*neighbours)(Position[], size_t[], Position, size_t, size_t, char[height][width]) = NULL; switch (dirs) { case 4: neighbours = &neighbours_4dir; break; case 8: neighbours = &neighbours_8dir; break; default: error("Tried to call breadth_first_search_path with wrong direction amount\n"); } 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) { ppq_free(frontier); return path; /* Found path */ } Position na[dirs]; size_t costs[dirs]; unsigned int nc = neighbours(na, costs, 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) != PPQ_INSERT_ALREADY) { 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; } /* FIXME: I feel like there's a better way to do this, but not sure */ size_t manhattan_distance(Position a, Position b) { size_t d = 0; if (a.x > b.x) { d += a.x - b.x; } else { d += b.x - a.x; } if (a.y > b.y) { d += a.y - b.y; } else { d += b.y - a.y; } return d; } void path_free(Path path, size_t height) { if (path == NULL) return; for (size_t i = 0; i < height; i++) { free(path[i]); } free(path); }