From 6301b1f90cb175bd3f84c74ee7b122ce24f71121 Mon Sep 17 00:00:00 2001 From: zv0n Date: Thu, 16 Dec 2021 19:29:01 +0100 Subject: [PATCH] 16 --- 16/CMakeLists.txt | 22 ++++ 16/input | 1 + 16/main.cpp | 311 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 334 insertions(+) create mode 100644 16/CMakeLists.txt create mode 100644 16/input create mode 100644 16/main.cpp diff --git a/16/CMakeLists.txt b/16/CMakeLists.txt new file mode 100644 index 0000000..f09b67a --- /dev/null +++ b/16/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.10) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED True) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +enable_language(CXX) + +project(AoC16) + +if(APPLE) + include_directories(/usr/local/include) + link_directories(/usr/local/lib) +endif() + +if(WIN32) + add_executable(${CMAKE_PROJECT_NAME} WIN32) +else() + add_executable(${CMAKE_PROJECT_NAME}) +endif() + +target_sources(${CMAKE_PROJECT_NAME} + PRIVATE main.cpp + ) diff --git a/16/input b/16/input new file mode 100644 index 0000000..159f371 --- /dev/null +++ b/16/input @@ -0,0 +1 @@ +40541D900AEDC01A88002191FE2F45D1006A2FC2388D278D4653E3910020F2E2F3E24C007ECD7ABA6A200E6E8017F92C934CFA0E5290B569CE0F4BA5180213D963C00DC40010A87905A0900021B0D624C34600906725FFCF597491C6008C01B0004223342488A200F4378C9198401B87311A0C0803E600FC4887F14CC01C8AF16A2010021D1260DC7530042C012957193779F96AD9B36100907A00980021513E3943600043225C1A8EB2C3040043CC3B1802B400D3CA4B8D3292E37C30600B325A541D979606E384B524C06008E802515A638A73A226009CDA5D8026200D473851150401E8BF16E2ACDFB7DCD4F5C02897A5288D299D89CA6AA672AD5118804F592FC5BE8037000042217C64876000874728550D4C0149F29D00524ACCD2566795A0D880432BEAC79995C86483A6F3B9F6833397DEA03E401004F28CD894B9C48A34BC371CF7AA840155E002012E21260923DC4C248035299ECEB0AC4DFC0179B864865CF8802F9A005E264C25372ABAC8DEA706009F005C32B7FCF1BF91CADFF3C6FE4B3FB073005A6F93B633B12E0054A124BEE9C570004B245126F6E11E5C0199BDEDCE589275C10027E97BE7EF330F126DF3817354FFC82671BB5402510C803788DFA009CAFB14ECDFE57D8A766F0001A74F924AC99678864725F253FD134400F9B5D3004A46489A00A4BEAD8F7F1F7497C39A0020F357618C71648032BB004E4BBC4292EF1167274F1AA0078902262B0D4718229C8608A5226528F86008CFA6E802F275E2248C65F3610066274CEA9A86794E58AA5E5BDE73F34945E2008D27D2278EE30C489B3D20336D00C2F002DF480AC820287D8096F700288082C001DE1400C50035005AA2013E5400B10028C009600A74001EF2004F8400C92B172801F0F4C0139B8E19A8017D96A510A7E698800EAC9294A6E985783A400AE4A2945E9170 diff --git a/16/main.cpp b/16/main.cpp new file mode 100644 index 0000000..095c42c --- /dev/null +++ b/16/main.cpp @@ -0,0 +1,311 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +class Packet { +public: + Packet(int version, int type) : _version(version), _type(type) {} + + void setValue(uint64_t value) { + _has_value = true; + _value = value; + } + + void addSubPacket(Packet p) { + _subs.push_back(std::move(p)); + } + + int getVersion() const { + return _version; + } + + int getType() const { + return _type; + } + + uint64_t getValue() const { + return _value; + } + + bool hasSubs() const { + return _subs.size() != 0; + } + + const std::vector &getSubs() const { + return _subs; + } + + std::vector &getSubs() { + return _subs; + } + + bool hasValue() const { + return _has_value; + } + +private: + int _version; + int _type; + uint64_t _value{}; + bool _has_value = false; + std::vector _subs{}; +}; + +uint8_t getBitsFromChar(const char &c) { + switch (c) { + case 'A': + return 0b1010; + case 'B': + return 0b1011; + case 'C': + return 0b1100; + case 'D': + return 0b1101; + case 'E': + return 0b1110; + case 'F': + return 0b1111; + default: + return c - '0'; + } +} + +std::vector getBits(const std::string &file_name) { + std::vector bits; + + std::ifstream file(file_name); + std::string str; + std::getline(file, str); + if (str.length() % 2 == 1) { + bits.resize(str.length() / 2 + 1); + } else { + bits.resize(str.length() / 2); + } + for (size_t i = 0; i < str.length() / 2; i++) { + bits[i] |= getBitsFromChar(str[i * 2]); + bits[i] <<= 4; + bits[i] |= getBitsFromChar(str[i * 2 + 1]); + } + if (str.length() % 2 == 1) { + bits.back() |= getBitsFromChar(str.back()); + bits.back() <<= 4; + } + + return bits; +} + +uint8_t getBit(const std::vector &bits, uint64_t bitpos) { + auto ind = bitpos / 8; + auto bit = bitpos % 8; + uint8_t comparator = 0; + switch (bit) { + case 0: + comparator = 0b10000000; + break; + case 1: + comparator = 0b01000000; + break; + case 2: + comparator = 0b00100000; + break; + case 3: + comparator = 0b00010000; + break; + case 4: + comparator = 0b00001000; + break; + case 5: + comparator = 0b00000100; + break; + case 6: + comparator = 0b00000010; + break; + case 7: + comparator = 0b00000001; + break; + } + return bits[ind] & comparator ? 1 : 0; +} + +std::pair getPacketValue(const std::vector &bits, + uint64_t size, uint64_t bitpos) { + uint64_t result = 0; + auto length = bitpos + size; + while (bitpos < length) { + uint8_t group = 0; + for (int i = 0; i < 5; i++) { + group <<= 1; + group |= getBit(bits, bitpos); + bitpos++; + } + result <<= 4; + result |= group & 0b00001111; + if (!(group & 0b00010000)) { + break; + } + } + return { bitpos, result }; +} + +std::pair bitsToPacket(const std::vector &bits, + uint64_t start, uint64_t size) { + int version = 0; + version |= getBit(bits, start); + version <<= 1; + version |= getBit(bits, start + 1); + version <<= 1; + version |= getBit(bits, start + 2); + int type = 0; + type |= getBit(bits, start + 3); + type <<= 1; + type |= getBit(bits, start + 4); + type <<= 1; + type |= getBit(bits, start + 5); + + auto length = start + size; + + uint64_t end = 0; + Packet result(version, type); + switch (type) { + case 4: { + auto res = getPacketValue(bits, size - 6, start + 6); + result.setValue(res.second); + end = res.first; + } break; + default: + if (getBit(bits, start + 6)) { + uint16_t count = 0; + for (int i = 0; i < 11; i++) { + count <<= 1; + count |= getBit(bits, start + 7 + i); + } + + auto new_start = start + 7 + 11; + for (int i = 0; i < count; i++) { + auto res = bitsToPacket(bits, new_start, length - new_start); + new_start = res.first; + result.addSubPacket(std::move(res.second)); + } + end = new_start; + } else { + uint16_t size = 0; + for (int i = 0; i < 15; i++) { + size <<= 1; + size |= getBit(bits, start + 7 + i); + } + + auto new_start = start + 7 + 15; + auto sub_end = start + 7 + 15 + size; + while (new_start < sub_end) { + auto res = bitsToPacket(bits, new_start, size); + size -= res.first - new_start; + new_start = res.first; + result.addSubPacket(std::move(res.second)); + } + end = new_start; + } + break; + } + return { end, result }; +} + +uint64_t versionSum(const Packet &packet) { + uint64_t sum = packet.getVersion(); + if (packet.hasSubs()) { + for (auto &sub : packet.getSubs()) { + sum += versionSum(sub); + } + } + return sum; +} + +uint64_t part1(const Packet &packet) { + return versionSum(packet); +} + +uint64_t calculatePacket(Packet &packet) { + if (packet.hasValue()) { + return packet.getValue(); + } + uint64_t result = 0; + switch (packet.getType()) { + case 0: + result = 0; + for (auto &sub : packet.getSubs()) { + result += calculatePacket(sub); + } + break; + case 1: + result = 1; + for (auto &sub : packet.getSubs()) { + result *= calculatePacket(sub); + } + break; + case 2: + result = -1; + for (auto &sub : packet.getSubs()) { + auto calc = calculatePacket(sub); + if (calc < result) { + result = calc; + } + } + break; + case 3: + result = 0; + for (auto &sub : packet.getSubs()) { + auto calc = calculatePacket(sub); + if (calc > result) { + result = calc; + } + } + break; + case 4: + result = packet.getValue(); + break; + case 5: + result = calculatePacket(packet.getSubs()[0]) > + calculatePacket(packet.getSubs()[1]) + ? 1 + : 0; + break; + case 6: + result = calculatePacket(packet.getSubs()[0]) < + calculatePacket(packet.getSubs()[1]) + ? 1 + : 0; + break; + case 7: + result = calculatePacket(packet.getSubs()[0]) == + calculatePacket(packet.getSubs()[1]) + ? 1 + : 0; + break; + default: + break; + } + packet.setValue(result); + return result; +} + +uint64_t part2(Packet &packet) { + return calculatePacket(packet); +} + +int main(int argc, char **argv) { + if (argc < 2) { + std::cerr << "You must provide input file!" << std::endl; + return 1; + } + auto bits = getBits(argv[1]); + auto packet = bitsToPacket(bits, 0, bits.size() * 8).second; + std::cout << "Sum of all packet's versions is \033[91;1m" << part1(packet) + << "\033[0m." << std::endl; + std::cout << "The resulting value of the outermost packet is \033[91;1m" + << part2(packet) << "\033[0m." << std::endl; + return 0; +}