diff --git a/day 20/day_20_felix.cpp b/day 20/day_20_felix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..56cfdfadc4cc1ef6c4cbd3074b987a7f66739fa0 --- /dev/null +++ b/day 20/day_20_felix.cpp @@ -0,0 +1,147 @@ +/* +Usage: + g++ -o main day_X_felix.cpp (or compile however you like) + ./main < input.txt (pipe the input) + + Options: + -d : debug mode +*/ + +#include <bits/stdc++.h> +using namespace std; +bool DEBUG = false; + +// Standard definitions for many problems +#define coord pair <int, int> +#define ll long long + +set<coord> FLOORS; +set<coord> WALLS; +coord START; +coord END; +int N, M = 0; +array<array<bool, 145>, 145> IS_WALL = {true}; +map<coord, ll> TO_COME; +map<coord, ll> TO_GO; + +void parse_input() { + string line; + int row = 0; + while (getline(cin, line)) { + if (N == 0) N = line.size(); + int col = 0; + for (char c : line) { + if (c != '#') { + IS_WALL[row][col] = false; + FLOORS.insert({row, col}); + if (c == 'S') START = {row, col}; + if (c == 'E') END = {row, col}; + } else { + IS_WALL[row][col] = true; + WALLS.insert({row, col}); + } + col++; + } + row++; + } + M = row; + if (DEBUG) { + cout << "N: " << N << " M: " << M << endl; + cout << "Start: " << START.first << " " << START.second << endl; + cout << "End: " << END.first << " " << END.second << endl; + int n_walls = WALLS.size() - 2 * N - 2 * M + 4; + cout << "Walls: " << n_walls << endl; + } +} + +bool in_bounds(coord u) { + return u.first >= 0 && u.first < M && u.second >= 0 && u.second < N; +} + +vector<coord> neighbors(coord u) { + vector<coord> n = { + {u.first - 1, u.second}, + {u.first + 1, u.second}, + {u.first, u.second - 1}, + {u.first, u.second + 1} + }; + return n; +} + +vector<pair<coord,int>> cheat_neighbors(coord u, int cheat_length) { + vector<pair<coord,int>> nlist; + + // grab all squares within distance cheat_length that are not in a wall + for (int i = -cheat_length; i <= cheat_length; i++) { + for (int j = -cheat_length + abs(i); j <= cheat_length - abs(i); j++) { + coord n = {u.first + i, u.second + j}; + if (!in_bounds(n) || IS_WALL[n.first][n.second]) continue; + int cost = abs(i) + abs(j); + + if (cost <= cheat_length) nlist.push_back({n, cost}); + + } + } + + return nlist; +} + + + +map<coord, ll> bfs(coord start) { + queue<tuple<ll, coord>> q; + q.push({0, start}); + array<array<bool, 145>, 145> visited = {false}; + + ll n_cheats = 0; + + map<coord, ll> costs; + costs[start] = 0; + visited[start.first][start.second] = true; + + while (!q.empty()) { + auto [c, pos] = q.front(); q.pop(); + + for (coord n : neighbors(pos)) if (in_bounds(n) && !IS_WALL[n.first][n.second] && !visited[n.first][n.second]) { + q.push({c + 1, n}); + costs[n] = c + 1; + visited[n.first][n.second] = true; + } + } + + return costs; +} + +ll n_cheats(int cheat_distance, ll baseline) { + ll n_cheats = 0; + for (auto [pos, cost] : TO_COME) if (cost < baseline) { + for (auto [cheat_pos, cheat_cost] : cheat_neighbors(pos, cheat_distance)) { + if (TO_GO[cheat_pos] + cost + cheat_cost <= baseline) { + n_cheats++; + } + } + } + return n_cheats; +} + +int main (int argc, char* argv[]) { + for (int i = 0; i < argc; i++) if (string(argv[i]) == "-d") DEBUG = true; + + parse_input(); + + TO_COME = bfs(START); + TO_GO = bfs(END); + ll baseline = TO_COME[END]; + + if (DEBUG) { + cout << "Baseline: " << baseline << endl; + } + + ll part1 = n_cheats(2, baseline - 100); + cout << "Part 1: " << part1 << endl; + + ll part2 = n_cheats(20, baseline - 100); + cout << "Part 2: " << part2 << endl; + + return 0; +} \ No newline at end of file diff --git a/day 21/day_21_felix.cpp b/day 21/day_21_felix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cb061b3ae41898f0fd2b3514c0fc61fa79fc9da2 --- /dev/null +++ b/day 21/day_21_felix.cpp @@ -0,0 +1,115 @@ +/* +Usage: + g++ -o main day_X_felix.cpp (or compile however you like) + ./main < input.txt (pipe the input) + + Options: + -d : debug mode +*/ + +#include <bits/stdc++.h> +using namespace std; +bool DEBUG = false; + +// Standard definitions for many problems +#define coord pair <int, int> +#define ll long long + +map <char, coord> dig_map = { + {'7', {0, 0}}, {'8', {0, 1}}, {'9', {0, 2}}, + {'4', {1, 0}}, {'5', {1, 1}}, {'6', {1, 2}}, + {'1', {2, 0}}, {'2', {2, 1}}, {'3', {2, 2}}, + {'0', {3, 1}}, {'A', {3, 2}} +}; + +map <char, coord> dir_map = { + {'^', {0, 1}}, {'A', {0, 2}}, + {'<', {1, 0}}, {'v', {1, 1}}, {'>', {1, 2}} +}; + +vector<string> dig_path(char c1, char c2) { + coord p1 = dig_map[c1], p2 = dig_map[c2]; + int dx = p2.second - p1.second, dy = p2.first - p1.first; + string sx = dx > 0 ? string(dx, '>') : string(-dx, '<'); + string sy = dy > 0 ? string(dy, 'v') : string(-dy, '^'); + + vector<string> paths; + if (!(p1.first == 3 && p2.second == 0)) paths.push_back(sx + sy + 'A'); + if (!(p2.first == 3 && p1.second == 0)) paths.push_back(sy + sx + 'A'); + // if (DEBUG) for (string path : paths) cout << "path: " << path << endl; + return paths; +} + + +vector<string> dir_path(char c1, char c2) { + coord p1 = dir_map[c1], p2 = dir_map[c2]; + int dx = p2.second - p1.second, dy = p2.first - p1.first; + string sx = dx > 0 ? string(dx, '>') : string(-dx, '<'); + string sy = dy > 0 ? string(dy, 'v') : string(-dy, '^'); + + vector<string> paths; + if (!(p1.first == 0 && p2.second == 0)) paths.push_back(sx + sy + 'A'); + if (!(p2.first == 0 && p1.second == 0)) paths.push_back(sy + sx + 'A'); + + // if (DEBUG) for (string path : paths) cout << "path: " << path << endl; + return paths; +} + + +map<tuple<char, char, int>, ll> CACHE; +ll dir_presses(char c1, char c2, int depth, bool digit_layer = false) { + + if (CACHE.find({c1, c2, depth}) != CACHE.end()) return CACHE[{c1, c2, depth}]; + + if (depth == 0) { + vector<string> p = dir_path(c1, c2); + return p[0].size(); + } + + vector<string> paths = digit_layer ? dig_path(c1, c2) : dir_path(c1, c2); + + ll shortest = LLONG_MAX; + for (string p : paths) { + ll lower_path = 0; + for (int i = 0; i < p.size(); i++) { + char c1 = i == 0 ? 'A' : p[i-1]; + char c2 = p[i]; + lower_path += dir_presses(c1, c2, depth -1); + } + shortest = min(shortest, lower_path); + } + CACHE[{c1, c2, depth}] = shortest; + return shortest; +} + + +int complexity(string &input) { + // remove last character and parse as int + return stoi(input.substr(0, input.size() - 1)); +} + +int main (int argc, char* argv[]) { + for (int i = 0; i < argc; i++) if (string(argv[i]) == "-d") DEBUG = true; + + string input; + string presses; + + ll part1 = 0; + ll part2 = 0; + + while (cin >> input) { + int c = complexity(input); + + input = 'A' + input; + + for (int i = 0; i < input.size() - 1; i++) { + part1 += c * dir_presses(input[i], input[i+1], 2, true); + part2 += c * dir_presses(input[i], input[i+1], 25, true); + } + } + cout << "Part 1: " << part1 << endl; + cout << "Part 2: " << part2 << endl; + + + return 0; +} \ No newline at end of file