diff --git a/2017/18.cpp b/2017/18.cpp index 552dafd..f1ef275 100644 --- a/2017/18.cpp +++ b/2017/18.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,7 @@ namespace { + using Name = std::string; using Value = std::int64_t; @@ -23,6 +25,10 @@ struct Literal { Value value; }; struct Variable { Name name; }; using Expression = std::variant; +struct Send { Value sent; }; +struct Receive { Value & target; }; +using Effect = std::variant; + struct Set { Name x; Expression y; }; struct Add { Name x; Expression y; }; struct Mul { Name x; Expression y; }; @@ -32,6 +38,11 @@ struct Rcv { Name x; }; struct Snd { Expression x; }; using Instruction = std::variant; +struct State { + std::map registers; + std::size_t pc; +}; + auto IsName(std::string const& word) { return std::all_of(word.begin(), word.end(), [](auto c) { return std::isalpha(c); }); } @@ -92,113 +103,140 @@ auto Parse(std::istream & in) -> std::vector { return result; } -struct Send { Value sent; }; -struct Receive { Value & target; }; -struct Halt {}; -using Effect = std::variant; +auto Eval(State const& state, Expression expression) -> Value { + return std::visit(overloaded{ + [](Literal l) -> Value { return l.value; }, + [&](Variable v) -> Value { + if (auto it = state.registers.find(v.name); it != state.registers.end()) { + return it->second; + } else { + return 0; } + }, + }, expression); +} -struct Machine { - std::vector const& program_; - std::map registers_; - std::size_t pc_; +auto Step(State & state, Instruction const& instruction) -> std::optional { + using R = std::optional; + return std::visit(overloaded{ + [&](Set instruction) -> R { state.registers[instruction.x] = Eval(state, instruction.y); state.pc++; return {}; }, + [&](Add instruction) -> R { state.registers[instruction.x] += Eval(state, instruction.y); state.pc++; return {}; }, + [&](Mul instruction) -> R { state.registers[instruction.x] *= Eval(state, instruction.y); state.pc++; return {}; }, + [&](Mod instruction) -> R { state.registers[instruction.x] %= Eval(state, instruction.y); state.pc++; return {}; }, + [&](Jgz instruction) -> R { state.pc += Eval(state, instruction.x) > 0 ? Eval(state, instruction.y) : 1; return {}; }, + [&](Snd instruction) -> R { state.pc++; return Send{Eval(state, instruction.x)}; }, + [&](Rcv instruction) -> R { state.pc++; return Receive{state.registers[instruction.x]}; }, + }, + instruction); +} -public: - Machine(std::vector const& program) - : program_{program}, registers_{}, pc_{} - {} - - auto Eval(Expression expression) -> Value { - return std::visit(overloaded{ - [](Literal l) { return l.value; }, - [&](Variable v) { return registers_[v.name]; }, - }, expression); - } - - auto Step() -> Effect { - while (pc_ < program_.size()) { - if (auto effect = std::visit(overloaded{ - [&](Set instruction) -> std::optional { registers_[instruction.x] = Eval(instruction.y); pc_++; return {}; }, - [&](Add instruction) -> std::optional { registers_[instruction.x] += Eval(instruction.y); pc_++; return {}; }, - [&](Mul instruction) -> std::optional { registers_[instruction.x] *= Eval(instruction.y); pc_++; return {}; }, - [&](Mod instruction) -> std::optional { registers_[instruction.x] %= Eval(instruction.y); pc_++; return {}; }, - [&](Jgz instruction) -> std::optional { pc_ += Eval(instruction.x) > 0 ? Eval(instruction.y) : 1; return {}; }, - [&](Snd instruction) -> std::optional { pc_++; return Send{Eval(instruction.x)}; }, - [&](Rcv instruction) -> std::optional { pc_++; return Receive{registers_[instruction.x]}; }, - }, - program_[pc_])) - { - return *effect; - } +auto BigStep(State & state, std::vector const& program) -> Effect { + while(state.pc < program.size()) { + if (auto effect = Step(state, program[state.pc])) { + return *effect; } - return Halt{}; } -}; + throw std::runtime_error{"program crash"}; +} auto Part1(std::vector const& program) -> Value { Value last_sound = -1; - Machine m { program }; + State state {}; - for(;;) { - auto effect = m.Step(); + for (;;) { + auto effect = BigStep(state, program); switch (effect.index()) { case 0: last_sound = std::get<0>(effect).sent; break; case 1: if (std::get<1>(effect).target > 0) { return last_sound; } break; - default: throw std::runtime_error{"program halted"}; } } + + throw std::runtime_error{"part 1 failed"}; } -auto Spin(Machine & m, std::deque & input, std::deque & output) -> Value* { +auto Spin( + State & state, + std::vector const& program, + std::deque & input, + std::deque & output +) -> std::pair +{ + std::size_t n = 0; for(;;) { - auto effect = m.Step(); + auto effect = BigStep(state, program); switch (effect.index()) { - case 0: output.push_back(std::get<0>(effect).sent); break; + case 0: + output.push_back(std::get<0>(effect).sent); + n++; + break; case 1: { auto & target = std::get<1>(effect).target; if (input.empty()) { - return ⌖ + return {&target, n}; } else { target = input.front(); input.pop_front(); } break; } - default: throw std::runtime_error{"program halted"}; } } } auto Part2(std::vector const& program) -> std::size_t { - Machine m0 { program }; - Machine m1 { program }; - m1.registers_["p"] = 1; + State m0{}; + State m1{{{"p",1}}}; std::deque inputs0; std::deque inputs1; - auto stuck0 = Spin(m0, inputs0, inputs1); - auto stuck1 = Spin(m1, inputs1, inputs0); - - std::size_t result = inputs0.size(); + auto [stuck0, _] = Spin(m0, program, inputs0, inputs1); + auto [stuck1, n] = Spin(m1, program, inputs1, inputs0); while(!(inputs0.empty() && inputs1.empty())) { if (!inputs0.empty()) { *stuck0 = inputs0.front(); inputs0.pop_front(); - stuck0 = Spin(m0, inputs0, inputs1); + stuck0 = Spin(m0, program, inputs0, inputs1).first; } if (!inputs1.empty()) { *stuck1 = inputs1.front(); inputs1.pop_front(); - result -= inputs0.size(); - stuck1 = Spin(m1, inputs1, inputs0); - result += inputs0.size(); + auto res = Spin(m1, program, inputs1, inputs0); + stuck1 = res.first; + n += res.second; } } - - return result; + return n; } } // namespace +TEST_SUITE("documented examples") { + TEST_CASE("part 1") { + std::istringstream in { + "set a 1\n" + "add a 2\n" + "mul a a\n" + "mod a 5\n" + "snd a\n" + "set a 0\n" + "rcv a\n" + "jgz a -1\n" + "set a 1\n" + "jgz a -2\n"}; + REQUIRE(Part1(Parse(in)) == 4); + } + TEST_CASE("part 2") { + std::istringstream in { + "snd 1\n" + "snd 2\n" + "snd p\n" + "rcv a\n" + "rcv b\n" + "rcv c\n" + "rcv d\n"}; + REQUIRE(Part2(Parse(in)) == 3); + } +} + auto main(int argc, char** argv) -> int { auto program = Parse(aocpp::Startup(argc, argv)); std::cout << "Part 1: " << Part1(program) << std::endl; diff --git a/2019/CMakeLists.txt b/2019/CMakeLists.txt index 22f112d..37f9932 100644 --- a/2019/CMakeLists.txt +++ b/2019/CMakeLists.txt @@ -1,74 +1,74 @@ -add_executable(01 01.cpp) -target_link_libraries(01 aocpp) +add_executable(2019_01 01.cpp) +target_link_libraries(2019_01 aocpp) -add_executable(02 02.cpp) -target_link_libraries(02 aocpp intcode) +add_executable(2019_02 02.cpp) +target_link_libraries(2019_02 aocpp intcode) -add_executable(03 03.cpp) -target_link_libraries(03 aocpp) +add_executable(2019_03 03.cpp) +target_link_libraries(2019_03 aocpp) -add_executable(04 04.cpp) -target_link_libraries(04 aocpp) +add_executable(2019_04 04.cpp) +target_link_libraries(2019_04 aocpp) -add_executable(05 05.cpp) -target_link_libraries(05 aocpp intcode) +add_executable(2019_05 05.cpp) +target_link_libraries(2019_05 aocpp intcode) -add_executable(06 06.cpp) -target_link_libraries(06 aocpp) +add_executable(2019_06 06.cpp) +target_link_libraries(2019_06 aocpp) -add_executable(07 07.cpp) -target_link_libraries(07 aocpp intcode) +add_executable(2019_07 07.cpp) +target_link_libraries(2019_07 aocpp intcode) -add_executable(08 08.cpp) -target_link_libraries(08 aocpp) +add_executable(2019_08 08.cpp) +target_link_libraries(2019_08 aocpp) -add_executable(09 09.cpp) -target_link_libraries(09 aocpp intcode) +add_executable(2019_09 09.cpp) +target_link_libraries(2019_09 aocpp intcode) -add_executable(10 10.cpp) -target_link_libraries(10 aocpp) +add_executable(2019_10 10.cpp) +target_link_libraries(2019_10 aocpp) -add_executable(11 11.cpp) -target_link_libraries(11 aocpp intcode) +add_executable(2019_11 11.cpp) +target_link_libraries(2019_11 aocpp intcode) -add_executable(12 12.cpp) -target_link_libraries(12 aocpp) +add_executable(2019_12 12.cpp) +target_link_libraries(2019_12 aocpp) -add_executable(13 13.cpp) -target_link_libraries(13 aocpp intcode) +add_executable(2019_13 13.cpp) +target_link_libraries(2019_13 aocpp intcode) -add_executable(14 14.cpp) -target_link_libraries(14 aocpp) +add_executable(2019_14 14.cpp) +target_link_libraries(2019_14 aocpp) -add_executable(15 15.cpp) -target_link_libraries(15 aocpp intcode) +add_executable(2019_15 15.cpp) +target_link_libraries(2019_15 aocpp intcode) -add_executable(16 16.cpp) -target_link_libraries(16 aocpp) +add_executable(2019_16 16.cpp) +target_link_libraries(2019_16 aocpp) -add_executable(17 17.cpp) -target_link_libraries(17 aocpp intcode) +add_executable(2019_17 17.cpp) +target_link_libraries(2019_17 aocpp intcode) -add_executable(18 18.cpp) -target_link_libraries(18 aocpp) +add_executable(2019_18 18.cpp) +target_link_libraries(2019_18 aocpp) -add_executable(19 19.cpp) -target_link_libraries(19 aocpp intcode) +add_executable(2019_19 19.cpp) +target_link_libraries(2019_19 aocpp intcode) -add_executable(20 20.cpp) -target_link_libraries(20 aocpp) +add_executable(2019_20 20.cpp) +target_link_libraries(2019_20 aocpp) -add_executable(21 21.cpp) -target_link_libraries(21 aocpp intcode) +add_executable(2019_21 21.cpp) +target_link_libraries(2019_21 aocpp intcode) -add_executable(22 22.cpp) -target_link_libraries(22 aocpp zmod) +add_executable(2019_22 22.cpp) +target_link_libraries(2019_22 aocpp zmod) -add_executable(23 23.cpp) -target_link_libraries(23 aocpp intcode) +add_executable(2019_23 23.cpp) +target_link_libraries(2019_23 aocpp intcode) -add_executable(24 24.cpp) -target_link_libraries(24 aocpp) +add_executable(2019_24 24.cpp) +target_link_libraries(2019_24 aocpp) -add_executable(25 25.cpp) -target_link_libraries(25 aocpp intcode) +add_executable(2019_25 25.cpp) +target_link_libraries(2019_25 aocpp intcode) diff --git a/2020/01.cpp b/2020/01.cpp new file mode 100644 index 0000000..dfc9dac --- /dev/null +++ b/2020/01.cpp @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace { + +auto Parse(std::istream & in) -> std::vector +{ + std::vector result; + std::int64_t x; + while (in >> x) { + result.push_back(x); + } + return result; +} + +auto Part1(std::vector entries) { + std::bitset<2020> numbers; + std::sort(entries.begin(), entries.end()); + for (auto const i : entries) { + if (i >= 2020) { + break; + } + numbers.set(i); + } + for (auto const i : entries) { + if (numbers.test(2020 - i)) { + return (2020 - i) * i; + } + } + throw std::runtime_error{"no part 1 solution"}; +} + +auto Part2(std::vector entries) { + std::bitset<2020> numbers; + std::sort(entries.begin(), entries.end()); + for (auto const i : entries) { + if (i >= 2020) { break; } + if (i < 2020) { numbers.set(i); } + } + + for (auto it1 = entries.begin(); it1 != entries.end(); it1++) { + for (auto it2 = std::next(it1); it2 != entries.end(); it2++) { + auto target = 2020 - (*it1) - (*it2); + if (target < 0) break; + if (target < 2020 && numbers.test(target)) { return target * *it1 * *it2;} + } + } + throw std::runtime_error{"no part 2 solution"}; +} + +} + +TEST_SUITE("documented examples") { + std::istringstream in { + "1721\n" + "979\n" + "366\n" + "299\n" + "675\n" + "1456\n"}; + auto entries = Parse(in); + +TEST_CASE("part 1") { + REQUIRE(Part1(entries) == 514579); +} + +TEST_CASE("part 2") { + REQUIRE(Part2(entries) == 241861950); +} + +} + +auto main(int argc, char** argv) -> int { + auto entries = Parse(aocpp::Startup(argc, argv)); + std::cout << "Part 1: " << Part1(entries) << std::endl; + std::cout << "Part 2: " << Part2(entries) << std::endl; +} diff --git a/2020/CMakeLists.txt b/2020/CMakeLists.txt new file mode 100644 index 0000000..93f0586 --- /dev/null +++ b/2020/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(2020_01 01.cpp) +target_link_libraries(2020_01 aocpp) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a94da1..16016d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,3 +22,4 @@ add_subdirectory(zmod) add_subdirectory(intcode) add_subdirectory(2017) add_subdirectory(2019) +add_subdirectory(2020) diff --git a/CMakePresets.json b/CMakePresets.json index 155daee..3571f09 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -8,7 +8,7 @@ "generator": "Ninja", "binaryDir": "${sourceDir}/out/build/${presetName}", "cacheVariables": { - "CMAKE_BUILD_TYPE": "RelWithDebInfo", + "CMAKE_BUILD_TYPE": "Debug", "CMAKE_TOOLCHAIN_FILE": "", "CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}" }