day 11 done

This commit is contained in:
Dylan Thies
2023-12-12 08:44:39 -05:00
parent 84769b2afa
commit 6a5d1d5454
8 changed files with 239 additions and 1 deletions

10
2023/Cargo.lock generated
View File

@@ -102,6 +102,16 @@ dependencies = [
"rstest", "rstest",
] ]
[[package]]
name = "day-11"
version = "2023.0.0"
dependencies = [
"glam",
"itertools",
"nom",
"nom_locate",
]
[[package]] [[package]]
name = "day-2" name = "day-2"
version = "2023.0.0" version = "2023.0.0"

View File

@@ -18,6 +18,7 @@ nom_locate= "4.2.0"
rstest = "0.18.2" rstest = "0.18.2"
rstest_reuse = "0.6.0" rstest_reuse = "0.6.0"
dhat = "0.3.2" dhat = "0.3.2"
glam = "0.24.2"
[profile.dhat] [profile.dhat]

View File

@@ -165,7 +165,6 @@ pub fn part2(input: &str) -> String {
}; };
let mut pieces = HashMap::new(); let mut pieces = HashMap::new();
//TODO might need to get the actual start type
pieces.insert(start_node.position, start_node_true_type); pieces.insert(start_node.position, start_node_true_type);
successors( successors(

14
2023/day-11/Cargo.toml Normal file
View File

@@ -0,0 +1,14 @@
[package]
name = "day-11"
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 }

4
2023/day-11/src/lib.rs Normal file
View File

@@ -0,0 +1,4 @@
pub mod part1;
pub use crate::part1::*;
pub mod part2;
pub use crate::part2::*;

12
2023/day-11/src/main.rs Normal file
View File

@@ -0,0 +1,12 @@
#![warn(clippy::all, clippy::pedantic)]
use day_11::part1;
use day_11::part2;
fn main() {
let input = include_str!("./input.txt");
let part1_result = part1(input);
println!("part 1: {part1_result}");
let part2_result = part2(input, 1_000_000);
println!("part 2: {part2_result}");
}

95
2023/day-11/src/part1.rs Normal file
View File

@@ -0,0 +1,95 @@
#![warn(clippy::all, clippy::pedantic)]
use glam::IVec2;
use itertools::Itertools;
use std::collections::HashSet;
#[must_use]
pub fn part1(input: &str) -> String {
let points = parse_input(input);
let ((min_x, min_y), (mut max_x, /*mut*/ max_y)) = points.iter().fold(
((i32::MAX, i32::MAX), (i32::MIN, i32::MIN)),
|((min_x, min_y), (max_x, max_y)), pos| {
let min_x = min_x.min(pos.x);
let min_y = min_y.min(pos.y);
let max_x = max_x.max(pos.x);
let max_y = max_y.max(pos.y);
((min_x, min_y), (max_x, max_y))
},
);
let mut modifier = 0;
let mut adjusted_points = HashSet::new();
for x in min_x..=max_x {
let column = (min_y..=max_y)
.filter_map(|y| points.get(&(x, y).into()))
.collect::<Vec<_>>();
if column.is_empty() {
modifier += 1;
}
for point in column {
adjusted_points.insert(*point + IVec2::new(modifier, 0));
}
}
max_x += modifier;
let mut modifier = 0;
let mut points = HashSet::new();
for y in min_y..=max_y {
let row = (min_x..=max_x)
.filter_map(|x| adjusted_points.get(&(x, y).into()))
.collect::<Vec<_>>();
if row.is_empty() {
modifier += 1;
}
for point in row {
points.insert(*point + IVec2::new(0, modifier));
}
}
//max_y += modifier;
(points
.iter()
.cartesian_product(points.iter())
.filter_map(|(a, b)| (a != b).then_some(*a - *b))
.map(|pos| pos.x.abs() + pos.y.abs())
.sum::<i32>()
/ 2)
.to_string()
}
fn parse_input(input: &str) -> HashSet<IVec2> {
input
.lines()
.enumerate()
.flat_map(|(y, line)| {
line.chars().enumerate().filter_map(move |(x, c)| {
(c != '.').then_some(IVec2::new(
i32::try_from(x).unwrap(),
i32::try_from(y).unwrap(),
))
})
})
.collect()
}
#[cfg(test)]
mod test {
use super::*;
const INPUT: &str = "...#......
.......#..
#.........
..........
......#...
.#........
.........#
..........
.......#..
#...#.....";
#[test]
fn part1_works() {
let result = part1(INPUT);
assert_eq!(result, "374".to_string());
}
}

103
2023/day-11/src/part2.rs Normal file
View File

@@ -0,0 +1,103 @@
#![warn(clippy::all, clippy::pedantic)]
use glam::I64Vec2;
use itertools::Itertools;
use std::collections::HashSet;
/// day 11 part 2 of aoc 2023
///
/// # Arguments
/// - input the input for today's puzzle
///
/// # Panics
/// panics whne it cannot parse the input OR when ever the number of game numbers is greater than
/// usize
#[must_use]
pub fn part2(input: &str, modr: i64) -> String {
let points = parse_input(input);
let ((min_x, min_y), (mut max_x, /*mut*/ max_y)) = points.iter().fold(
((i64::MAX, i64::MAX), (i64::MIN, i64::MIN)),
|((min_x, min_y), (max_x, max_y)), pos| {
let min_x = min_x.min(pos.x);
let min_y = min_y.min(pos.y);
let max_x = max_x.max(pos.x);
let max_y = max_y.max(pos.y);
((min_x, min_y), (max_x, max_y))
},
);
let mut modifier = 0;
let mut adjusted_points = HashSet::new();
for x in min_x..=max_x {
let column = (min_y..=max_y)
.filter_map(|y| points.get(&(x, y).into()))
.collect::<Vec<_>>();
if column.is_empty() {
modifier += modr-1;
}
for point in column {
adjusted_points.insert(*point + I64Vec2::new(modifier, 0));
}
}
max_x += modifier;
let mut modifier = 0;
let mut points = HashSet::new();
for y in min_y..=max_y {
let row = (min_x..=max_x)
.filter_map(|x| adjusted_points.get(&(x, y).into()))
.collect::<Vec<_>>();
if row.is_empty() {
modifier += modr-1;
}
for point in row {
points.insert(*point + I64Vec2::new(0, modifier));
}
}
//max_y += modifier;
(points
.iter()
.cartesian_product(points.iter())
.filter_map(|(a, b)| (*a != *b).then_some(*a-*b))
.map(|a| u64::try_from(a.x.abs()+a.y.abs()).unwrap())
.sum::<u64>()
/ 2)
.to_string()
}
fn parse_input(input: &str) -> HashSet<I64Vec2> {
input
.lines()
.enumerate()
.flat_map(|(y, line)| {
line.chars().enumerate().filter_map(move |(x, c)| {
(c != '.').then_some(I64Vec2::new(
i64::try_from(x).unwrap(),
i64::try_from(y).unwrap(),
))
})
})
.collect()
}
#[cfg(test)]
mod test {
use super::*;
const INPUT: &str = "...#......
.......#..
#.........
..........
......#...
.#........
.........#
..........
.......#..
#...#.....";
#[test]
fn part2_works() {
let result = part2(INPUT, 10);
assert_eq!(result, "1030".to_string());
}
}