diff --git a/day 16/day_16_felix.cpp b/day 16/day_16_felix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7034ec94554829eb0dd5b0c596b31a4c0ce64e44 --- /dev/null +++ b/day 16/day_16_felix.cpp @@ -0,0 +1,155 @@ +#include <bits/stdc++.h> +using namespace std; +const bool DEBUG = false; + +#define coord pair <int, int> +#define ll long long + +struct State { + coord pos; + char dir; + bool operator<(const State& other) const { + return tie(pos.first, pos.second, dir) < tie(other.pos.first, other.pos.second, other.dir); + } +}; + +map<char,coord> DIRMAP = { + {'N', {0, -1}}, + {'S', {0, 1}}, + {'W', {-1, 0}}, + {'E', {1, 0}} +}; + +map<char,vector<char>> TURNMAP = { + {'N', {'W', 'E'}}, + {'S', {'E', 'W'}}, + {'W', {'S', 'N'}}, + {'E', {'N', 'S'}} +}; + +coord GOAL; +vector<string> MAZE; + +coord parse_input() { + string line; + coord start; + int row = 0; + while (getline(cin, line)) { + MAZE.push_back(line); + if (line.find('E') != string::npos) { + GOAL = {line.find('E'), row}; + } + if (line.find('S') != string::npos) { + start = {line.find('S'), row}; + } + row++; + } + return start; +} + +void visualize(map<coord, bool> visited) { + vector<string> test_maze = MAZE; + for (auto v : visited) { + if (v.second) { + test_maze[v.first.second][v.first.first] = 'O'; + } + } + for (auto row : test_maze) { + cout << row << endl; + } +} + +vector<State> neighbor_states(State x0) { + vector<State> neighbors; + for (auto d : TURNMAP[x0.dir]) { + neighbors.push_back({x0.pos, d}); + } + coord new_pos = {x0.pos.first + DIRMAP[x0.dir].first, x0.pos.second + DIRMAP[x0.dir].second}; + neighbors.push_back({new_pos, x0.dir}); + return neighbors; +} + +pair<ll,ll> find_seats(coord start) { + State start_state = {start, 'E'}; + + map<State, ll> costs; + costs[start_state] = 0; + + auto cost_comp = [&costs](const State& lhs, const State& rhs) { + return costs[lhs] > costs[rhs]; + }; + + priority_queue<State, vector<State>, decltype(cost_comp)> q(cost_comp); + q.push(start_state); + + ll cheapest_goal = LLONG_MAX; + set<char> goal_dirs = {}; + + map<State, vector<State>> path_to_goal; + + while (!q.empty()) { + State cur = q.top(); + q.pop(); + + if (MAZE[cur.pos.second][cur.pos.first] == '#') continue; + if (costs[cur] > cheapest_goal) break; + + if (cur.pos == GOAL) { + if (goal_dirs.empty() || costs[cur] < cheapest_goal) { + goal_dirs = {cur.dir}; + cheapest_goal = costs[cur]; + } else if (costs[cur] == cheapest_goal) { + goal_dirs.insert(cur.dir); + } + } + + + for (auto n : neighbor_states(cur)) { + ll new_cost = costs[cur] + (n.dir == cur.dir ? 1 : 1000); + if (!costs.count(n) || costs[n] > new_cost) { + costs[n] = new_cost; + q.push(n); + path_to_goal[n] = {cur}; + } else if (costs[n] == new_cost) { + path_to_goal[n].push_back(cur); + } + } + } + + vector<State> part_of_path; + for (auto d : goal_dirs) { + part_of_path.push_back({GOAL, d}); + } + map<coord, bool> visited; + ll count = 0; + while (!part_of_path.empty()) { + State cur = part_of_path.back(); + part_of_path.pop_back(); + + if (!visited.count(cur.pos)) { + count++; + } + visited[cur.pos] = true; + + for (auto p : path_to_goal[cur]) { + part_of_path.push_back(p); + } + } + if (DEBUG) visualize(visited); + return {cheapest_goal, count}; + +} + +int main () { + coord start = parse_input(); + if (DEBUG) { + cout << "Start " << start.first << " " << start.second << endl; + cout << "Goal " << GOAL.first << " " << GOAL.second << endl; + } + pair<ll,ll> parts = find_seats(start); + + cout << "Part 1: " << parts.first << endl; + + cout << "Part 2: " << parts.second << endl; + return 0; +} \ No newline at end of file