From 29ae94401866e6689f135c2582c47043c5e6e7fe Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Sun, 12 Dec 2021 16:21:01 +0000 Subject: [PATCH] Add 2016 day 23 puzzles --- 2016/puzzle-23-01.cc | 199 +++++++++++++++++++++++++++++++++++++++++++ 2016/puzzle-23-02.cc | 199 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 398 insertions(+) create mode 100644 2016/puzzle-23-01.cc create mode 100644 2016/puzzle-23-02.cc diff --git a/2016/puzzle-23-01.cc b/2016/puzzle-23-01.cc new file mode 100644 index 0000000..6183d83 --- /dev/null +++ b/2016/puzzle-23-01.cc @@ -0,0 +1,199 @@ +// +// Created by Matthew Gretton-Dann on 12/12/2021. +// + +#include +#include +#include +#include +#include + +enum class Register { a, b, c, d }; +Register to_register(char c) +{ + switch (c) { + case 'a': + return Register::a; + case 'b': + return Register::b; + case 'c': + return Register::c; + case 'd': + return Register::d; + default: + abort(); + } +} + +enum class Opcode { cpy, inc, dec, jnz, tgl }; + +Opcode to_opcode(std::string const& s) +{ + if (s == "cpy") { + return Opcode::cpy; + } + if (s == "inc") { + return Opcode::inc; + } + if (s == "dec") { + return Opcode::dec; + } + if (s == "jnz") { + return Opcode::jnz; + } + if (s == "tgl") { + return Opcode::tgl; + } + abort(); +} + +using Int = long; +using Operand = std::variant; + +struct Instruction +{ + Instruction(Opcode opcode, Operand const& op1, Operand const& op2) + : opcode_(opcode), op1_(op1), op2_(op2) + { + } + + Opcode opcode() const noexcept { return opcode_; } + Operand const& op1() const noexcept { return op1_; } + Operand const& op2() const noexcept { return op2_; } + + void toggle() + { + switch (opcode_) { + case Opcode::cpy: + opcode_ = Opcode::jnz; + break; + case Opcode::jnz: + opcode_ = Opcode::cpy; + break; + case Opcode::inc: + opcode_ = Opcode::dec; + break; + case Opcode::dec: + case Opcode::tgl: + opcode_ = Opcode::inc; + break; + } + } + + static auto instruction(std::string const& s) -> Instruction + { + Opcode opcode = to_opcode(s.substr(0, 3)); + Operand op1{std::monostate()}; + Operand op2{std::monostate()}; + std::size_t idx{4}; + + { + char* end{nullptr}; + auto val{std::strtol(s.data() + idx, &end, 10)}; + if (end != s.data() + idx) { + op1 = val; + idx = end - s.data(); + } + else { + op1 = to_register(s[idx]); + idx += 1; + } + } + + if (idx < s.size()) { + assert(s[idx] == ' '); + ++idx; + char* end{0}; + auto val{std::strtol(s.data() + idx, &end, 10)}; + if (end != s.data() + idx) { + op2 = val; + } + else { + op2 = to_register(s[idx]); + } + } + + return Instruction(opcode, op1, op2); + } + +private: + Opcode opcode_; + Operand op1_; + Operand op2_; +}; + +struct State +{ + State(std::vector const& instructions) : instructions_(instructions) {} + + auto reg(Register r) const noexcept -> Int { return registers_[static_cast(r)]; } + void reg(Register r, Int v) noexcept { registers_[static_cast(r)] = v; } + + void execute() + { + while (pc_ < instructions_.size()) { + auto& i{instructions_[pc_]}; + switch (i.opcode()) { + case Opcode::cpy: + set(i.op2(), value(i.op1())); + break; + case Opcode::inc: + set(i.op1(), value(i.op1()) + 1); + break; + case Opcode::dec: + set(i.op1(), value(i.op1()) - 1); + break; + case Opcode::jnz: + if (value(i.op1()) != 0) { + pc_ += value(i.op2()) - 1; + } + break; + case Opcode::tgl: + auto dest{pc_ + value(i.op1())}; + if (dest >= 0 && dest < instructions_.size()) { + instructions_[dest].toggle(); + } + break; + } + + ++pc_; + } + } + +private: + Int value(Operand const& o) + { + if (std::holds_alternative(o)) { + return registers_[static_cast(std::get(o))]; + } + if (std::holds_alternative(o)) { + return std::get(o); + } + abort(); + } + + void set(Operand const& dest, Int value) + { + if (std::holds_alternative(dest)) { + registers_[static_cast(std::get(dest))] = value; + } + } + + std::vector instructions_; + std::array registers_{0, 0, 0, 0}; + Int pc_{0}; +}; + +auto main() -> int +{ + std::vector instructions; + std::string line; + while (std::getline(std::cin, line)) { + instructions.push_back(Instruction::instruction(line)); + } + + State state(instructions); + state.reg(Register::a, 7); + state.execute(); + std::cout << "Part 1 a = " << state.reg(Register::a) << '\n'; +} diff --git a/2016/puzzle-23-02.cc b/2016/puzzle-23-02.cc new file mode 100644 index 0000000..8f99a06 --- /dev/null +++ b/2016/puzzle-23-02.cc @@ -0,0 +1,199 @@ +// +// Created by Matthew Gretton-Dann on 12/12/2021. +// + +#include +#include +#include +#include +#include + +enum class Register { a, b, c, d }; +Register to_register(char c) +{ + switch (c) { + case 'a': + return Register::a; + case 'b': + return Register::b; + case 'c': + return Register::c; + case 'd': + return Register::d; + default: + abort(); + } +} + +enum class Opcode { cpy, inc, dec, jnz, tgl }; + +Opcode to_opcode(std::string const& s) +{ + if (s == "cpy") { + return Opcode::cpy; + } + if (s == "inc") { + return Opcode::inc; + } + if (s == "dec") { + return Opcode::dec; + } + if (s == "jnz") { + return Opcode::jnz; + } + if (s == "tgl") { + return Opcode::tgl; + } + abort(); +} + +using Int = long; +using Operand = std::variant; + +struct Instruction +{ + Instruction(Opcode opcode, Operand const& op1, Operand const& op2) + : opcode_(opcode), op1_(op1), op2_(op2) + { + } + + Opcode opcode() const noexcept { return opcode_; } + Operand const& op1() const noexcept { return op1_; } + Operand const& op2() const noexcept { return op2_; } + + void toggle() + { + switch (opcode_) { + case Opcode::cpy: + opcode_ = Opcode::jnz; + break; + case Opcode::jnz: + opcode_ = Opcode::cpy; + break; + case Opcode::inc: + opcode_ = Opcode::dec; + break; + case Opcode::dec: + case Opcode::tgl: + opcode_ = Opcode::inc; + break; + } + } + + static auto instruction(std::string const& s) -> Instruction + { + Opcode opcode = to_opcode(s.substr(0, 3)); + Operand op1{std::monostate()}; + Operand op2{std::monostate()}; + std::size_t idx{4}; + + { + char* end{nullptr}; + auto val{std::strtol(s.data() + idx, &end, 10)}; + if (end != s.data() + idx) { + op1 = val; + idx = end - s.data(); + } + else { + op1 = to_register(s[idx]); + idx += 1; + } + } + + if (idx < s.size()) { + assert(s[idx] == ' '); + ++idx; + char* end{0}; + auto val{std::strtol(s.data() + idx, &end, 10)}; + if (end != s.data() + idx) { + op2 = val; + } + else { + op2 = to_register(s[idx]); + } + } + + return Instruction(opcode, op1, op2); + } + +private: + Opcode opcode_; + Operand op1_; + Operand op2_; +}; + +struct State +{ + State(std::vector const& instructions) : instructions_(instructions) {} + + auto reg(Register r) const noexcept -> Int { return registers_[static_cast(r)]; } + void reg(Register r, Int v) noexcept { registers_[static_cast(r)] = v; } + + void execute() + { + while (pc_ < instructions_.size()) { + auto& i{instructions_[pc_]}; + switch (i.opcode()) { + case Opcode::cpy: + set(i.op2(), value(i.op1())); + break; + case Opcode::inc: + set(i.op1(), value(i.op1()) + 1); + break; + case Opcode::dec: + set(i.op1(), value(i.op1()) - 1); + break; + case Opcode::jnz: + if (value(i.op1()) != 0) { + pc_ += value(i.op2()) - 1; + } + break; + case Opcode::tgl: + auto dest{pc_ + value(i.op1())}; + if (dest >= 0 && dest < instructions_.size()) { + instructions_[dest].toggle(); + } + break; + } + + ++pc_; + } + } + +private: + Int value(Operand const& o) + { + if (std::holds_alternative(o)) { + return registers_[static_cast(std::get(o))]; + } + if (std::holds_alternative(o)) { + return std::get(o); + } + abort(); + } + + void set(Operand const& dest, Int value) + { + if (std::holds_alternative(dest)) { + registers_[static_cast(std::get(dest))] = value; + } + } + + std::vector instructions_; + std::array registers_{0, 0, 0, 0}; + Int pc_{0}; +}; + +auto main() -> int +{ + std::vector instructions; + std::string line; + while (std::getline(std::cin, line)) { + instructions.push_back(Instruction::instruction(line)); + } + + State state(instructions); + state.reg(Register::a, 12); + state.execute(); + std::cout << "Part 2 a = " << state.reg(Register::a) << '\n'; +}