-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday9.cpp
133 lines (106 loc) · 4.66 KB
/
day9.cpp
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
/*
--- Day 9: Explosives in Cyberspace ---
Wandering around a secure area, you come across a datalink port to a new part
of the network. After briefly scanning it for interesting files, you find one
file in particular that catches your attention. It's compressed with an
experimental format, but fortunately, the documentation for the format is
nearby.
The format compresses a sequence of characters. Whitespace is ignored. To
indicate that some sequence should be repeated, a marker is added to the file,
like (10x2). To decompress this marker, take the subsequent 10 characters and
repeat them 2 times. Then, continue reading the file after the repeated data.
The marker itself is not included in the decompressed output.
If parentheses or other characters appear within the data referenced by a
marker, that's okay - treat it like normal data, not a marker, and then resume
looking for markers after the decompressed section.
For example:
- ADVENT contains no markers and decompresses to itself with no changes,
resulting in a decompressed length of 6.
- A(1x5)BC repeats only the B a total of 5 times, becoming ABBBBBC for a
decompressed length of 7.
- (3x3)XYZ becomes XYZXYZXYZ for a decompressed length of 9.
- A(2x2)BCD(2x2)EFG doubles the BC and EF, becoming ABCBCDEFEFG for a
decompressed length of 11.
- (6x1)(1x3)A simply becomes (1x3)A - the (1x3) looks like a marker, but
because it's within a data section of another marker, it is not treated any
differently from the A that comes after it. It has a decompressed length of 6.
- X(8x2)(3x3)ABCY becomes X(3x3)ABC(3x3)ABCY (for a decompressed length of
18), because the decompressed data from the (8x2) marker (the (3x3)ABC) is
skipped and not processed further.
What is the decompressed length of the file (your puzzle input)? Don't count
whitespace.
--- Part Two ---
Apparently, the file actually uses version two of the format.
In version two, the only difference is that markers within decompressed data
are decompressed. This, the documentation explains, provides much more
substantial compression capabilities, allowing many-gigabyte files to be stored
in only a few kilobytes.
For example:
- (3x3)XYZ still becomes XYZXYZXYZ, as the decompressed section contains no
markers.
- X(8x2)(3x3)ABCY becomes XABCABCABCABCABCABCY, because the decompressed data
from the (8x2) marker is then further decompressed, thus triggering the
(3x3) marker twice for a total of six ABC sequences.
- (27x12)(20x12)(13x14)(7x10)(1x12)A decompresses into a string of A repeated
241920 times.
- (25x3)(3x3)ABC(2x3)XY(5x2)PQRSTX(18x9)(3x2)TWO(5x7)SEVEN becomes 445
characters long.
Unfortunately, the computer you brought probably doesn't have enough memory to
actually decompress the file; you'll have to come up with another way to get
its decompressed length.
What is the decompressed length of the file using this improved format?
*/
#include <cassert>
#include <iostream>
#include <sstream>
#include "day9.h"
#include "main.h"
size_t DecompressedSize( CompressionType compType, std::string& s ) {
size_t index = 0;
size_t size = 0;
do {
size_t p1 = s.find( '(', index );
if ( p1 == std::string::npos ) {
size += s.size();
s.clear();
return size;
}
size += p1;
s.erase( 0, p1 );
p1 = 0;
size_t p2 = s.find( ')', p1+1 );
// Create parser with YxZ and parse it.
std::istringstream parser( std::string( s, p1 + 1, p2 - p1 - 1 ) );
size_t repeatLength;
parser >> repeatLength;
assert( parser.peek() == 'x' );
parser.get();
assert( parser );
size_t repeatCount;
parser >> repeatCount;
assert( parser );
// Remove YxZ.
s.erase( p1, p2 - p1 + 1 );
// Set index to beginning of text to duplicate.
index = p1;
// Duplicate the string repeatCount-1 times. Insert new copies before
// exiting copies.
for ( size_t count = 0; count < repeatCount - 1; count++ ) {
s.insert( index + repeatLength, s, index, repeatLength );
}
// Advance over just expanded text.
if ( compType == CompressionType::NON_RECURSIVE ) {
index += repeatLength * repeatCount;
}
} while ( true );
}
int mainfunc( std::istream& is, std::ostream& os, Part part ) {
std::string input;
getline( is, input );
assert( is );
size_t size = DecompressedSize( part == Part::PART1 ?
CompressionType::NON_RECURSIVE :
CompressionType::RECURSIVE, input );
os << size << std::endl;
return 0;
}