diff --git a/day02.cpp b/day02.cpp index 2156151..ee0effc 100644 --- a/day02.cpp +++ b/day02.cpp @@ -10,7 +10,7 @@ namespace { auto Compute(Machine machine, ValueType x, ValueType y) { machine.At(1) = x; machine.At(2) = y; - machine.Step(); + Step(machine); return machine.At(0); } diff --git a/day05.cpp b/day05.cpp index d79dad9..4e3b4af 100644 --- a/day05.cpp +++ b/day05.cpp @@ -18,7 +18,7 @@ auto Compute(Machine machine, ValueType d) -> ValueType { last_output = arg.val; return true; }}, - machine.Step())); + Step(machine))); return last_output; } diff --git a/day07.cpp b/day07.cpp index fae588c..06162a3 100644 --- a/day07.cpp +++ b/day07.cpp @@ -14,7 +14,7 @@ template auto Controller(Machine machine, R const ¶ms) { std::vector amps; for (auto p : params) { auto m = machine; - std::get(m.Step()).pos = p; + std::get(Step(m)).pos = p; amps.push_back(std::move(m)); } return amps; @@ -23,10 +23,10 @@ template auto Controller(Machine machine, R const ¶ms) { template auto Feed(R &&s, ValueType start) -> std::optional { for (auto &m : amps) { - auto i = m.Step(); + auto i = Step(m); if (auto p = std::get_if(&i)) { p->pos = start; - start = std::get(m.Step()).val; + start = std::get(Step(m)).val; } else { return {}; } diff --git a/day09.cpp b/day09.cpp index bcdc80b..8570af3 100644 --- a/day09.cpp +++ b/day09.cpp @@ -18,7 +18,7 @@ auto Compute(Machine machine, ValueType d) -> ValueType { output = arg.val; return false; }}, - machine.Step())); + Step(machine))); return output; } diff --git a/day11.cpp b/day11.cpp index 6d775ae..137f6dd 100644 --- a/day11.cpp +++ b/day11.cpp @@ -19,15 +19,15 @@ auto Compute(Machine machine, ValueType start) ValueType dy {-1}; for (;;) { - auto effect = machine.Step(); + auto effect = Step(machine); if (std::holds_alternative(effect)) { return paint; } std::get(effect).pos = paint[here]; - paint[here] = std::get(machine.Step()).val; - auto dir = std::get(machine.Step()).val; + paint[here] = std::get(Step(machine)).val; + auto dir = std::get(Step(machine)).val; std::swap(dx, dy); if (dir) { diff --git a/day13.cpp b/day13.cpp index 0bb37e3..a16201a 100644 --- a/day13.cpp +++ b/day13.cpp @@ -15,13 +15,13 @@ auto Compute1(Machine machine) std::set screen; for (;;) { - auto effect = machine.Step(); + auto effect = Step(machine); if (std::holds_alternative(effect)) { return screen.size(); } auto x = std::get(effect).val; - auto y = std::get(machine.Step()).val; - auto v = std::get(machine.Step()).val; + auto y = std::get(Step(machine)).val; + auto v = std::get(Step(machine)).val; if (2 == v) { screen.insert({x,y}); } else { screen.erase({x,y}); } } @@ -34,7 +34,7 @@ auto Compute2(Machine machine) { machine.At(0) = 2; for(;;) { - auto effect = machine.Step(); + auto effect = Step(machine); if (std::holds_alternative(effect)) { return score; } else if (auto i = std::get_if(&effect)) { @@ -42,8 +42,8 @@ auto Compute2(Machine machine) { : paddleX > ballX ? -1 : 0; } else { auto x = std::get(effect).val; - auto y = std::get(machine.Step()).val; - auto v = std::get(machine.Step()).val; + auto y = std::get(Step(machine)).val; + auto v = std::get(Step(machine)).val; if (-1 == x && 0 == y) { score = v; diff --git a/day15.cpp b/day15.cpp index b49d479..a351318 100644 --- a/day15.cpp +++ b/day15.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include using namespace intcode; @@ -13,46 +14,65 @@ namespace { using Coord = std::pair; auto Compute(Machine machine) -> std::pair { - int part1 = 0; - int part2 = 0; - Coord here {0,0}; - std::map world; + std::map world {{{0,0},1}}; - std::deque> todo {{0, {0,0}, std::move(machine)}}; + using State = std::tuple; - auto action = [&world, &todo](Machine m, int steps, ValueType cmd, Coord coord) { + std::vector layer {{{0,0}, std::move(machine)}}; + std::vector next_layer; + + auto action = [&](Machine m, ValueType cmd, Coord coord) { if (!world.contains(coord)) { - std::get(m.Step()).pos = cmd; - auto o = std::get(m.Step()).val; + std::get(Step(m)).pos = cmd; + auto o = std::get(Step(m)).val; world[coord] = o; if (o) { - todo.emplace_back(steps + 1, coord, std::move(m)); + next_layer.emplace_back(coord, std::move(m)); } } }; - while (!todo.empty()) { - auto [steps, here, machine] = todo.front(); - auto [x,y] = here; - todo.pop_front(); - - if (2 == world[here]) { - part1 = steps; - todo.clear(); - world.clear(); - world[here] = 2; - steps = 0; - part2 = 0; + int part1 = 0; + while (!layer.empty()) { + for (auto && s : layer) { + auto& [loc, m] = s; + if (2 == world[loc]) { + world.clear(); + world[loc] = 2; + auto start = std::move(m); + layer.clear(); + layer.push_back({loc, std::move(start)}); + goto loop2; + } + auto [x,y] = loc; + action(m, 1, {x,y-1}); + action(m, 2, {x,y+1}); + action(m, 3, {x-1,y}); + action(std::move(m), 4, {x+1,y}); } - part2 = std::max(part2, steps); - - action(machine, steps, 1, {x,y-1}); - action(machine, steps, 2, {x,y+1}); - action(machine, steps, 3, {x-1,y}); - action(std::move(machine), steps, 4, {x+1,y}); + layer = std::move(next_layer); + next_layer.clear(); + part1++; } - return {part1,part2}; + + +loop2: + int part2 = 0; + while (!layer.empty()) { + for (auto && s : layer) { + auto& [loc, m] = s; + auto [x,y] = loc; + action(m, 1, {x,y-1}); + action(m, 2, {x,y+1}); + action(m, 3, {x-1,y}); + action(std::move(m), 4, {x+1,y}); + } + layer = std::move(next_layer); + next_layer.clear(); + part2++; + } + return {part1, part2-1}; } } // namespace diff --git a/lib/include/intcode.hpp b/lib/include/intcode.hpp index 1e12e95..a78dd7f 100644 --- a/lib/include/intcode.hpp +++ b/lib/include/intcode.hpp @@ -36,9 +36,6 @@ public: Machine(); explicit Machine(std::vector ram); - /// Advance machine until next side effect - auto Step() -> std::variant; - /// Access memory at absolute address /// @param address /// @return reference to memory at given address @@ -48,8 +45,14 @@ public: /// @param offset from base pointer /// @return reference to memory at given offset auto Rel(std::size_t offset) -> ValueType &; + + auto Next() -> ValueType &; + auto Goto(std::size_t address) -> void; + auto Rebase(std::size_t offset) -> void; }; +auto Step(Machine & m) -> std::variant; + struct BadInstruction : public std::runtime_error { explicit BadInstruction(char const* what); }; diff --git a/lib/intcode.cpp b/lib/intcode.cpp index d2bc5a4..00e1c2b 100644 --- a/lib/intcode.cpp +++ b/lib/intcode.cpp @@ -11,23 +11,6 @@ Machine::Machine() : rom_{}, ram_{}, pc_{0}, base_{0} {} Machine::Machine(std::vector ram) : rom_{ram}, ram_{}, pc_{0}, base_{0} {} -namespace { -auto Ref(Machine & m, ValueType instruction, std::size_t k, ValueType p) - -> ValueType & { - auto &v = m.At(k); - switch (instruction / p % 10) { - case 0: - return m.At(v); - case 1: - return v; - case 2: - return m.Rel(v); - default: - throw BadInstruction{"invalid addressing mode"}; - } -} -} - auto Machine::At(std::size_t i) -> ValueType & { return i < rom_.size() ? rom_[i] : ram_[i]; } @@ -36,57 +19,95 @@ auto Machine::Rel(std::size_t i) -> ValueType & { return At(base_ + i); } -auto Machine::Step() -> std::variant { +auto Machine::Rebase(std::size_t offset) -> void { + base_ += offset; +} + + +auto Machine::Next() -> ValueType & { + return At(pc_++); +} + +auto Machine::Goto(std::size_t address) -> void { + pc_ = address; +} + +auto Step(Machine & m) -> std::variant { for (;;) { - auto instruction = At(pc_); - auto a = [=]() -> auto & { return Ref(*this, instruction, pc_+1, 100); }; - auto b = [=]() -> auto & { return Ref(*this, instruction, pc_+2, 1000); }; - auto c = [=]() -> auto & { return Ref(*this, instruction, pc_+3, 10000); }; + auto instruction = m.Next(); + auto modes = instruction / 10; + + auto arg = [&]() -> ValueType & { + auto &v = m.Next(); + switch ((modes /= 10) % 10) { + case 0: + return m.At(v); + case 1: + return v; + case 2: + return m.Rel(v); + default: + throw BadInstruction{"invalid addressing mode"}; + } + }; switch (instruction % 100) { - case 1: - c() = a() + b(); - pc_ += 4; + case 1: { + auto a = arg(); + auto b = arg(); + auto& c = arg(); + c = a + b; break; + } - case 2: - c() = a() * b(); - pc_ += 4; + case 2: { + auto a = arg(); + auto b = arg(); + auto& c = arg(); + c = a * b; break; + } case 3: { - auto &pos = a(); - pc_ += 2; - return Input{pos}; + return Input{arg()}; } case 4: { - auto val = a(); - pc_ += 2; - return Output{val}; + return Output{arg()}; } - case 5: - pc_ = a() ? b() : pc_ + 3; + case 5: { + auto a = arg(); + auto b = arg(); + if (a) { m.Goto(b); } break; + } - case 6: - pc_ = a() ? pc_ + 3 : b(); + case 6: { + auto a = arg(); + auto b = arg(); + if (!a) { m.Goto(b); } break; + } - case 7: - c() = a() < b(); - pc_ += 4; + case 7: { + auto a = arg(); + auto b = arg(); + auto& c = arg(); + c = a < b; break; + } - case 8: - c() = a() == b(); - pc_ += 4; + case 8: { + auto a = arg(); + auto b = arg(); + auto& c = arg(); + c = a == b; break; + } case 9: - base_ += a(); - pc_ += 2; + m.Rebase(arg()); break; case 99: