From c2e7713a299b6c2eefbc0104bb9194e0b4f79e26 Mon Sep 17 00:00:00 2001
From: Felix Agner <felix.agner@control.lth.se>
Date: Sat, 21 Dec 2024 12:18:54 +0100
Subject: [PATCH] added some days yo

---
 day 20/day_20_felix.cpp | 147 ++++++++++++++++++++++++++++++++++++++++
 day 21/day_21_felix.cpp | 115 +++++++++++++++++++++++++++++++
 2 files changed, 262 insertions(+)
 create mode 100644 day 20/day_20_felix.cpp
 create mode 100644 day 21/day_21_felix.cpp

diff --git a/day 20/day_20_felix.cpp b/day 20/day_20_felix.cpp
new file mode 100644
index 0000000..56cfdfa
--- /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 0000000..cb061b3
--- /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
-- 
GitLab