-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
152 lines (136 loc) · 4.86 KB
/
main.cpp
File metadata and controls
152 lines (136 loc) · 4.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include <iostream>
#include <chrono>
#include <fstream>
#include <unordered_set>
#include <unordered_map>
#include <queue>
#include <numeric>
#include "../Utils/utils.h"
#include "../Utils/Vector.h"
typedef std::vector<std::string> puzzle_t;
struct Packet {
Packet() = default;
Packet(int version, int typeId) : version_(version), typeId_(typeId) {}
int accumulateVersions(){
int version = this->version_;
for(auto& packet : this->subPackets_){
version += packet.accumulateVersions();
}
return version;
}
size_t calculateTransmission(){
if(typeId_ == 4){
return value_;
}
// this is done, to clean up the switch case, it adds space complexity, but is easier to read
// and we have space
std::vector<size_t> values;
values.reserve(this->subPackets_.size());
for (auto& subPacket : this->subPackets_) {
values.push_back(subPacket.calculateTransmission());
}
switch(this->typeId_){
case 0:
return std::accumulate(values.begin(), values.end(), size_t(0), std::plus<>());
case 1:
return std::accumulate(values.begin(), values.end(), size_t(1), std::multiplies<>());
case 2:
return *std::min_element(values.begin(), values.end());
case 3:
return *std::max_element(values.begin(), values.end());
case 5:
return values[0] > values[1];
case 6:
return values[0] < values[1];
case 7:
return values[0] == values[1];
default:
return 0;
}
}
unsigned int version_ : 3 = 0;
unsigned int typeId_ : 3 = 0;
size_t packetBitLength_ = 0;
size_t value_ = 0;
std::vector<Packet> subPackets_;
};
Packet parse(const std::vector<unsigned char>& bits, size_t start){
// first 3 bits are version number, second three bits are typeId
int version = (bits[start] << 2) | (bits[start+1] << 1) | bits[start+2];
int typeId = (bits[start+3] << 2) | (bits[start+4] << 1) | bits[start+5];
Packet curr(version, typeId);
if(typeId == 4){
size_t packetCnt = 0;
for (size_t i = start + 6; i < bits.size(); i += 5) {
packetCnt++;
size_t groupStart = i + 1;
for (size_t bit = 0; bit < 4; ++bit) {
curr.value_ = (curr.value_ << 1) | bits[groupStart + bit];
}
if (bits[i] == 0) {
break; // Last group
}
}
curr.packetBitLength_ = 6 + packetCnt*5;
return curr;
}
size_t length = 0;
size_t bitsLength = bits[start + 6] == 0 ? 15 : 11;
size_t newStart = start + 7;
for (size_t i = 0; i < bitsLength; ++i) {
length = (length << 1) | bits[newStart++];
}
if(bitsLength == 11){
curr.subPackets_.reserve(length);
for(int i = 0; i < length; i++){
curr.subPackets_.emplace_back(parse(bits, newStart));
newStart += curr.subPackets_.back().packetBitLength_;
}
} else {
size_t end = newStart + length;
while(newStart < end){
curr.subPackets_.emplace_back(parse(bits, newStart));
newStart += curr.subPackets_.back().packetBitLength_;
}
}
curr.packetBitLength_ = newStart - start;
return curr;
}
void solvePuzzle(const puzzle_t& puzzle, int stage){
std::vector<unsigned char> bits(puzzle.at(0).length()*4);
for(int currDigit = 0; currDigit < puzzle.at(0).length(); currDigit++){
size_t x = std::stoi(puzzle.at(0).substr(currDigit, 1), nullptr, 16);
for(int bit = 0; x > 0; bit++) {
bits[(currDigit*4) + 4-bit-1] = x%2;
x /= 2;
}
}
Packet packet = parse(bits, 0);
if(stage == 1){
std::cout << packet.accumulateVersions() << "\n";
} else {
std::cout << packet.calculateTransmission() << "\n";
}
}
void stage1(const puzzle_t& puzzle) {
solvePuzzle(puzzle, 1);
}
void stage2(const puzzle_t& puzzle) {
solvePuzzle(puzzle, 2);
}
int main(){
puzzle_t puzzle;
std::string input = "example";
input = "input";
aoc_utils::load_puzzle(input, puzzle);
auto start = std::chrono::high_resolution_clock::now();
stage1(puzzle);
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed = end - start;
std::cout << "Stage 1 took " << elapsed.count() << " seconds\n";
start = std::chrono::high_resolution_clock::now();
stage2(puzzle);
end = std::chrono::high_resolution_clock::now();
elapsed = end - start;
std::cout << "Stage 2 took " << elapsed.count() << " seconds\n";
}