Completed day 10. Not wildly happy with my runtime

This commit is contained in:
Connor Johnstone
2023-12-11 00:39:11 -07:00
parent b60591ea38
commit 8b270c236b
13 changed files with 1392 additions and 7 deletions

216
day_10/src/lib.rs Normal file
View File

@@ -0,0 +1,216 @@
// use nom::{
// character::complete,
// multi::separated_list1,
// IResult,
// };
use std::collections::HashMap;
use ndarray::prelude::*;
#[derive(Debug)]
struct Point {
x: usize,
y: usize,
}
#[derive(Debug, PartialEq)]
enum Direction {
North,
South,
East,
West,
}
pub fn part1(input: &str) -> String {
let node_mapping = HashMap::from([
('|', Some([Direction::North, Direction::South])),
('-', Some([Direction::East, Direction::West])),
('L', Some([Direction::North, Direction::East])),
('J', Some([Direction::North, Direction::West])),
('7', Some([Direction::South, Direction::West])),
('F', Some([Direction::South, Direction::East])),
('.', None),
]);
let mut current_nodes = vec![input.lines().enumerate().find_map(|(y,line)| {
line.chars().position(|character| {character == 'S'}).and_then(|x| {Some(Point{x, y})})
}).unwrap()];
let rows = input.lines().collect::<Vec<_>>().len();
let columns = input.lines().next().unwrap().len();
let mut count_map: Array2<usize> = Array::zeros((rows, columns));
let mut num_steps = 0;
while current_nodes.len() > 0 {
let mut next_nodes = vec![];
current_nodes.iter().for_each(|point| {
let character = input.lines().nth(point.y).unwrap().chars().nth(point.x).unwrap();
if character == 'S' {
if point.y != 0 {
let next_character = input.lines().nth(point.y-1).unwrap().chars().nth(point.x).unwrap();
if ['|','7','F'].contains(&next_character) {
next_nodes.push(Point{x: point.x, y: point.y-1});
}
}
if point.x != columns-1 {
let next_character = input.lines().nth(point.y).unwrap().chars().nth(point.x+1).unwrap();
if ['-','7','J'].contains(&next_character) {
next_nodes.push(Point{x: point.x+1, y: point.y});
}
}
if point.y != rows-1 {
let next_character = input.lines().nth(point.y+1).unwrap().chars().nth(point.x).unwrap();
if ['|','L','J'].contains(&next_character) {
next_nodes.push(Point{x: point.x, y: point.y+1});
}
}
if point.x != 0 {
let next_character = input.lines().nth(point.y).unwrap().chars().nth(point.x-1).unwrap();
if ['-','F','L'].contains(&next_character) {
next_nodes.push(Point{x: point.x-1, y: point.y});
}
}
} else if let Some(dirs) = node_mapping.get(&character).unwrap() {
if dirs.contains(&Direction::North) && point.y != 0 {
next_nodes.push(Point{x: point.x, y: point.y-1});
}
if dirs.contains(&Direction::East) && point.x != columns-1 {
next_nodes.push(Point{x: point.x+1, y: point.y});
}
if dirs.contains(&Direction::South) && point.y != rows-1 {
next_nodes.push(Point{x: point.x, y: point.y+1});
}
if dirs.contains(&Direction::West) && point.x != 0 {
next_nodes.push(Point{x: point.x-1, y: point.y});
}
};
});
num_steps += 1;
current_nodes = vec![];
next_nodes.iter().for_each(|point| {
if count_map[[point.y, point.x]] == 0 {
count_map[[point.y, point.x]] = num_steps;
current_nodes.push(Point{x: point.x, y: point.y});
}
});
}
count_map.iter().max().unwrap().to_string()
}
pub fn part2(input: &str) -> String {
let node_mapping = HashMap::from([
('|', Some([Direction::North, Direction::South])),
('-', Some([Direction::East, Direction::West])),
('L', Some([Direction::North, Direction::East])),
('J', Some([Direction::North, Direction::West])),
('7', Some([Direction::South, Direction::West])),
('F', Some([Direction::South, Direction::East])),
('.', None),
]);
let mut current_nodes = vec![input.lines().enumerate().find_map(|(y,line)| {
line.chars().position(|character| {character == 'S'}).and_then(|x| {Some(Point{x, y})})
}).unwrap()];
let rows = input.lines().collect::<Vec<_>>().len();
let columns = input.lines().next().unwrap().len();
let mut count_map: Array2<usize> = Array::zeros((rows, columns));
let mut num_steps = 0;
while current_nodes.len() > 0 {
let mut next_nodes = vec![];
current_nodes.iter().for_each(|point| {
let character = input.lines().nth(point.y).unwrap().chars().nth(point.x).unwrap();
if character == 'S' {
if point.y != 0 {
let next_character = input.lines().nth(point.y-1).unwrap().chars().nth(point.x).unwrap();
if ['|','7','F'].contains(&next_character) {
next_nodes.push(Point{x: point.x, y: point.y-1});
}
}
if point.x != columns-1 {
let next_character = input.lines().nth(point.y).unwrap().chars().nth(point.x+1).unwrap();
if ['-','7','J'].contains(&next_character) {
next_nodes.push(Point{x: point.x+1, y: point.y});
}
}
if point.y != rows-1 {
let next_character = input.lines().nth(point.y+1).unwrap().chars().nth(point.x).unwrap();
if ['|','L','J'].contains(&next_character) {
next_nodes.push(Point{x: point.x, y: point.y+1});
}
}
if point.x != 0 {
let next_character = input.lines().nth(point.y).unwrap().chars().nth(point.x-1).unwrap();
if ['-','F','L'].contains(&next_character) {
next_nodes.push(Point{x: point.x-1, y: point.y});
}
}
} else if let Some(dirs) = node_mapping.get(&character).unwrap() {
if dirs.contains(&Direction::North) && point.y != 0 {
next_nodes.push(Point{x: point.x, y: point.y-1});
}
if dirs.contains(&Direction::East) && point.x != columns-1 {
next_nodes.push(Point{x: point.x+1, y: point.y});
}
if dirs.contains(&Direction::South) && point.y != rows-1 {
next_nodes.push(Point{x: point.x, y: point.y+1});
}
if dirs.contains(&Direction::West) && point.x != 0 {
next_nodes.push(Point{x: point.x-1, y: point.y});
}
};
});
num_steps += 1;
current_nodes = vec![];
next_nodes.iter().for_each(|point| {
if count_map[[point.y, point.x]] == 0 {
count_map[[point.y, point.x]] = num_steps;
current_nodes.push(Point{x: point.x, y: point.y});
}
});
}
let s_position = input.lines().enumerate().find_map(|(y,line)| {
line.chars().position(|character| {character == 'S'}).and_then(|x| {Some(Point{x, y})})
}).unwrap();
count_map[[s_position.y, s_position.x]] = 1;
let mut inside_points = 0;
for y in 0..rows {
for x in 0..columns {
if count_map[[y,x]] == 0 { // It's not a part of the main loop
// Now we go in one direction
let mut sum = 0.0_f32;
let mut count_f = 0_i32;
let mut count_l = 0_i32;
let mut count_7 = 0_i32;
let mut count_j = 0_i32;
for new_y in (0..y).rev() {
// And we keep moving in that direction
// If we reach a part of the pipe
if count_map[[new_y,x]] != 0 {
// We can add either a half or full count
let next_character = input.lines().nth(new_y).unwrap().chars().nth(x).unwrap();
if ['7', 'S'].contains(&next_character) {
count_7 += 1;
} else if next_character == 'J' {
count_j += 1;
} else if next_character == 'L' {
count_l += 1;
} else if next_character == 'F' {
count_f += 1;
} else if next_character == '-' {
sum += 1.0;
}
}
}
count_f = (count_f - count_l).abs(); // L's cancel with F
count_7 = (count_7 - count_j).abs(); // J's cancel with 7
sum += (count_f + count_7) as f32 / 2.0;
if sum % 2.0 != 0.0 {
inside_points += 1;
}
}
}
}
inside_points.to_string()
}
pub mod prelude {
pub use super::part1;
pub use super::part2;
}

41
day_10/src/main.rs Normal file
View File

@@ -0,0 +1,41 @@
use day_10::prelude::*;
fn main() {
let input = include_str!("../input.txt");
println!("{}", part1(input));
println!("{}", part2(input));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_part1() {
assert_eq!(part1(".....
.S-7.
.|.|.
.L-J.
....."), "4".to_string());
assert_eq!(part1("..F7.
.FJ|.
SJ.L7
|F--J
LJ..."), "8".to_string());
}
#[test]
fn test_part2() {
assert_eq!(part2(".F7FSF7F7F7F7F7F---7
.|LJ||||||||||||F--J
.L-7LJLJ||||||LJL-7.
F--JF--7||LJLJ.F7FJ.
L---JF-JLJ....FJLJ..
...F-JF---7...L7....
..FJF7L7F-JF7..L---7
..L-JL7||F7|L7F-7F7|
.....FJ|||||FJL7||LJ
.....L-JLJLJL--JLJ.."), "10".to_string());
}
}