advent_of_code/year2016/
day08.rs1use crate::common::character_recognition::{CHAR_HEIGHT, recognize};
2use crate::input::Input;
3
4struct Screen {
5 pixels: [bool; Self::WIDTH * CHAR_HEIGHT],
6}
7
8impl Screen {
9 const WIDTH: usize = 50;
10
11 const fn get_pixel(&self, x: usize, y: usize) -> bool {
12 self.pixels[y * Self::WIDTH + x]
13 }
14
15 const fn set_pixel(&mut self, x: usize, y: usize, on: bool) {
16 self.pixels[y * Self::WIDTH + x] = on;
17 }
18
19 fn turn_on_rect(&mut self, width: usize, height: usize) {
20 for x in 0..width {
21 for y in 0..height {
22 self.set_pixel(x, y, true);
23 }
24 }
25 }
26
27 fn rotate_row(&mut self, row: usize, amount: usize) {
28 let mut new_row = [false; Self::WIDTH];
29 for x in 0..Self::WIDTH {
30 new_row[(x + amount) % Self::WIDTH] = self.get_pixel(x, row);
31 }
32 for (x, &on) in new_row.iter().enumerate() {
33 self.set_pixel(x, row, on);
34 }
35 }
36
37 fn rotate_col(&mut self, col: usize, amount: usize) {
38 let mut new_col = [false; CHAR_HEIGHT];
39 for y in 0..CHAR_HEIGHT {
40 new_col[(y + amount) % CHAR_HEIGHT] = self.get_pixel(col, y);
41 }
42
43 for (y, &on) in new_col.iter().enumerate() {
44 self.set_pixel(col, y, on);
45 }
46 }
47
48 const fn new() -> Self {
49 Self {
50 pixels: [false; Self::WIDTH * CHAR_HEIGHT],
51 }
52 }
53}
54
55pub fn solve(input: &Input) -> Result<String, String> {
56 let mut screen = Screen::new();
57 for line in input.text.lines() {
58 if let Some(after) = line.strip_prefix("rect ") {
59 let (part1, part2) = after
60 .split_once('x')
61 .ok_or_else(|| "Invalid input".to_string())?;
62 let width = part1.parse::<usize>().map_err(|_| "Invalid input")?;
63 let height = part2.parse::<usize>().map_err(|_| "Invalid input")?;
64 screen.turn_on_rect(width, height);
65 } else if let Some(after) = line.strip_prefix("rotate row y=") {
66 let (part1, part2) = after
67 .split_once(" by ")
68 .ok_or_else(|| "invalid input".to_string())?;
69 let row_to_rotate = part1.parse::<usize>().map_err(|_| "Invalid input")?;
70 let rotation_amount = part2.parse::<usize>().map_err(|_| "Invalid input")?;
71 screen.rotate_row(row_to_rotate, rotation_amount);
72 } else if let Some(after) = line.strip_prefix("rotate column x=") {
73 let (part1, part2) = after
74 .split_once(" by ")
75 .ok_or_else(|| "invalid input".to_string())?;
76 let col_to_rotate = part1.parse::<usize>().map_err(|_| "Invalid input")?;
77 let rotation_amount = part2.parse::<usize>().map_err(|_| "Invalid input")?;
78 screen.rotate_col(col_to_rotate, rotation_amount);
79 } else {
80 return Err("Invalid line".to_string());
81 }
82 }
83
84 if input.is_part_one() {
85 Ok(screen.pixels.iter().filter(|&&p| p).count().to_string())
86 } else {
87 recognize(&screen.pixels)
88 }
89}
90
91#[test]
92pub fn tests() {
93 let real_input = include_str!("day08_input.txt");
94 test_part_one!(real_input => "128".to_string());
95 test_part_two!(real_input => "EOARGPHYAO".to_string());
96}