-
Notifications
You must be signed in to change notification settings - Fork 0
/
day21.cpp
244 lines (189 loc) · 5.95 KB
/
day21.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
/*
--- Day 21: Fractal Art ---
You find a program trying to generate some art. It uses a strange process
that involves repeatedly enhancing the detail of an image through a set of
rules.
The image consists of a two-dimensional square grid of pixels that are
either on (#) or off (.). The program always begins with this pattern:
.#.
..#
###
Because the pattern is both 3 pixels wide and 3 pixels tall, it is said to
have a size of 3.
Then, the program repeats the following process:
- If the size is evenly divisible by 2, break the pixels up into 2x2
squares, and convert each 2x2 square into a 3x3 square by following
the corresponding enhancement rule.
- Otherwise, the size is evenly divisible by 3; break the pixels up into
3x3 squares, and convert each 3x3 square into a 4x4 square by
following the corresponding enhancement rule.
Because each square of pixels is replaced by a larger one, the image gains
pixels and so its size increases.
The artist's book of enhancement rules is nearby (your puzzle input);
however, it seems to be missing rules. The artist explains that sometimes,
one must rotate or flip the input pattern to find a match. (Never rotate or
flip the output pattern, though.) Each pattern is written concisely: rows
are listed as single units, ordered top-down, and separated by slashes. For
example, the following rules correspond to the adjacent patterns:
../.# = ..
.#
.#.
.#./..#/### = ..#
###
#..#
#..#/..../#..#/.##. = ....
#..#
.##.
When searching for a rule to use, rotate and flip the pattern as necessary.
For example, all of the following patterns match the same rule:
.#. .#. #.. ###
..# #.. #.# ..#
### ### ##. .#.
Suppose the book contained the following two rules:
../.# => ##./#../...
.#./..#/### => #..#/..../..../#..#
As before, the program begins with this pattern:
.#.
..#
###
The size of the grid (3) is not divisible by 2, but it is divisible by 3.
It divides evenly into a single square; the square matches the second rule
which produces:
#..#
....
....
#..#
The size of this enhanced grid (4) is evenly divisible by 2, so that rule
is used. It divides evenly into four squares:
#.|.#
..|..
--+--
..|..
#.|.#
Each of these squares matches the same rule (../.# => ##./#../...), three
of which require some flipping and rotation to line up with the rule. The
output for the rule is the same in all four cases:
##.|##.
#..|#..
...|...
---+---
##.|##.
#..|#..
...|...
Finally, the squares are joined into a new grid:
##.##.
#..#..
......
##.##.
#..#..
......
Thus, after 2 iterations, the grid contains 12 pixels that are on.
How many pixels stay on after 5 iterations?
--- Part Two ---
How many pixels stay on after 18 iterations?
*/
#include <algorithm>
#include <cassert>
#include <iostream>
#include <list>
#include <unordered_map>
#include <sstream>
#include <utility>
#include "day21.h"
#include "main.h"
using namespace std;
std::ostream& operator<<( std::ostream& os, const Picture& grid ) {
grid.print( os );
return os;
}
class Rules : public unordered_map<Pixels,Pixels> {
public:
void insertRule( Pixels oldPixels, Pixels newPixels ) {
auto iter = find( oldPixels );
if ( iter == end() ) {
insert( { oldPixels, newPixels } );
} else {
// If the old pixel pattern exists then the new pixels must be the
// same if the input rules are valid.
assert( newPixels == iter->second );
}
}
};
ostream& operator<<( ostream& os, const Rules& rules ) {
for ( const auto& rule : rules ) {
os << rule.first.getString() << " => " << rule.second.getString()
<< "\n";
}
return os;
}
static void addRule( Rules& rules,
const Pixels& oldPixels,
const Pixels& newPixels ) {
{
Pixels tmpPixels { oldPixels };
rules.insertRule( tmpPixels, newPixels );
tmpPixels.mirrorHoriz();
rules.insertRule( tmpPixels, newPixels );
tmpPixels.mirrorHoriz();
tmpPixels.rotateCCW();
rules.insertRule( tmpPixels, newPixels );
tmpPixels.mirrorHoriz();
rules.insertRule( tmpPixels, newPixels );
tmpPixels.mirrorHoriz();
tmpPixels.rotateCCW();
rules.insertRule( tmpPixels, newPixels );
tmpPixels.mirrorHoriz();
rules.insertRule( tmpPixels, newPixels );
tmpPixels.mirrorHoriz();
tmpPixels.rotateCCW();
rules.insertRule( tmpPixels, newPixels );
tmpPixels.mirrorHoriz();
rules.insertRule( tmpPixels, newPixels );
tmpPixels.mirrorHoriz();
}
}
static const Pixels initialPixels { ".#./..#/###" };
int simulate( istream& is, ostream& os, Part part, const unsigned iterations ) {
string line;
Rules rules;
while ( getline( is, line ) ) {
istringstream parser( line );
string oldPixels, newPixels;
parser >> oldPixels;
parser.ignore( 100, '>' );
parser >> newPixels;
assert( parser );
addRule( rules, oldPixels, newPixels );
}
Picture grid { { { initialPixels } } };
for ( unsigned iteration = 0; iteration < iterations; iteration++ ) {
grid.flatten();
grid.reduce();
// Walk grid
for ( auto& row : grid ) {
for ( auto& subgrid : row ) {
auto iterRule = rules.find( subgrid );
assert( iterRule != rules.end() );
subgrid = iterRule->second;
}
}
}
// Walk grid and count pixels.
size_t count=0;
size_t numOn = 0;
for ( auto& row : grid ) {
for ( auto& subgrid : row ) {
numOn += subgrid.numMatching( '#' );
count++;
}
}
os << numOn << endl;
return 0;
}
int mainfunc( istream& is, ostream& os, Part part ) {
if ( part == Part::PART1 ) {
return simulate( is, os, part, 5 );
} else {
return simulate( is, os, part, 18 );
}
}