Completed day 10. Not wildly happy with my runtime
This commit is contained in:
216
day_10/src/lib.rs
Normal file
216
day_10/src/lib.rs
Normal 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
41
day_10/src/main.rs
Normal 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());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user