This commit is contained in:
zv0n 2021-12-16 19:29:01 +01:00
parent c21ff6800f
commit 6301b1f90c
3 changed files with 334 additions and 0 deletions

22
16/CMakeLists.txt Normal file
View File

@ -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
)

1
16/input Normal file
View File

@ -0,0 +1 @@
40541D900AEDC01A88002191FE2F45D1006A2FC2388D278D4653E3910020F2E2F3E24C007ECD7ABA6A200E6E8017F92C934CFA0E5290B569CE0F4BA5180213D963C00DC40010A87905A0900021B0D624C34600906725FFCF597491C6008C01B0004223342488A200F4378C9198401B87311A0C0803E600FC4887F14CC01C8AF16A2010021D1260DC7530042C012957193779F96AD9B36100907A00980021513E3943600043225C1A8EB2C3040043CC3B1802B400D3CA4B8D3292E37C30600B325A541D979606E384B524C06008E802515A638A73A226009CDA5D8026200D473851150401E8BF16E2ACDFB7DCD4F5C02897A5288D299D89CA6AA672AD5118804F592FC5BE8037000042217C64876000874728550D4C0149F29D00524ACCD2566795A0D880432BEAC79995C86483A6F3B9F6833397DEA03E401004F28CD894B9C48A34BC371CF7AA840155E002012E21260923DC4C248035299ECEB0AC4DFC0179B864865CF8802F9A005E264C25372ABAC8DEA706009F005C32B7FCF1BF91CADFF3C6FE4B3FB073005A6F93B633B12E0054A124BEE9C570004B245126F6E11E5C0199BDEDCE589275C10027E97BE7EF330F126DF3817354FFC82671BB5402510C803788DFA009CAFB14ECDFE57D8A766F0001A74F924AC99678864725F253FD134400F9B5D3004A46489A00A4BEAD8F7F1F7497C39A0020F357618C71648032BB004E4BBC4292EF1167274F1AA0078902262B0D4718229C8608A5226528F86008CFA6E802F275E2248C65F3610066274CEA9A86794E58AA5E5BDE73F34945E2008D27D2278EE30C489B3D20336D00C2F002DF480AC820287D8096F700288082C001DE1400C50035005AA2013E5400B10028C009600A74001EF2004F8400C92B172801F0F4C0139B8E19A8017D96A510A7E698800EAC9294A6E985783A400AE4A2945E9170

311
16/main.cpp Normal file
View File

@ -0,0 +1,311 @@
#include <algorithm>
#include <deque>
#include <fstream>
#include <iostream>
#include <sstream>
#include <unordered_map>
#include <unordered_set>
#include <vector>
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<Packet> &getSubs() const {
return _subs;
}
std::vector<Packet> &getSubs() {
return _subs;
}
bool hasValue() const {
return _has_value;
}
private:
int _version;
int _type;
uint64_t _value{};
bool _has_value = false;
std::vector<Packet> _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<uint8_t> getBits(const std::string &file_name) {
std::vector<uint8_t> 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<uint8_t> &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<uint64_t, uint64_t> getPacketValue(const std::vector<uint8_t> &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<uint64_t, Packet> bitsToPacket(const std::vector<uint8_t> &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;
}