201718
This commit is contained in:
parent
4d4dfb4424
commit
8f772d85b2
206
2017/18.cpp
Normal file
206
2017/18.cpp
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <deque>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iterator>
|
||||||
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <doctest.h>
|
||||||
|
|
||||||
|
#include <aocpp/Startup.hpp>
|
||||||
|
#include <aocpp/Overloaded.hpp>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using Name = std::string;
|
||||||
|
using Value = std::int64_t;
|
||||||
|
|
||||||
|
struct Literal { Value value; };
|
||||||
|
struct Variable { Name name; };
|
||||||
|
using Expression = std::variant<Literal, Variable>;
|
||||||
|
|
||||||
|
struct Set { Name x; Expression y; };
|
||||||
|
struct Add { Name x; Expression y; };
|
||||||
|
struct Mul { Name x; Expression y; };
|
||||||
|
struct Mod { Name x; Expression y; };
|
||||||
|
struct Jgz { Expression x; Expression y; };
|
||||||
|
struct Rcv { Name x; };
|
||||||
|
struct Snd { Expression x; };
|
||||||
|
using Instruction = std::variant<Set, Add, Mul, Mod, Jgz, Rcv, Snd>;
|
||||||
|
|
||||||
|
auto IsName(std::string const& word) {
|
||||||
|
return std::all_of(word.begin(), word.end(), [](auto c) { return std::isalpha(c); });
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ParseName(std::istream & in) -> Name
|
||||||
|
{
|
||||||
|
std::string word;
|
||||||
|
in >> word;
|
||||||
|
if (IsName(word)) { return word; }
|
||||||
|
throw std::runtime_error{"bad name"};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ParseExpression(std::istream & in) -> Expression
|
||||||
|
{
|
||||||
|
std::string word;
|
||||||
|
in >> word;
|
||||||
|
if (IsName(word)) {
|
||||||
|
return Variable{word};
|
||||||
|
} else {
|
||||||
|
return Literal{std::stoll(word)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Parse(std::istream & in) -> std::vector<Instruction> {
|
||||||
|
std::vector<Instruction> result;
|
||||||
|
std::string op;
|
||||||
|
while (in >> op) {
|
||||||
|
if ("set" == op) {
|
||||||
|
auto x = ParseName(in);
|
||||||
|
auto y = ParseExpression(in);
|
||||||
|
result.push_back(Set{x,y});
|
||||||
|
} else if ("add" == op) {
|
||||||
|
auto x = ParseName(in);
|
||||||
|
auto y = ParseExpression(in);
|
||||||
|
result.push_back(Add{x,y});
|
||||||
|
} else if ("mul" == op) {
|
||||||
|
auto x = ParseName(in);
|
||||||
|
auto y = ParseExpression(in);
|
||||||
|
result.push_back(Mul{x,y});
|
||||||
|
} else if ("mod" == op) {
|
||||||
|
auto x = ParseName(in);
|
||||||
|
auto y = ParseExpression(in);
|
||||||
|
result.push_back(Mod{x,y});
|
||||||
|
} else if ("jgz" == op) {
|
||||||
|
auto x = ParseExpression(in);
|
||||||
|
auto y = ParseExpression(in);
|
||||||
|
result.push_back(Jgz{x,y});
|
||||||
|
} else if ("rcv" == op) {
|
||||||
|
auto x = ParseName(in);
|
||||||
|
result.push_back(Rcv{x});
|
||||||
|
} else if ("snd" == op) {
|
||||||
|
auto x = ParseExpression(in);
|
||||||
|
result.push_back(Snd{x});
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error{"unknown op"};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Send { Value sent; };
|
||||||
|
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{
|
||||||
|
[](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<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_]))
|
||||||
|
{
|
||||||
|
return *effect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Halt{};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto Part1(std::vector<Instruction> const& program) -> Value {
|
||||||
|
Value last_sound = -1;
|
||||||
|
Machine m { program };
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
auto effect = m.Step();
|
||||||
|
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"};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Spin(Machine & m, std::deque<Value> & input, std::deque<Value> & output) -> Value* {
|
||||||
|
for(;;) {
|
||||||
|
auto effect = m.Step();
|
||||||
|
switch (effect.index()) {
|
||||||
|
case 0: output.push_back(std::get<0>(effect).sent); break;
|
||||||
|
case 1: {
|
||||||
|
auto & target = std::get<1>(effect).target;
|
||||||
|
if (input.empty()) {
|
||||||
|
return ⌖
|
||||||
|
} else {
|
||||||
|
target = input.front();
|
||||||
|
input.pop_front();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: throw std::runtime_error{"program halted"};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Part2(std::vector<Instruction> const& program) -> std::size_t {
|
||||||
|
Machine m0 { program };
|
||||||
|
Machine m1 { program };
|
||||||
|
m1.registers_["p"] = 1;
|
||||||
|
|
||||||
|
std::deque<Value> inputs0;
|
||||||
|
std::deque<Value> inputs1;
|
||||||
|
|
||||||
|
auto stuck0 = Spin(m0, inputs0, inputs1);
|
||||||
|
auto stuck1 = Spin(m1, inputs1, inputs0);
|
||||||
|
|
||||||
|
std::size_t result = inputs0.size();
|
||||||
|
|
||||||
|
while(!(inputs0.empty() && inputs1.empty())) {
|
||||||
|
if (!inputs0.empty()) {
|
||||||
|
*stuck0 = inputs0.front(); inputs0.pop_front();
|
||||||
|
stuck0 = Spin(m0, inputs0, inputs1);
|
||||||
|
}
|
||||||
|
if (!inputs1.empty()) {
|
||||||
|
*stuck1 = inputs1.front(); inputs1.pop_front();
|
||||||
|
result -= inputs0.size();
|
||||||
|
stuck1 = Spin(m1, inputs1, inputs0);
|
||||||
|
result += inputs0.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
auto main(int argc, char** argv) -> int {
|
||||||
|
auto program = Parse(aocpp::Startup(argc, argv));
|
||||||
|
std::cout << "Part 1: " << Part1(program) << std::endl;
|
||||||
|
std::cout << "Part 2: " << Part2(program) << std::endl;
|
||||||
|
}
|
2
2017/CMakeLists.txt
Normal file
2
2017/CMakeLists.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
add_executable(2017_18 18.cpp)
|
||||||
|
target_link_libraries(2017_18 aocpp)
|
|
@ -1,7 +1,7 @@
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
set(CMAKE_C_STANDARD 11)
|
set(CMAKE_C_STANDARD 11)
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
project(aocpp19
|
project(aocpp
|
||||||
VERSION 1
|
VERSION 1
|
||||||
LANGUAGES C CXX
|
LANGUAGES C CXX
|
||||||
)
|
)
|
||||||
|
@ -15,9 +15,10 @@ else()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(PkgConfig)
|
find_package(PkgConfig)
|
||||||
pkg_check_modules(GMP REQUIRED IMPORTED_TARGET gmp)
|
pkg_check_modules(GMP REQUIRED IMPORTED_TARGET gmpxx)
|
||||||
|
|
||||||
add_subdirectory(lib)
|
add_subdirectory(lib)
|
||||||
add_subdirectory(zmod)
|
add_subdirectory(zmod)
|
||||||
add_subdirectory(intcode)
|
add_subdirectory(intcode)
|
||||||
|
add_subdirectory(2017)
|
||||||
add_subdirectory(2019)
|
add_subdirectory(2019)
|
||||||
|
|
9
lib/include/aocpp/Overloaded.hpp
Normal file
9
lib/include/aocpp/Overloaded.hpp
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef AOCPP_OVERLOADED_HPP_
|
||||||
|
#define AOCPP_OVERLOADED_HPP_
|
||||||
|
|
||||||
|
// helper type for the visitor #4
|
||||||
|
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
|
||||||
|
// explicit deduction guide (not needed as of C++20)
|
||||||
|
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
|
||||||
|
|
||||||
|
#endif // AOCPP_OVERLOADED_HPP_
|
|
@ -21,6 +21,12 @@ public:
|
||||||
return {value + rhs.value};
|
return {value + rhs.value};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto operator+=(ZMod const& rhs) -> ZMod & {
|
||||||
|
value += rhs.value;
|
||||||
|
mpz_mod_ui(this->value.get_mpz_t(), value.get_mpz_t(), Mod);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
auto operator-() const -> ZMod {
|
auto operator-() const -> ZMod {
|
||||||
return {-value};
|
return {-value};
|
||||||
}
|
}
|
||||||
|
@ -29,10 +35,22 @@ public:
|
||||||
return {value - rhs.value};
|
return {value - rhs.value};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto operator-=(ZMod const& rhs) -> ZMod & {
|
||||||
|
value -= rhs.value;
|
||||||
|
mpz_mod_ui(value.get_mpz_t(), value.get_mpz_t(), Mod);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
auto operator*(ZMod const& rhs) const -> ZMod {
|
auto operator*(ZMod const& rhs) const -> ZMod {
|
||||||
return {value * rhs.value};
|
return {value * rhs.value};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto operator*=(ZMod const& rhs) -> ZMod & {
|
||||||
|
value -= rhs.value;
|
||||||
|
mpz_mod_ui(value.get_mpz_t(), value.get_mpz_t(), Mod);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
auto inverse() const -> ZMod {
|
auto inverse() const -> ZMod {
|
||||||
mpz_class m{Mod};
|
mpz_class m{Mod};
|
||||||
ZMod result;
|
ZMod result;
|
||||||
|
@ -47,4 +65,4 @@ public:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue
Block a user