#include "aoc.h" #include #include namespace aoc2017 { static int radias = 12; // demo 25/2 = 12 input enum facing { f_up, f_down, f_right, f_left, }; enum virus_state { v_clean, v_weakened, v_infected, v_flaged, v_unknown, }; struct vpos { int x; int y; facing f; }; static vpos turn_right(vpos p) { facing fs[4] = {f_right, f_left, f_down, f_up}; return {p.x, p.y, fs[(int)p.f]}; } static vpos turn_left(vpos p) { facing fs[4] = {f_left, f_right, f_up, f_down}; return {p.x, p.y, fs[(int)p.f]}; } static vpos reverse(vpos p) { facing fs[4] = {f_down, f_up, f_left, f_right}; return {p.x, p.y, fs[(int)p.f]}; } static vpos move(vpos p) { vpos vs[4] = { {p.x, p.y - 1, p.f}, {p.x, p.y + 1, p.f}, {p.x + 1, p.y, p.f}, {p.x - 1, p.y, p.f}, }; return vs[(int)p.f]; } vpos burst1(std::map& infected, vpos p, int* c) { auto it = infected.find({p.x, p.y}); bool is_infected = it != infected.end(); // If the current node is infected, it turns to its right. Otherwise, it turns to its left. (Turning is done in-place; // the current node does not change.) vpos px = is_infected ? turn_right(p) : turn_left(p); // If the current node is clean, it becomes infected. Otherwise, it becomes // cleaned. (This is done after the node is considered for the purposes of changing direction.) The virus carrier if (!is_infected) { infected.insert({{p.x, p.y}, v_infected}); *c += 1; } else { infected.erase(it); } // moves forward one node in the direction it is facing. px = move(px); return px; } vpos burst2(std::map& nodes, vpos p, int* c) { // 1. Decide which way to turn based on the current node: // If it is clean, it turns left. // If it is weakened, it does not turn, and will continue moving in the same direction. // If it is infected, it turns right. // If it is flagged, it reverses direction, and will go back the way it came. auto it = nodes.find({p.x, p.y}); virus_state s{v_unknown}; if (it == nodes.end()) { s = v_clean; p = turn_left(p); } else { s = it->second; if (s == v_infected) { p = turn_right(p); } if (s == v_flaged) { p = reverse(p); } } // 2. Modify the state of the current node, as described below. // Clean nodes become weakened. // Weakened nodes become infected. // Infected nodes become flagged. // Flagged nodes become clean. if (s == v_clean) { nodes.insert({{p.x, p.y}, v_weakened}); } else { if (s == v_weakened) { *c += 1; it->second = v_infected; } if (s == v_infected) { it->second = v_flaged; } if (s == v_flaged) { nodes.erase(it); } } // 3. The virus carrier moves forward one node in the direction it is facing. p = move(p); return p; } static void load(std::map& is, int r, line_view lv) { const char* p = lv.line; int x = 0; while (*(p + x) != '\n') { if (*(p + x) == '#') { node22 n{x - radias, r - radias}; is.insert({n, v_infected}); } x++; } } static void part1(std::map nodes, int* c) { vpos p{0, 0, f_up}; for (int i = 0; i < 10000; i++) { p = burst1(nodes, p, c); } } static void part2(std::map nodes, int* c) { vpos p{0, 0, f_up}; for (int i = 0; i < 10000000; i++) { p = burst2(nodes, p, c); } } std::pair day22(line_view file) { std::map nodes; int r{0}; per_line(file, [&r, &nodes](line_view lv) { load(nodes, r++, lv); return true; }); int t0{0}, t1{0}; part1(nodes, &t0); part2(nodes, &t1); // for (auto& n : infected) { // printf("%d,%d\n", n.x, n.y); // } return {t0, t1}; } } // namespace aoc2017