diff --git a/day 20/day_20_felix.cpp b/day 20/day_20_felix.cpp index 56cfdfadc4cc1ef6c4cbd3074b987a7f66739fa0..02b8c1b8501c4fe4dbf804f870651658c8aef9c4 100644 --- a/day 20/day_20_felix.cpp +++ b/day 20/day_20_felix.cpp @@ -21,8 +21,7 @@ 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; +vector <coord> FORWARD_PATH; void parse_input() { string line; @@ -55,70 +54,60 @@ void parse_input() { } bool in_bounds(coord u) { - return u.first >= 0 && u.first < M && u.second >= 0 && u.second < N; + bool in = u.first >= 0 && u.first < M && u.second >= 0 && u.second < N; + return in && !IS_WALL[u.first][u.second]; } -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; +coord move(coord u, char d) { + if (d == 'N') return {u.first - 1, u.second}; + if (d == 'S') return {u.first + 1, u.second}; + if (d == 'W') return {u.first, u.second - 1}; + if (d == 'E') return {u.first, u.second + 1}; + return {-1, -1}; } -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}); - - } - } +coord next(coord u, array<array<bool, 145>, 145> &visited) { + coord n = move(u, 'N'); + if (in_bounds(n) && !visited[n.first][n.second]) return n; + n = move(u, 'S'); + if (in_bounds(n) && !visited[n.first][n.second]) return n; + n = move(u, 'W'); + if (in_bounds(n) && !visited[n.first][n.second]) return n; + n = move(u, 'E'); + if (in_bounds(n) && !visited[n.first][n.second]) return n; + return {-1, -1}; +} - return nlist; +int dist(coord u, coord v) { + return abs(u.first - v.first) + abs(u.second - v.second); } +vector<coord> bfs(coord start) { -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; + vector<coord> path = {start}; + coord curr = next(start, visited); - 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; - } + while (curr != END) { + visited[curr.first][curr.second] = true; + path.push_back(curr); + curr = next(curr, visited); } + path.push_back(END); - return costs; + return path; } -ll n_cheats(int cheat_distance, ll baseline) { +ll n_cheats(int cheat_distance, int improvement_goal) { 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++; - } + for (int i = 0; i < FORWARD_PATH.size() - improvement_goal; i++) { + for (int j = i + improvement_goal; j < FORWARD_PATH.size(); j++) { + int d = dist(FORWARD_PATH[i], FORWARD_PATH[j]); + if (d > cheat_distance) j += max(d - cheat_distance-1, 0); + else if (j - i - d >= improvement_goal) n_cheats++; } } return n_cheats; @@ -127,20 +116,19 @@ ll n_cheats(int cheat_distance, ll baseline) { int main (int argc, char* argv[]) { for (int i = 0; i < argc; i++) if (string(argv[i]) == "-d") DEBUG = true; + if (DEBUG) cout << "Reading data..." << endl; parse_input(); - - TO_COME = bfs(START); - TO_GO = bfs(END); - ll baseline = TO_COME[END]; + FORWARD_PATH = bfs(START); + if (DEBUG) cout << "Data read." << endl; if (DEBUG) { - cout << "Baseline: " << baseline << endl; + cout << "Baseline: " << FORWARD_PATH.size() << endl; } - ll part1 = n_cheats(2, baseline - 100); + ll part1 = n_cheats(2, 100); cout << "Part 1: " << part1 << endl; - ll part2 = n_cheats(20, baseline - 100); + ll part2 = n_cheats(20, 100); cout << "Part 2: " << part2 << endl; return 0;