2020-01
This commit is contained in:
parent
8f772d85b2
commit
c6879b4359
154
2017/18.cpp
154
2017/18.cpp
|
@ -3,6 +3,7 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
@ -16,6 +17,7 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
|
||||||
using Name = std::string;
|
using Name = std::string;
|
||||||
using Value = std::int64_t;
|
using Value = std::int64_t;
|
||||||
|
|
||||||
|
@ -23,6 +25,10 @@ struct Literal { Value value; };
|
||||||
struct Variable { Name name; };
|
struct Variable { Name name; };
|
||||||
using Expression = std::variant<Literal, Variable>;
|
using Expression = std::variant<Literal, Variable>;
|
||||||
|
|
||||||
|
struct Send { Value sent; };
|
||||||
|
struct Receive { Value & target; };
|
||||||
|
using Effect = std::variant<Send, Receive>;
|
||||||
|
|
||||||
struct Set { Name x; Expression y; };
|
struct Set { Name x; Expression y; };
|
||||||
struct Add { Name x; Expression y; };
|
struct Add { Name x; Expression y; };
|
||||||
struct Mul { Name x; Expression y; };
|
struct Mul { Name x; Expression y; };
|
||||||
|
@ -32,6 +38,11 @@ struct Rcv { Name x; };
|
||||||
struct Snd { Expression x; };
|
struct Snd { Expression x; };
|
||||||
using Instruction = std::variant<Set, Add, Mul, Mod, Jgz, Rcv, Snd>;
|
using Instruction = std::variant<Set, Add, Mul, Mod, Jgz, Rcv, Snd>;
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
std::map<Name, Value> registers;
|
||||||
|
std::size_t pc;
|
||||||
|
};
|
||||||
|
|
||||||
auto IsName(std::string const& word) {
|
auto IsName(std::string const& word) {
|
||||||
return std::all_of(word.begin(), word.end(), [](auto c) { return std::isalpha(c); });
|
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<Instruction> {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Send { Value sent; };
|
auto Eval(State const& state, Expression expression) -> Value {
|
||||||
struct Receive { Value & target; };
|
|
||||||
struct Halt {};
|
|
||||||
using Effect = std::variant<Send, Receive, Halt>;
|
|
||||||
|
|
||||||
struct Machine {
|
|
||||||
std::vector<Instruction> const& program_;
|
|
||||||
std::map<Name, Value> registers_;
|
|
||||||
std::size_t pc_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Machine(std::vector<Instruction> const& program)
|
|
||||||
: program_{program}, registers_{}, pc_{}
|
|
||||||
{}
|
|
||||||
|
|
||||||
auto Eval(Expression expression) -> Value {
|
|
||||||
return std::visit(overloaded{
|
return std::visit(overloaded{
|
||||||
[](Literal l) { return l.value; },
|
[](Literal l) -> Value { return l.value; },
|
||||||
[&](Variable v) { return registers_[v.name]; },
|
[&](Variable v) -> Value {
|
||||||
}, expression);
|
if (auto it = state.registers.find(v.name); it != state.registers.end()) {
|
||||||
}
|
return it->second;
|
||||||
|
} else {
|
||||||
auto Step() -> Effect {
|
return 0; }
|
||||||
while (pc_ < program_.size()) {
|
|
||||||
if (auto effect = std::visit(overloaded{
|
|
||||||
[&](Set instruction) -> std::optional<Effect> { registers_[instruction.x] = Eval(instruction.y); pc_++; return {}; },
|
|
||||||
[&](Add instruction) -> std::optional<Effect> { registers_[instruction.x] += Eval(instruction.y); pc_++; return {}; },
|
|
||||||
[&](Mul instruction) -> std::optional<Effect> { registers_[instruction.x] *= Eval(instruction.y); pc_++; return {}; },
|
|
||||||
[&](Mod instruction) -> std::optional<Effect> { registers_[instruction.x] %= Eval(instruction.y); pc_++; return {}; },
|
|
||||||
[&](Jgz instruction) -> std::optional<Effect> { pc_ += Eval(instruction.x) > 0 ? Eval(instruction.y) : 1; return {}; },
|
|
||||||
[&](Snd instruction) -> std::optional<Effect> { pc_++; return Send{Eval(instruction.x)}; },
|
|
||||||
[&](Rcv instruction) -> std::optional<Effect> { pc_++; return Receive{registers_[instruction.x]}; },
|
|
||||||
},
|
},
|
||||||
program_[pc_]))
|
}, expression);
|
||||||
{
|
}
|
||||||
|
|
||||||
|
auto Step(State & state, Instruction const& instruction) -> std::optional<Effect> {
|
||||||
|
using R = std::optional<Effect>;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto BigStep(State & state, std::vector<Instruction> const& program) -> Effect {
|
||||||
|
while(state.pc < program.size()) {
|
||||||
|
if (auto effect = Step(state, program[state.pc])) {
|
||||||
return *effect;
|
return *effect;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Halt{};
|
throw std::runtime_error{"program crash"};
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
auto Part1(std::vector<Instruction> const& program) -> Value {
|
auto Part1(std::vector<Instruction> const& program) -> Value {
|
||||||
Value last_sound = -1;
|
Value last_sound = -1;
|
||||||
Machine m { program };
|
State state {};
|
||||||
|
|
||||||
for(;;) {
|
for (;;) {
|
||||||
auto effect = m.Step();
|
auto effect = BigStep(state, program);
|
||||||
switch (effect.index()) {
|
switch (effect.index()) {
|
||||||
case 0: last_sound = std::get<0>(effect).sent; break;
|
case 0: last_sound = std::get<0>(effect).sent; break;
|
||||||
case 1: if (std::get<1>(effect).target > 0) { return last_sound; } 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<Value> & input, std::deque<Value> & output) -> Value* {
|
auto Spin(
|
||||||
|
State & state,
|
||||||
|
std::vector<Instruction> const& program,
|
||||||
|
std::deque<Value> & input,
|
||||||
|
std::deque<Value> & output
|
||||||
|
) -> std::pair<Value*, std::size_t>
|
||||||
|
{
|
||||||
|
std::size_t n = 0;
|
||||||
for(;;) {
|
for(;;) {
|
||||||
auto effect = m.Step();
|
auto effect = BigStep(state, program);
|
||||||
switch (effect.index()) {
|
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: {
|
case 1: {
|
||||||
auto & target = std::get<1>(effect).target;
|
auto & target = std::get<1>(effect).target;
|
||||||
if (input.empty()) {
|
if (input.empty()) {
|
||||||
return ⌖
|
return {&target, n};
|
||||||
} else {
|
} else {
|
||||||
target = input.front();
|
target = input.front();
|
||||||
input.pop_front();
|
input.pop_front();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: throw std::runtime_error{"program halted"};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Part2(std::vector<Instruction> const& program) -> std::size_t {
|
auto Part2(std::vector<Instruction> const& program) -> std::size_t {
|
||||||
Machine m0 { program };
|
State m0{};
|
||||||
Machine m1 { program };
|
State m1{{{"p",1}}};
|
||||||
m1.registers_["p"] = 1;
|
|
||||||
|
|
||||||
std::deque<Value> inputs0;
|
std::deque<Value> inputs0;
|
||||||
std::deque<Value> inputs1;
|
std::deque<Value> inputs1;
|
||||||
|
|
||||||
auto stuck0 = Spin(m0, inputs0, inputs1);
|
auto [stuck0, _] = Spin(m0, program, inputs0, inputs1);
|
||||||
auto stuck1 = Spin(m1, inputs1, inputs0);
|
auto [stuck1, n] = Spin(m1, program, inputs1, inputs0);
|
||||||
|
|
||||||
std::size_t result = inputs0.size();
|
|
||||||
|
|
||||||
while(!(inputs0.empty() && inputs1.empty())) {
|
while(!(inputs0.empty() && inputs1.empty())) {
|
||||||
if (!inputs0.empty()) {
|
if (!inputs0.empty()) {
|
||||||
*stuck0 = inputs0.front(); inputs0.pop_front();
|
*stuck0 = inputs0.front(); inputs0.pop_front();
|
||||||
stuck0 = Spin(m0, inputs0, inputs1);
|
stuck0 = Spin(m0, program, inputs0, inputs1).first;
|
||||||
}
|
}
|
||||||
if (!inputs1.empty()) {
|
if (!inputs1.empty()) {
|
||||||
*stuck1 = inputs1.front(); inputs1.pop_front();
|
*stuck1 = inputs1.front(); inputs1.pop_front();
|
||||||
result -= inputs0.size();
|
auto res = Spin(m1, program, inputs1, inputs0);
|
||||||
stuck1 = Spin(m1, inputs1, inputs0);
|
stuck1 = res.first;
|
||||||
result += inputs0.size();
|
n += res.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return n;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // 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 main(int argc, char** argv) -> int {
|
||||||
auto program = Parse(aocpp::Startup(argc, argv));
|
auto program = Parse(aocpp::Startup(argc, argv));
|
||||||
std::cout << "Part 1: " << Part1(program) << std::endl;
|
std::cout << "Part 1: " << Part1(program) << std::endl;
|
||||||
|
|
|
@ -1,74 +1,74 @@
|
||||||
add_executable(01 01.cpp)
|
add_executable(2019_01 01.cpp)
|
||||||
target_link_libraries(01 aocpp)
|
target_link_libraries(2019_01 aocpp)
|
||||||
|
|
||||||
add_executable(02 02.cpp)
|
add_executable(2019_02 02.cpp)
|
||||||
target_link_libraries(02 aocpp intcode)
|
target_link_libraries(2019_02 aocpp intcode)
|
||||||
|
|
||||||
add_executable(03 03.cpp)
|
add_executable(2019_03 03.cpp)
|
||||||
target_link_libraries(03 aocpp)
|
target_link_libraries(2019_03 aocpp)
|
||||||
|
|
||||||
add_executable(04 04.cpp)
|
add_executable(2019_04 04.cpp)
|
||||||
target_link_libraries(04 aocpp)
|
target_link_libraries(2019_04 aocpp)
|
||||||
|
|
||||||
add_executable(05 05.cpp)
|
add_executable(2019_05 05.cpp)
|
||||||
target_link_libraries(05 aocpp intcode)
|
target_link_libraries(2019_05 aocpp intcode)
|
||||||
|
|
||||||
add_executable(06 06.cpp)
|
add_executable(2019_06 06.cpp)
|
||||||
target_link_libraries(06 aocpp)
|
target_link_libraries(2019_06 aocpp)
|
||||||
|
|
||||||
add_executable(07 07.cpp)
|
add_executable(2019_07 07.cpp)
|
||||||
target_link_libraries(07 aocpp intcode)
|
target_link_libraries(2019_07 aocpp intcode)
|
||||||
|
|
||||||
add_executable(08 08.cpp)
|
add_executable(2019_08 08.cpp)
|
||||||
target_link_libraries(08 aocpp)
|
target_link_libraries(2019_08 aocpp)
|
||||||
|
|
||||||
add_executable(09 09.cpp)
|
add_executable(2019_09 09.cpp)
|
||||||
target_link_libraries(09 aocpp intcode)
|
target_link_libraries(2019_09 aocpp intcode)
|
||||||
|
|
||||||
add_executable(10 10.cpp)
|
add_executable(2019_10 10.cpp)
|
||||||
target_link_libraries(10 aocpp)
|
target_link_libraries(2019_10 aocpp)
|
||||||
|
|
||||||
add_executable(11 11.cpp)
|
add_executable(2019_11 11.cpp)
|
||||||
target_link_libraries(11 aocpp intcode)
|
target_link_libraries(2019_11 aocpp intcode)
|
||||||
|
|
||||||
add_executable(12 12.cpp)
|
add_executable(2019_12 12.cpp)
|
||||||
target_link_libraries(12 aocpp)
|
target_link_libraries(2019_12 aocpp)
|
||||||
|
|
||||||
add_executable(13 13.cpp)
|
add_executable(2019_13 13.cpp)
|
||||||
target_link_libraries(13 aocpp intcode)
|
target_link_libraries(2019_13 aocpp intcode)
|
||||||
|
|
||||||
add_executable(14 14.cpp)
|
add_executable(2019_14 14.cpp)
|
||||||
target_link_libraries(14 aocpp)
|
target_link_libraries(2019_14 aocpp)
|
||||||
|
|
||||||
add_executable(15 15.cpp)
|
add_executable(2019_15 15.cpp)
|
||||||
target_link_libraries(15 aocpp intcode)
|
target_link_libraries(2019_15 aocpp intcode)
|
||||||
|
|
||||||
add_executable(16 16.cpp)
|
add_executable(2019_16 16.cpp)
|
||||||
target_link_libraries(16 aocpp)
|
target_link_libraries(2019_16 aocpp)
|
||||||
|
|
||||||
add_executable(17 17.cpp)
|
add_executable(2019_17 17.cpp)
|
||||||
target_link_libraries(17 aocpp intcode)
|
target_link_libraries(2019_17 aocpp intcode)
|
||||||
|
|
||||||
add_executable(18 18.cpp)
|
add_executable(2019_18 18.cpp)
|
||||||
target_link_libraries(18 aocpp)
|
target_link_libraries(2019_18 aocpp)
|
||||||
|
|
||||||
add_executable(19 19.cpp)
|
add_executable(2019_19 19.cpp)
|
||||||
target_link_libraries(19 aocpp intcode)
|
target_link_libraries(2019_19 aocpp intcode)
|
||||||
|
|
||||||
add_executable(20 20.cpp)
|
add_executable(2019_20 20.cpp)
|
||||||
target_link_libraries(20 aocpp)
|
target_link_libraries(2019_20 aocpp)
|
||||||
|
|
||||||
add_executable(21 21.cpp)
|
add_executable(2019_21 21.cpp)
|
||||||
target_link_libraries(21 aocpp intcode)
|
target_link_libraries(2019_21 aocpp intcode)
|
||||||
|
|
||||||
add_executable(22 22.cpp)
|
add_executable(2019_22 22.cpp)
|
||||||
target_link_libraries(22 aocpp zmod)
|
target_link_libraries(2019_22 aocpp zmod)
|
||||||
|
|
||||||
add_executable(23 23.cpp)
|
add_executable(2019_23 23.cpp)
|
||||||
target_link_libraries(23 aocpp intcode)
|
target_link_libraries(2019_23 aocpp intcode)
|
||||||
|
|
||||||
add_executable(24 24.cpp)
|
add_executable(2019_24 24.cpp)
|
||||||
target_link_libraries(24 aocpp)
|
target_link_libraries(2019_24 aocpp)
|
||||||
|
|
||||||
add_executable(25 25.cpp)
|
add_executable(2019_25 25.cpp)
|
||||||
target_link_libraries(25 aocpp intcode)
|
target_link_libraries(2019_25 aocpp intcode)
|
||||||
|
|
86
2020/01.cpp
Normal file
86
2020/01.cpp
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
#include <algorithm>
|
||||||
|
#include <bitset>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iterator>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <doctest.h>
|
||||||
|
|
||||||
|
#include <aocpp/Startup.hpp>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
auto Parse(std::istream & in) -> std::vector<std::int64_t>
|
||||||
|
{
|
||||||
|
std::vector<int64_t> result;
|
||||||
|
std::int64_t x;
|
||||||
|
while (in >> x) {
|
||||||
|
result.push_back(x);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Part1(std::vector<std::int64_t> 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<std::int64_t> 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;
|
||||||
|
}
|
2
2020/CMakeLists.txt
Normal file
2
2020/CMakeLists.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
add_executable(2020_01 01.cpp)
|
||||||
|
target_link_libraries(2020_01 aocpp)
|
|
@ -22,3 +22,4 @@ add_subdirectory(zmod)
|
||||||
add_subdirectory(intcode)
|
add_subdirectory(intcode)
|
||||||
add_subdirectory(2017)
|
add_subdirectory(2017)
|
||||||
add_subdirectory(2019)
|
add_subdirectory(2019)
|
||||||
|
add_subdirectory(2020)
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
"generator": "Ninja",
|
"generator": "Ninja",
|
||||||
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
"CMAKE_BUILD_TYPE": "Debug",
|
||||||
"CMAKE_TOOLCHAIN_FILE": "",
|
"CMAKE_TOOLCHAIN_FILE": "",
|
||||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}"
|
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user