From 89c45432152ebaef31d8a8a78a0138861cb6fbbc Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 20 Nov 2024 19:25:54 +0100 Subject: [PATCH] feat: add day 8 --- README.md | 3 +- data/examples/08.txt | 4 ++ src/bin/08.rs | 158 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 data/examples/08.txt create mode 100644 src/bin/08.rs diff --git a/README.md b/README.md index 52a9620..7905173 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,9 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www. | [Day 5](./src/bin/05.rs) | `5.1s` | `11.7s` | | [Day 6](./src/bin/06.rs) | `384.1µs` | `396.5µs` | | [Day 7](./src/bin/07.rs) | `1.5ms` | `1.3ms` | +| [Day 8](./src/bin/08.rs) | `132.9ms` | `-` | -**Total: 17199.36ms** +**Total: 17332.26ms** --- diff --git a/data/examples/08.txt b/data/examples/08.txt new file mode 100644 index 0000000..a9df2bc --- /dev/null +++ b/data/examples/08.txt @@ -0,0 +1,4 @@ +rect 3x2 +rotate column x=1 by 1 +rotate row y=0 by 4 +rotate column x=1 by 1 diff --git a/src/bin/08.rs b/src/bin/08.rs new file mode 100644 index 0000000..9624ff3 --- /dev/null +++ b/src/bin/08.rs @@ -0,0 +1,158 @@ +advent_of_code::solution!(8); + +use regex::Regex; + +const SCREEN_HEIGHT: usize = 6; +const SCREEN_WIDTH: usize = 50; + +const SCREEN_TOTAL: usize = SCREEN_HEIGHT * SCREEN_WIDTH; + +#[derive(Debug)] +enum Ins { + Rect { w: u8, h: u8 }, + RotateCol { col: u8, nb: u8 }, + RotateRow { row: u8, nb: u8 }, +} + +impl TryFrom<&str> for Ins { + type Error = String; + fn try_from(input: &str) -> Result { + let rect_reg = Regex::new(r"^rect (\d+)x(\d+)$").unwrap(); + let rotate_row_reg = Regex::new(r"^rotate row y=(\d+) by (\d+)").unwrap(); + let rotate_col_reg = Regex::new(r"^rotate column x=(\d+) by (\d+)").unwrap(); + + if let Some(captures) = rect_reg.captures(input) { + let (_, [w, h]) = captures.extract(); + return Ok(Ins::Rect { + w: w.parse::().unwrap(), + h: h.parse::().unwrap(), + }); + } + if let Some(captures) = rotate_row_reg.captures(input) { + let (_, [row, nb]) = captures.extract(); + return Ok(Ins::RotateRow { + row: row.parse::().unwrap(), + nb: nb.parse::().unwrap(), + }); + } + if let Some(captures) = rotate_col_reg.captures(input) { + let (_, [col, nb]) = captures.extract(); + return Ok(Ins::RotateCol { + col: col.parse::().unwrap(), + nb: nb.parse::().unwrap(), + }); + } + Err(format!("Couldn't parse input {:?}", input)) + } +} + +struct Screen { + display: [bool; SCREEN_TOTAL], +} + +impl Screen { + fn new() -> Self { + Self { + display: [false; SCREEN_TOTAL], + } + } + + fn get_row(&self, row: usize) -> String { + let start_offset = row * SCREEN_WIDTH; + let end_offset = start_offset + SCREEN_WIDTH; + self.display[start_offset..end_offset] + .iter() + .map(|b| match b { + true => '#', + false => '.', + }) + .collect::() + } + + fn draw_rect(&mut self, w: u8, h: u8) { + for j in 0..h { + for i in 0..w { + self.display[i as usize + (j as usize * SCREEN_WIDTH)] = true; + } + } + } + + fn rotate_col(&mut self, col: u8, nb: u8) { + let old_display = self.display; + let start_index: usize = col as usize; + for i in 0..SCREEN_HEIGHT { + let source = (SCREEN_WIDTH * i) % SCREEN_TOTAL; + let target = (SCREEN_WIDTH * (i + nb as usize)) % SCREEN_TOTAL; + self.display[target + start_index] = old_display[source + start_index]; + } + } + + fn rotate_row(&mut self, row: u8, nb: u8) { + let old_display = self.display; + let start_index: usize = row as usize * SCREEN_WIDTH; + for i in 0..SCREEN_WIDTH { + let target = (i + nb as usize) % SCREEN_WIDTH; + self.display[target + start_index] = old_display[start_index + i]; + } + } + + fn update(&mut self, instruction: Ins) { + match instruction { + Ins::Rect { w, h } => self.draw_rect(w, h), + Ins::RotateCol { col, nb } => self.rotate_col(col, nb), + Ins::RotateRow { row, nb } => self.rotate_row(row, nb), + }; + } + + fn lit(self) -> usize { + self.display.iter().filter(|p| **p).count() + } +} + +impl std::fmt::Debug for Screen { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + writeln!(formatter, "Screen Display:")?; + for row in 0..SCREEN_HEIGHT { + writeln!(formatter, "{}", self.get_row(row))?; + } + Ok(()) + } +} + +fn get_instructions(input: &str) -> impl Iterator + '_ { + input + .strip_suffix("\n") + .unwrap_or(input) + .split("\n") + .flat_map(Ins::try_from) +} + +pub fn part_one(input: &str) -> Option { + let mut screen = Screen::new(); + get_instructions(input).for_each(|i| screen.update(i)); + println!("End state\n{:?}", screen); + + screen.lit().into() +} + +pub fn part_two(_input: &str) -> Option { + // Well... Manually entered from the output of P1... + None +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_part_one() { + let result = part_one(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(6)); + } + + #[test] + fn test_part_two() { + let result = part_two(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, None); + } +}