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
|
#include <queue>
#include <iostream>
#include <iomanip>
#include <vector>
#include <cassert>
#include <limits>
constexpr int width = 10;
constexpr int height = 10;
constexpr int unset_distance = std::numeric_limits<int>::max();
constexpr int shallow_water_cost = 1;
constexpr int deep_water_cost = 12;
struct tile
{
bool impassable;
bool aground;
int distance;
};
struct edge
{
int x;
int y;
int distance;
};
static constexpr auto operator<=>(edge a, edge b) { return a.distance <=> b.distance; }
#define _ tile{ .impassable = false, .aground = false, .distance = unset_distance }
#define W tile{ .impassable = true, .aground = false, .distance = unset_distance }
#define L tile{ .impassable = true, .aground = true, .distance = unset_distance }
tile board[width * height]
{
_, _, L, L, L, L, _, _, _, _,
_, _, _, L, L, _, _, _, _, _,
_, _, _, _, _, _, _, _, _, _,
_, W, W, W, _, _, _, _, _, _,
_, W, W, W, _, _, W, W, _, _,
_, _, W, _, _, L, L, L, L, _,
_, _, _, _, L, L, L, _, L, _,
_, _, _, _, _, L, L, L, L, _,
_, _, _, _, _, _, L, L, _, _,
_, _, _, _, _, _, _, _, _, _,
};
#undef L
#undef W
#undef _
[[nodiscard]] static constexpr bool in_bounds_x(int x) { return x >= 0 && x < width; }
[[nodiscard]] static constexpr bool in_bounds_y(int y) { return y >= 0 && y < height; }
[[nodiscard]] static constexpr bool in_bounds(int x, int y) { return in_bounds_x(x) && in_bounds_y(y); }
[[nodiscard]] static constexpr int xy(int x, int y)
{
assert(in_bounds_x(x));
assert(in_bounds_y(y));
return x + y * width;
}
using queue_type = std::priority_queue<edge, std::vector<edge>, std::greater<edge>>;
static void push_coastal_tiles_onto_queue(int x, int y, queue_type& queue)
{
if (in_bounds(x, y))
{
if (tile& v = board[xy(x, y)]; v.distance == unset_distance)
{
if (v.aground)
{
v.distance = 0;
push_coastal_tiles_onto_queue(x + 1, y, queue);
push_coastal_tiles_onto_queue(x - 1, y, queue);
push_coastal_tiles_onto_queue(x, y + 1, queue);
push_coastal_tiles_onto_queue(x, y - 1, queue);
}
else queue.push({x, y, v.impassable? deep_water_cost: shallow_water_cost});
}
}
}
int main()
{
queue_type queue;
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
if (tile& v = board[xy(x, y)]; v.aground && v.distance == unset_distance)
push_coastal_tiles_onto_queue(x, y, queue);
}
while (queue.size())
{
auto [x, y, d] = queue.top(); queue.pop();
if (tile& v = board[xy(x, y)]; v.distance > d)
{
v.distance = d;
if (in_bounds(x - 1, y)) queue.push({x - 1, y, d + (board[xy(x - 1, y)].impassable? deep_water_cost: shallow_water_cost)});
if (in_bounds(x + 1, y)) queue.push({x + 1, y, d + (board[xy(x + 1, y)].impassable? deep_water_cost: shallow_water_cost)});
if (in_bounds(x, y + 1)) queue.push({x, y + 1, d + (board[xy(x, y + 1)].impassable? deep_water_cost: shallow_water_cost)});
if (in_bounds(x, y - 1)) queue.push({x, y - 1, d + (board[xy(x, y - 1)].impassable? deep_water_cost: shallow_water_cost)});
}
}
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
std::cout << std::setw(2) << (board[xy(x, y)].distance) << ' ';
std::cout << '\n';
}
}
|