implement day 13

This commit is contained in:
Jan Christian Grünhage 2021-12-13 07:33:20 +01:00
parent 123c62f810
commit d0216fda25
4 changed files with 231 additions and 0 deletions

85
src/day_13/mod.rs Normal file
View file

@ -0,0 +1,85 @@
mod model;
mod parsing;
use aoc_runner_derive::{aoc, aoc_generator};
pub use model::{Fold, Grid, Input, Point};
use yap::IntoTokens;
#[aoc_generator(day13)]
pub fn parse_input(input: &str) -> Input {
parsing::parse_input(&mut input.into_tokens()).unwrap()
}
#[aoc(day13, part1)]
pub fn part1(input: &Input) -> usize {
let Input {
mut grid,
instructions,
} = input.clone();
grid.fold(instructions[0]);
grid.count()
}
#[aoc(day13, part2)]
pub fn part2(input: &Input) -> String {
let Input {
mut grid,
instructions,
} = input.clone();
for instruction in instructions {
grid.fold(instruction);
}
grid.to_string()
}
#[cfg(test)]
mod test {
use super::Input;
const EXAMPLE_INPUT: &str = "6,10
0,14
9,10
0,3
10,4
4,11
6,0
6,12
4,1
0,13
10,12
3,4
3,0
8,4
1,10
2,14
8,10
9,0
fold along y=7
fold along x=5";
const RESULT_PART_1: usize = 17;
#[test]
fn part1_example() {
let result = super::part1(&super::parse_input(EXAMPLE_INPUT));
assert_eq!(result, RESULT_PART_1);
}
#[test]
fn fold_twice() {
let Input {
mut grid,
instructions,
} = super::parse_input(EXAMPLE_INPUT);
grid.fold(instructions[0]);
assert_eq!(grid.count(), 17);
grid.fold(instructions[1]);
assert_eq!(grid.count(), 16);
}
#[test]
fn parse_example() {
super::parse_input(EXAMPLE_INPUT);
}
}

93
src/day_13/model.rs Normal file
View file

@ -0,0 +1,93 @@
use itertools::Itertools;
#[derive(Copy, Clone)]
pub struct Point {
pub x: usize,
pub y: usize,
}
impl Point {
fn get_bounds(points: &[Point]) -> Point {
let x = points.iter().map(|p| p.x).max().unwrap_or_default();
let y = points.iter().map(|p| p.y).max().unwrap_or_default();
Point { x, y }
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Fold {
X(usize),
Y(usize),
}
#[derive(Clone)]
pub struct Grid {
pub grid: Vec<Vec<bool>>,
}
impl Grid {
pub fn new(points: &[Point]) -> Self {
let bounds = Point::get_bounds(points);
let mut line = Vec::new();
for _ in 0..=bounds.x {
line.push(false)
}
let mut grid = Vec::new();
for _ in 0..=bounds.y {
grid.push(line.clone())
}
for Point { x, y } in points {
grid[*y][*x] = true;
}
Self { grid }
}
pub fn fold(&mut self, instruction: Fold) {
match instruction {
Fold::X(fold) => {
for y in 0..self.grid.len() {
for x in fold + 1..self.grid[y].len() {
self.grid[y][fold - (x - fold)] |= self.grid[y][x];
}
self.grid[y].truncate(fold)
}
}
Fold::Y(fold) => {
for y in fold + 1..self.grid.len() {
for x in 0..self.grid[0].len() {
self.grid[fold - (y - fold)][x] |= self.grid[y][x];
}
}
self.grid.truncate(fold)
}
}
}
pub fn count(&self) -> usize {
self.grid
.iter()
.flat_map(|line| line.iter())
.filter(|val| **val)
.count()
}
}
impl ToString for Grid {
fn to_string(&self) -> String {
self.grid
.iter()
.map(|line| {
line.iter()
.map(|val| if *val { "#" } else { "." })
.collect::<String>()
})
.join("\n")
}
}
#[derive(Clone)]
pub struct Input {
pub grid: Grid,
pub instructions: Vec<Fold>,
}

52
src/day_13/parsing.rs Normal file
View file

@ -0,0 +1,52 @@
use yap::Tokens;
use crate::parsing::{newline, parse_n, parse_number};
use super::{Fold, Grid, Input, Point};
pub fn parse_fold(tokens: &mut impl Tokens<Item = char>) -> Option<Fold> {
yap::one_of!(ts from tokens;
ts.tokens("fold along y=".chars()).then(|| parse_number(ts).map(Fold::Y)).flatten(),
ts.tokens("fold along x=".chars()).then(|| parse_number(ts).map(Fold::X)).flatten(),
)
}
pub fn parse_point(tokens: &mut impl Tokens<Item = char>) -> Option<Point> {
parse_n(tokens, |t| parse_number(t), |t| t.token(',')).map(|point: [usize; 2]| Point {
x: point[0],
y: point[1],
})
}
pub fn parse_input(tokens: &mut impl Tokens<Item = char>) -> Option<Input> {
let points: Vec<Point> = tokens.sep_by(|t| parse_point(t), |t| newline(t)).collect();
if points.is_empty() {
return None;
}
tokens.skip_many(|t| newline(t));
let instructions: Vec<Fold> = tokens.sep_by(|t| parse_fold(t), |t| newline(t)).collect();
if instructions.is_empty() {
return None;
}
let grid = Grid::new(&points);
Some(Input { grid, instructions })
}
#[cfg(test)]
mod test {
use yap::IntoTokens;
use crate::day_13::Fold;
#[test]
fn parse_fold() {
assert_eq!(
super::parse_fold(&mut "fold along y=7".into_tokens()),
Some(Fold::Y(7)),
);
assert_eq!(
super::parse_fold(&mut "fold along x=5".into_tokens()),
Some(Fold::X(5)),
);
}
}

View file

@ -14,5 +14,6 @@ pub mod day_09;
pub mod day_10;
pub mod day_11;
pub mod day_12;
pub mod day_13;
aoc_lib! { year = 2021 }