1use crate::util::iter::*;
64use crate::util::parse::*;
65
66enum Command {
67 On,
68 Off,
69 Toggle,
70}
71
72impl Command {
73 fn from(bytes: &[u8]) -> Command {
74 match bytes[6] {
75 b'n' => Command::On,
76 b'f' => Command::Off,
77 b' ' => Command::Toggle,
78 _ => unreachable!(),
79 }
80 }
81}
82
83struct Rectangle {
84 x1: u32,
85 x2: u32,
86 y1: u32,
87 y2: u32,
88}
89
90impl Rectangle {
91 fn from([x1, y1, x2, y2]: [u32; 4]) -> Rectangle {
92 Rectangle { x1, x2, y1, y2 }
93 }
94
95 fn contains(&self, x: u32, y: u32) -> bool {
96 self.x1 <= x && x <= self.x2 && self.y1 <= y && y <= self.y2
97 }
98}
99
100struct Instruction {
101 command: Command,
102 rectangle: Rectangle,
103}
104
105impl Instruction {
106 fn from((bytes, points): (&[u8], [u32; 4])) -> Instruction {
107 let command = Command::from(bytes);
108 let rectangle = Rectangle::from(points);
109 Instruction { command, rectangle }
110 }
111}
112
113pub fn parse(input: &str) -> (u32, u32) {
114 let first = input.lines().map(str::as_bytes);
115 let second = input.iter_unsigned().chunk::<4>();
116 let instructions: Vec<_> = first.zip(second).map(Instruction::from).collect();
117
118 let mut xs = vec![0, 1000];
119 let mut ys = vec![0, 1000];
120
121 for instruction in &instructions {
122 let Rectangle { x1, x2, y1, y2 } = instruction.rectangle;
123 xs.push(x1);
124 xs.push(x2 + 1);
125 ys.push(y1);
126 ys.push(y2 + 1);
127 }
128
129 xs.sort_unstable();
130 xs.dedup();
131 ys.sort_unstable();
132 ys.dedup();
133
134 let mut x_index_from = [0; 1001];
135 for (i, &x) in xs.iter().enumerate() {
136 x_index_from[x as usize] = i;
137 }
138
139 let mut y_index_from = [0; 1001];
140 for (i, &y) in ys.iter().enumerate() {
141 y_index_from[y as usize] = i;
142 }
143
144 let stride = xs.len();
145 let capacity = stride * ys.len();
146 let mut up = vec![false; capacity];
147 let mut left = vec![false; capacity];
148 let mut previous = vec![(false, 0); capacity];
149
150 for instruction in &instructions {
151 let Rectangle { x1, x2, y1, y2 } = instruction.rectangle;
152 let x1 = x_index_from[x1 as usize];
153 let x2 = x_index_from[(x2 + 1) as usize];
154 let y1 = y_index_from[y1 as usize];
155 let y2 = y_index_from[(y2 + 1) as usize];
156
157 for x in x1..(x2 + 1) {
158 up[stride * y1 + x] = true;
159 up[stride * y2 + x] = true;
160 }
161 for y in y1..(y2 + 1) {
162 left[stride * y + x1] = true;
163 left[stride * y + x2] = true;
164 }
165 }
166
167 let mut result1 = 0;
168 let mut result2 = 0;
169
170 for j in 0..ys.len() - 1 {
171 let y1 = ys[j];
172 let y2 = ys[j + 1];
173
174 for i in 0..xs.len() - 1 {
175 let x1 = xs[i];
176 let x2 = xs[i + 1];
177 let area = (x2 - x1) * (y2 - y1);
178 let index = stride * j + i;
179
180 let current = if i > 0 && !left[index] {
181 previous[index - 1]
182 } else if j > 0 && !up[index] {
183 previous[index - stride]
184 } else {
185 let mut light = false;
186 let mut brightness: u8 = 0;
187
188 for instruction in &instructions {
189 if instruction.rectangle.contains(x1, y1) {
190 match instruction.command {
191 Command::On => {
192 light = true;
193 brightness += 1;
194 }
195 Command::Off => {
196 light = false;
197 brightness = brightness.saturating_sub(1);
198 }
199 Command::Toggle => {
200 light = !light;
201 brightness += 2;
202 }
203 }
204 }
205 }
206
207 (light, brightness)
208 };
209
210 previous[index] = current;
211 if current.0 {
212 result1 += area;
213 }
214 result2 += current.1 as u32 * area;
215 }
216 }
217
218 (result1, result2)
219}
220
221pub fn part1(input: &(u32, u32)) -> u32 {
222 input.0
223}
224
225pub fn part2(input: &(u32, u32)) -> u32 {
226 input.1
227}