#include #include #include #include #include "aoc.hpp" #include "aoc/utils.hpp" #include "fmt/format.h" #include "stb_image_write.h" #include "ctre.hpp" using namespace aoc::types; using namespace std::string_view_literals; namespace uec { enum class opcode : u16 { adv, bxl, bst, jnz, bxc, out, bdv, cdv, nop, }; auto opcode_to_str(opcode op) -> char const* { switch (op) { case opcode::adv: return "adv"; case opcode::bxl: return "bxl"; case opcode::bst: return "bst"; case opcode::jnz: return "jnz"; case opcode::bxc: return "bxc"; case opcode::out: return "out"; case opcode::bdv: return "bdv"; case opcode::cdv: return "cdv"; default: return "nop"; } } struct regs { u64 a; u64 b; u64 c; }; class cpu { public: cpu() {} auto load(uec::regs const& regs, std::vector const& program) -> void { m_regs = regs; m_program = program; } auto registers() const -> uec::regs const& { return m_regs; } auto program() const -> std::vector const& { return m_program; } auto clock() -> void { auto const op = read(); switch (op) { case opcode::adv: adv(); case opcode::bxl: bxl(); case opcode::bst: bst(); case opcode::jnz: jnz(); case opcode::bxc: bxc(); case opcode::out: out(); case opcode::bdv: bdv(); case opcode::cdv: cdv(); default: nop(); } } auto str() const -> std::string { using namespace std::string_literals; std::string str{}; str += "PC: " + fmt::format("{:#04x}", m_pc) + "\n"; str += "\n"; str += "A: " + fmt::format("{:#010x}", m_regs.a) + "\n"; str += "B: " + fmt::format("{:#010x}", m_regs.b) + "\n"; str += "C: " + fmt::format("{:#010x}", m_regs.c) + "\n"; str += "\n"; for (usize i = 0; i < m_program.size(); ++i) { str += fmt::format("{:02x}: ", i); str += fmt::format("{}\n", opcode_to_str(m_program[i])); } return str; } private: auto read() const -> opcode { if (m_pc < m_program.size()) return m_program[m_pc]; return opcode::nop; } auto peek() const -> opcode { if (m_pc + 1 < m_program.size()) return m_program[m_pc + 1]; return opcode::nop; } auto combo() const -> u64 { return 0; } private: auto adv(u64 x) -> void { m_regs.a >>= x; } auto bxl() -> void { m_regs.b = m_regs.b ^ u64(opcode::bxl); } auto bst(u64 x) -> void { m_regs.b = x % 8; } auto jnz() -> void { if (m_regs.a == 0) return; m_pc = u64(opcode::jnz); } auto bxc() -> void { m_regs.b = m_regs.b ^ m_regs.c; } auto out(u64 x) -> void { } auto bdv() -> void {} auto cdv() -> void {} auto nop() -> void {} private: u64 m_pc{}; uec::regs m_regs{}; std::vector m_program{}; }; } auto aoc24::day17([[maybe_unused]]std::span const& args) -> std::expected { auto res = aoc::read_text("./dat/24/ex/17.txt"); // auto res = aoc::read_text("./dat/24/re/17.txt"); if (!res) return std::unexpected(res.error()); auto const txt = *res; auto const lines = txt | aoc::split("\n"sv) | aoc::map_to_sv | aoc::filter_non_empty | std::ranges::to(); uec::regs regs{}; std::vector program{}; for (auto const& line : lines) { if (auto reg = ctre::match<"Register ([A-Z]): ([0-9]+)">(line)) { if (reg.get<1>().view() == "A"sv) { regs.a = std::stoul(reg.get<2>().to_string()); } else if (reg.get<1>().view() == "A"sv) { regs.b = std::stoul(reg.get<2>().to_string()); } else if (reg.get<1>().view() == "A"sv) { regs.c = std::stoul(reg.get<2>().to_string()); } else { // fmt::print("unknown register\n"); } continue; } if (auto prog = ctre::match<"Program: ([0-9,]+)">(line)) { program = prog.get<1>().to_string() | aoc::split(","sv) | aoc::map_to_str | aoc::filter_non_empty | std::views::transform([](auto const& str) { return uec::opcode(std::stoul(str)); }) | std::ranges::to(); } } uec::cpu cpu{}; cpu.load(regs, program); fmt::print("{}", cpu.str()); return {}; }