Advent of Code 2022 - 2nd attempt in c++
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

162 lines
4.5 KiB

2 years ago
#include <iostream>
#include <vector>
#include <complex>
#include <deque>
//#define ANIMATE
using namespace std;
struct Input {
vector<vector<unsigned char>> map;
unsigned width;
unsigned height;
complex<int> start;
complex<int> end;
};
complex<int> dirs[] = {
complex<int>(1, 0),
complex<int>(0, 1),
complex<int>(-1, 0),
complex<int>(0, -1)
};
Input parse()
{
Input data;
auto &map = data.map;
for (string line; getline(cin, line);) {
vector<unsigned char> row;
for (auto x : line) {
switch (x) {
case 'S':
data.start = complex<int>(row.size(), map.size());
row.push_back('a' - 'a');
break;
case 'E':
data.end = complex<int>(row.size(), map.size());
row.push_back('z' - 'a');
break;
default: row.push_back(x - 'a'); break;
}
}
data.map.push_back(row);
}
data.width = map.front().size();
data.height = map.size();
return data;
}
#ifdef ANIMATE
#include <fstream>
unsigned render_frame = 0;
void render(const Input &input, vector<vector<unsigned>> &dist, deque<complex<int>> &scan)
{
auto scan_map = (bool (*)[input.width])new bool[input.width * input.height]();
for (auto &x : scan) {
scan_map[x.imag()][x.real()] = true;
}
char fname[] = "img/00000.pam";
sprintf(fname, "img/%05u.pam", render_frame++);
auto file = ofstream(fname);
file << "P7\n";
file << "WIDTH " << input.width << '\n';
file << "HEIGHT " << input.height << '\n';
file << "DEPTH 3\nMAXVAL 255\nTUPLTYPE RGB\nENDHDR\n";
unsigned maxdist = 0;
for (unsigned y = 0; y < input.height; y++) {
for (unsigned x = 0; x < input.width; x++) {
unsigned d = dist[y][x];
if (d > maxdist) maxdist = d;
}
}
for (unsigned y = 0; y < input.height; y++) {
for (unsigned x = 0; x < input.width; x++) {
uint32_t color = 0;
color |= ((dist[y][x] * 0xFF / maxdist) & 0xFF) << 8;
color |= input.map[y][x] * 0xFF / 26;
if (scan_map[y][x]) color = 0xFF0000;
file.write((char *)&color, 3);
}
}
file.close();
delete scan_map;
}
#endif
vector<vector<unsigned>> calc_dist(const Input &input)
{
vector<vector<unsigned>> dist(input.height, vector<unsigned>(input.width));
auto &map = input.map;
deque<complex<int>> scan;
scan.push_back(input.end);
dist[input.end.imag()][input.end.real()] = 1;
while (!scan.empty()) {
auto pos = scan.front();
unsigned pos_d = dist[pos.imag()][pos.real()];
unsigned pos_h = map[pos.imag()][pos.real()];
scan.pop_front();
for (auto dir : dirs) {
auto newpos = pos + dir;
// Make sure the new position is in-bounds
if (newpos.imag() < 0 || newpos.imag() >= (int)input.height) continue;
if (newpos.real() < 0 || newpos.real() >= (int)input.width) continue;
// If the distance for this position has already been calculated,
// and is smaller than the current pos' distance, skip it.
unsigned &newpos_d = dist[newpos.imag()][newpos.real()];
if (newpos_d && newpos_d <= pos_d + 1) continue;
// Make sure the height difference isn't too big
unsigned newpos_h = map[newpos.imag()][newpos.real()];
if ((int)pos_h - (int)newpos_h > 1) continue;
// Otherwise, continue down this path
newpos_d = pos_d + 1;
scan.push_back(newpos);
}
#ifdef ANIMATE
render(input, dist, scan);
#endif
}
return dist;
}
unsigned p1(const Input &input, const vector<vector<unsigned>> &dist)
{
unsigned end_dist = dist[input.start.imag()][input.start.real()];
if (end_dist) end_dist--;
return end_dist;
}
unsigned p2(const Input &input, const vector<vector<unsigned>> &dist)
{
unsigned smallest = dist[input.start.imag()][input.start.real()];
for (unsigned y = 0; y < input.height; y++) {
for (unsigned x = 0; x < input.width; x++) {
if (input.map[y][x] == 0) {
unsigned d = dist[y][x];
if (d && d < smallest) smallest = d;
}
}
}
if (smallest) smallest--;
return smallest;
}
int main()
{
auto input = parse();
auto dist = calc_dist(input);
cout << p1(input, dist) << endl;
cout << p2(input, dist) << endl;
}