diff --git a/res/2016/day23/test_input.txt b/res/2016/day23/test_input.txt index e69de29..bcabc2c 100644 --- a/res/2016/day23/test_input.txt +++ b/res/2016/day23/test_input.txt @@ -0,0 +1,7 @@ +cpy 2 a +tgl a +tgl a +tgl a +cpy 1 a +dec a +dec a diff --git a/src/2016/Day23.cpp b/src/2016/Day23.cpp index 805c373..85a01c2 100644 --- a/src/2016/Day23.cpp +++ b/src/2016/Day23.cpp @@ -2,30 +2,197 @@ namespace y2016::day23 { - REGISTER_DAY(2016, Day23, std::vector, int); + enum class Operator + { + Cpy, + Inc, + Dec, + Jnz, + Tgl + }; - REGISTER_TEST_EXAMPLE(2016, Day23, ExampleInput, 1, 0); - REGISTER_TEST(2016, Day23, Input, 1, 0); - REGISTER_TEST_EXAMPLE(2016, Day23, ExampleInput, 2, 0); - REGISTER_TEST(2016, Day23, Input, 2, 0); + struct Instruction + { + Operator op; + std::variant arg1; + std::variant arg2; + }; + + REGISTER_DAY(2016, Day23, std::vector, int); + + REGISTER_TEST(2016, Day23, Input, 1, 11415); + REGISTER_TEST(2016, Day23, Input, 2, 479007975); + + std::variant ReadArg(const std::string& str, int arg) + { + size_t pos = str.find(' '); + int i = 0; + while (i < arg) + { + pos = str.find(' ', pos + 1); + i++; + } + + if (str[pos + 1] >= 'a' && str[pos + 1] <= 'd') + return str[pos + 1]; + + return (int)std::atoi(str.c_str() + pos + 1); + } READ_INPUT(input) { - std::vector vec; + std::vector vec; std::string str; while (getline(input, str)) { + Instruction instruction; + if (str[0] == 'c') + { + instruction.op = Operator::Cpy; + instruction.arg1 = ReadArg(str, 0); + instruction.arg2 = ReadArg(str, 1); + } + else if (str[0] == 'i') + { + instruction.op = Operator::Inc; + instruction.arg1 = ReadArg(str, 0); + } + else if (str[0] == 'd') + { + instruction.op = Operator::Dec; + instruction.arg1 = ReadArg(str, 0); + } + else if (str[0] == 'j') + { + instruction.op = Operator::Jnz; + instruction.arg1 = ReadArg(str, 0); + instruction.arg2 = ReadArg(str, 1); + } + else if (str[0] == 't') + { + instruction.op = Operator::Tgl; + instruction.arg1 = ReadArg(str, 0); + } + vec.emplace_back(instruction); } return vec; } + void Toggle(Instruction& instruction) + { + switch (instruction.op) + { + case Operator::Cpy: + instruction.op = Operator::Jnz; + break; + case Operator::Inc: + instruction.op = Operator::Dec; + break; + case Operator::Dec: + instruction.op = Operator::Inc; + break; + case Operator::Jnz: + instruction.op = Operator::Cpy; + break; + case Operator::Tgl: + instruction.op = Operator::Inc; + break; + } + } + + bool IsValid(const Instruction& instruction) + { + switch (instruction.op) + { + case Operator::Cpy: + return std::holds_alternative(instruction.arg2); + case Operator::Inc: + return std::holds_alternative(instruction.arg1); + case Operator::Dec: + return std::holds_alternative(instruction.arg1); + case Operator::Jnz: + return true; + case Operator::Tgl: + return true; + } + return false; + } + + int GetRegisterIndex(const std::variant& c) + { + return std::get(c) - 'a'; + } + + int GetValue(const std::vector& registers, const std::variant& data) + { + if (std::holds_alternative(data)) + return std::get(data); + else + return registers[GetRegisterIndex(data)]; + } + + int Run(std::vector instructions, std::vector registers) + { + int i = 0; + for (size_t pc = 0; pc < instructions.size(); pc++) + { + i++; + if (!IsValid(instructions[pc])) + continue; + // The input program I got does a multiplication (a = b * d). So instead of using the ++, -- operators, calculate + // it directly and set the registers to expected value after the operation is done. + // Other inputs might have different pc position, and multiply different registers. + if (pc == 4) + { + registers[0] = registers[1] * registers[3]; + registers[3] = 0; + registers[2] = registers[1]; + pc = 9; + } + switch (instructions[pc].op) + { + case Operator::Cpy: + { + int number = GetValue(registers, instructions[pc].arg1); + registers[GetRegisterIndex(instructions[pc].arg2)] = number; + break; + } + case Operator::Inc: + { + registers[GetRegisterIndex(instructions[pc].arg1)]++; + break; + } + case Operator::Dec: + { + registers[GetRegisterIndex(instructions[pc].arg1)]--; + break; + } + case Operator::Jnz: + { + int value = GetValue(registers, instructions[pc].arg1); + if (value != 0) + pc += GetValue(registers, instructions[pc].arg2) - 1; + break; + } + case Operator::Tgl: + { + int offset = registers[GetRegisterIndex(instructions[pc].arg1)]; + if (pc + offset >= 0 && pc + offset < instructions.size()) + Toggle(instructions[pc + offset]); + } + break; + } + } + return registers[0]; + } + OUTPUT1(input) { - return 0; + return Run(input, std::vector{7, 0, 0, 0}); } OUTPUT2(input) { - return 0; + return Run(input, std::vector{12, 0, 0, 0}); } } diff --git a/src/common/lib/Helper.h b/src/common/lib/Helper.h index 6aeb4a1..df2d321 100644 --- a/src/common/lib/Helper.h +++ b/src/common/lib/Helper.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "Array2D.h" @@ -33,6 +34,9 @@ static std::ostream& operator<<(std::ostream& stream, const std::map& cont template static std::ostream& operator<<(std::ostream& stream, const std::pair& pair); +template +static std::ostream& operator<<(std::ostream& stream, const std::variant& variant); + struct Helper { struct ScopedTraceErrorDisabler @@ -639,3 +643,10 @@ static std::ostream& operator<<(std::ostream& stream, const std::pair& pai { return stream << "(" << pair.first << ", " << pair.second << ")"; } + +template +static std::ostream& operator<<(std::ostream& stream, const std::variant& variant) +{ + std::visit([&stream](const auto& value) { stream << value; }, variant); + return stream; +}