day-13 part 1 done
This commit is contained in:
11
2023/Cargo.lock
generated
11
2023/Cargo.lock
generated
@@ -121,6 +121,17 @@ dependencies = [
|
||||
"rstest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "day-13"
|
||||
version = "2023.0.0"
|
||||
dependencies = [
|
||||
"glam",
|
||||
"itertools",
|
||||
"nom",
|
||||
"nom_locate",
|
||||
"rstest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "day-2"
|
||||
version = "2023.0.0"
|
||||
|
||||
17
2023/day-13/Cargo.toml
Normal file
17
2023/day-13/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "day-13"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nom = { workspace = true }
|
||||
itertools = {workspace = true }
|
||||
glam.workspace = true
|
||||
nom_locate.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
rstest.workspace = true
|
||||
4
2023/day-13/src/lib.rs
Normal file
4
2023/day-13/src/lib.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod part1;
|
||||
pub use crate::part1::*;
|
||||
pub mod part2;
|
||||
pub use crate::part2::*;
|
||||
12
2023/day-13/src/main.rs
Normal file
12
2023/day-13/src/main.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
use day_13::part1;
|
||||
use day_13::part2;
|
||||
|
||||
fn main() {
|
||||
let input = include_str!("./input.txt");
|
||||
let part1_result = part1(input);
|
||||
println!("part 1: {part1_result}");
|
||||
let part2_result = part2(input);
|
||||
println!("part 2: {part2_result}");
|
||||
}
|
||||
147
2023/day-13/src/part1.rs
Normal file
147
2023/day-13/src/part1.rs
Normal file
@@ -0,0 +1,147 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use glam::UVec2;
|
||||
use nom::{
|
||||
bytes::complete::is_a,
|
||||
character::complete,
|
||||
multi::separated_list1,
|
||||
IResult, sequence::tuple,
|
||||
};
|
||||
|
||||
struct Drawing {
|
||||
pub size: UVec2,
|
||||
pub mounds: HashSet<UVec2>,
|
||||
}
|
||||
|
||||
impl Drawing {
|
||||
fn process(&self) -> u32 {
|
||||
let (max_col, max_row) = self.size.into();
|
||||
let col_score = (1..max_col )
|
||||
.filter_map(|reflect_col| {
|
||||
let span = reflect_col.min(max_col - reflect_col);
|
||||
(self.mounds
|
||||
.iter()
|
||||
.filter(|mound| mound.x + span >= reflect_col && mound.x < reflect_col)
|
||||
.map(|mound| (2* reflect_col - mound.x - 1, mound.y).into())
|
||||
.all(|mound_reflect| self.mounds.get(&mound_reflect).is_some())
|
||||
&&
|
||||
self.mounds
|
||||
.iter()
|
||||
.filter(|mound|mound.x < reflect_col + span && mound.x >= reflect_col)
|
||||
.map(|mound| ( 2*reflect_col - mound.x - 1,mound.y).into())
|
||||
.all(|mound_reflect| self.mounds.get(&mound_reflect).is_some())
|
||||
)
|
||||
.then_some(reflect_col)
|
||||
})
|
||||
.sum::<u32>();
|
||||
let row_score = (1..max_row )
|
||||
.filter_map(|reflect_row| {
|
||||
let span = reflect_row.min(max_row - reflect_row);
|
||||
(self.mounds
|
||||
.iter()
|
||||
.filter(|mound| mound.y + span >= reflect_row && mound.y < reflect_row)
|
||||
.map(|mound| (mound.x, 2 * reflect_row - mound.y - 1).into())
|
||||
.all(|mound_reflect| self.mounds.get(&mound_reflect).is_some())
|
||||
&&
|
||||
self.mounds
|
||||
.iter()
|
||||
.filter(|mound|mound.y < reflect_row + span && mound.y >= reflect_row)
|
||||
.map(|mound| (mound.x, 2*reflect_row - mound.y - 1).into())
|
||||
.all(|mound_reflect| self.mounds.get(&mound_reflect).is_some())
|
||||
)
|
||||
.then_some(reflect_row)
|
||||
})
|
||||
.sum::<u32>()
|
||||
* 100;
|
||||
col_score + row_score
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn part1(_input: &str) -> String {
|
||||
let (_, drawings) = parse_input(_input).expect("aoc always valid");
|
||||
drawings.iter().map(Drawing::process).sum::<u32>().to_string()
|
||||
}
|
||||
|
||||
fn parse_drawing(input: &str) -> IResult<&str, Drawing> {
|
||||
let (input, rows) = separated_list1(complete::line_ending, is_a(".#"))(input)?;
|
||||
let max_rows = u32::try_from(rows.len()).expect("shouldn't be that big");
|
||||
let max_cols = u32::try_from(rows[0].len()).expect("shouldn't be that big");
|
||||
let size = UVec2::from((max_cols, max_rows));
|
||||
let mounds = rows
|
||||
.iter()
|
||||
.enumerate()
|
||||
.flat_map(|y| {
|
||||
y.1.chars().enumerate().map(move |x| {
|
||||
(
|
||||
u32::try_from(x.0).expect("should be 32"),
|
||||
u32::try_from(y.0).expect("should not fail"),
|
||||
x.1,
|
||||
)
|
||||
})
|
||||
})
|
||||
.filter_map(|(x, y, mound)| (mound == '#').then_some(UVec2::from((x, y)) ))
|
||||
.collect();
|
||||
Ok((input, Drawing { size, mounds }))
|
||||
}
|
||||
|
||||
fn parse_input(input: &str) -> IResult<&str, Vec<Drawing>>{
|
||||
separated_list1(tuple((complete::line_ending, complete::line_ending)), parse_drawing)(input)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use rstest::rstest;
|
||||
|
||||
#[rstest]
|
||||
#[case(
|
||||
"#.##..##.
|
||||
..#.##.#.
|
||||
##......#
|
||||
##......#
|
||||
..#.##.#.
|
||||
..##..##.
|
||||
#.#.##.#.",
|
||||
5
|
||||
)]
|
||||
#[case(
|
||||
"#...##..#
|
||||
#....#..#
|
||||
..##..###
|
||||
#####.##.
|
||||
#####.##.
|
||||
..##..###
|
||||
#....#..#",
|
||||
400
|
||||
)]
|
||||
fn board_test(#[case] input: &str, #[case] expected: u32) {
|
||||
let (_, drawing) = parse_drawing(input).expect("Parsing should work");
|
||||
assert_eq!(drawing.process(), expected);
|
||||
}
|
||||
|
||||
const INPUT: &str = "#.##..##.
|
||||
..#.##.#.
|
||||
##......#
|
||||
##......#
|
||||
..#.##.#.
|
||||
..##..##.
|
||||
#.#.##.#.
|
||||
|
||||
#...##..#
|
||||
#....#..#
|
||||
..##..###
|
||||
#####.##.
|
||||
#####.##.
|
||||
..##..###
|
||||
#....#..#";
|
||||
|
||||
#[test]
|
||||
fn part1_works() {
|
||||
let result = part1(INPUT);
|
||||
assert_eq!(result, "405".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
20
2023/day-13/src/part2.rs
Normal file
20
2023/day-13/src/part2.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
#[must_use]
|
||||
pub fn part2 (_input: &str) -> String {
|
||||
"Not Finished".to_string()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
const INPUT: &str = "";
|
||||
|
||||
#[test]
|
||||
fn part2_works() {
|
||||
let result = part2(INPUT);
|
||||
assert_eq!(result, "Not Finished".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user