64 lines
2 KiB
C
64 lines
2 KiB
C
|
|
#include "dijkstra.h"
|
||
|
|
#include <stddef.h>
|
||
|
|
|
||
|
|
static int passable(uint8_t t) {
|
||
|
|
return t == T_FLOOR || t == T_CORRIDOR || t == T_DOOR || t == T_BRIDGE
|
||
|
|
|| t == T_STAIRS_UP || t == T_STAIRS_DOWN;
|
||
|
|
}
|
||
|
|
|
||
|
|
void bfs_from(grid_t g, int sx, int sy, dist_map_t dist,
|
||
|
|
int extra_passable_x, int extra_passable_y) {
|
||
|
|
for (int y = 0; y < DROWS; y++)
|
||
|
|
for (int x = 0; x < DCOLS; x++)
|
||
|
|
dist[y][x] = DIST_UNREACHABLE;
|
||
|
|
|
||
|
|
if (!grid_in_bounds(sx, sy)) return;
|
||
|
|
|
||
|
|
static const int dx4[4] = {1, -1, 0, 0};
|
||
|
|
static const int dy4[4] = {0, 0, 1, -1};
|
||
|
|
|
||
|
|
int qx[DCOLS * DROWS];
|
||
|
|
int qy[DCOLS * DROWS];
|
||
|
|
int head = 0, tail = 0;
|
||
|
|
|
||
|
|
dist[sy][sx] = 0;
|
||
|
|
qx[tail] = sx; qy[tail] = sy; tail++;
|
||
|
|
|
||
|
|
while (head < tail) {
|
||
|
|
int cx = qx[head], cy = qy[head]; head++;
|
||
|
|
int16_t d = dist[cy][cx];
|
||
|
|
for (int i = 0; i < 4; i++) {
|
||
|
|
int nx = cx + dx4[i], ny = cy + dy4[i];
|
||
|
|
if (!grid_in_bounds(nx, ny)) continue;
|
||
|
|
int is_extra = (nx == extra_passable_x && ny == extra_passable_y);
|
||
|
|
if (!is_extra && !passable(g[ny][nx].terrain)) continue;
|
||
|
|
if (dist[ny][nx] <= d + 1) continue;
|
||
|
|
dist[ny][nx] = d + 1;
|
||
|
|
qx[tail] = nx; qy[tail] = ny; tail++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int is_connected(grid_t g, int *out_unreached) {
|
||
|
|
int sx = -1, sy = -1, total = 0;
|
||
|
|
for (int y = 0; y < DROWS; y++) {
|
||
|
|
for (int x = 0; x < DCOLS; x++) {
|
||
|
|
if (passable(g[y][x].terrain)) {
|
||
|
|
if (sx < 0) { sx = x; sy = y; }
|
||
|
|
total++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (total == 0) { if (out_unreached) *out_unreached = 0; return 1; }
|
||
|
|
|
||
|
|
static dist_map_t dist;
|
||
|
|
bfs_from(g, sx, sy, dist, -1, -1);
|
||
|
|
int reached = 0;
|
||
|
|
for (int y = 0; y < DROWS; y++)
|
||
|
|
for (int x = 0; x < DCOLS; x++)
|
||
|
|
if (passable(g[y][x].terrain) && dist[y][x] != DIST_UNREACHABLE)
|
||
|
|
reached++;
|
||
|
|
if (out_unreached) *out_unreached = total - reached;
|
||
|
|
return reached == total;
|
||
|
|
}
|