#include #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 = 0, bxl = 1, bst = 2, jnz = 3, bxc = 4, out = 5, bdv = 6, cdv = 7, nop = 8, }; 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(); if (peek() == opcode::nop) return; auto const x = combo(); switch (op) { case opcode::adv: adv(x); break; case opcode::bxl: bxl(); break; case opcode::bst: bst(x); break; case opcode::jnz: jnz(); break; case opcode::bxc: bxc(); break; case opcode::out: out(x); break; case opcode::bdv: bdv(x); break; case opcode::cdv: cdv(x); break; default: nop(); break; } m_pc += 2; } auto halt() const -> bool { return peek() == opcode::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]), m_pc == i ? " <" : ""); } str += "\n"; str += " "; for (usize i = 0; i < 16; ++i) { str += fmt::format("{:02X}", i); if (i == 7) str += " "; else str += " "; } str += "\n\n"; for (usize i = 0; i < m_output.size() * sizeof(u64); ++i) { if (i % 16 == 0) str += fmt::format("{:04X}: ", i); str += fmt::format("{:02X}", *(reinterpret_cast(const_cast(m_output.data())) + i)); if ((i + 1) % 16 == 0) str += "\n"; else if ((i + 1) % 8 == 0) str += " "; else str += " "; } if (m_output.size() != 0) str += "\n"; str += "-------------------------------------------------------\n"; return str; } auto output_str() const -> std::string { std::string str{}; for (usize i = 0; i < m_output.size(); ++i) { str += fmt::format("{}", m_output.at(i)); if (i < m_output.size() - 1) str += ","; } return str; } auto output() const -> std::vector const& { return m_output; } 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 { auto const op = u64(peek()); if (op < 4) return op; else if (op == 4) return m_regs.a; else if (op == 5) return m_regs.b; else if (op == 6) return m_regs.c; else return u64(opcode::nop); } private: auto adv(u64 x) -> void { m_regs.a >>= x; } auto bxl() -> void { m_regs.b = m_regs.b ^ u64(peek()); } auto bst(u64 x) -> void { m_regs.b = x % 8; } auto jnz() -> void { if (m_regs.a == 0) return; m_pc = u64(peek()) - 2; } auto bxc() -> void { m_regs.b = m_regs.b ^ m_regs.c; } auto out(u64 x) -> void { m_output.emplace_back(x % 8); } auto bdv(u64 x) -> void { m_regs.b = m_regs.a >> x; } auto cdv(u64 x) -> void { m_regs.c = m_regs.a >> x; } auto nop() -> void {} private: u64 m_pc{}; uec::regs m_regs{}; std::vector m_program{}; std::vector m_output{}; }; } auto part_a(uec::regs const& regs, std::vector const& program) -> void { uec::cpu cpu{}; cpu.load(regs, program); while (!cpu.halt()) { // fmt::print("{}", cpu.str()); // std::cin.get(); cpu.clock(); } fmt::print("{}", cpu.str()); fmt::print("{}\n", cpu.output_str()); } auto aoc24::day17([[maybe_unused]]std::span const& args) -> std::expected { // auto res = aoc::read_text("./dat/24/ex/17a.txt"); auto res = aoc::read_text("./dat/24/ex/17b.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(); } } // part_a(regs, program); uec::cpu cpu{}; cpu.load({}, program); return {}; }