y2024d20p1 some cleanup before reattempting p2

This commit is contained in:
Fabian Schmidt 2024-12-20 10:55:13 +01:00
parent 5ce4e2b51b
commit cd42646864

View File

@ -1,14 +1,12 @@
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
error::Error, error::Error,
sync::mpsc,
}; };
use itertools::Itertools; use itertools::Itertools;
use rayon::prelude::*;
pub fn process_part1(input: &str) -> u32 { pub fn process_part1(input: &str) -> u32 {
simulate_all_2(input, 100).values().copied().sum() simulate_all(input, 100).values().copied().sum()
//simulate_all(input) //simulate_all(input)
// .iter() // .iter()
// .map( // .map(
@ -23,147 +21,11 @@ pub fn process_part1(input: &str) -> u32 {
// .sum() // .sum()
} }
fn simulate_all(input: &str) -> HashMap<u32, u32> {
let mut cheats = Vec::new();
let mut start = (0, 0);
let grid = input
.lines()
.enumerate()
.map(|(yidx, row)| {
row.chars()
.enumerate()
.map(|(xidx, chara)| {
let tile = GridTile::try_from(chara).unwrap();
if tile == GridTile::Start {
start = (xidx, yidx);
}
tile
})
.collect_vec()
})
.collect_vec();
grid[1..grid.len() - 1]
.iter()
.enumerate()
.for_each(|(yidx, row)| {
row[1..row.len() - 1]
.iter()
.enumerate()
.for_each(|(xidx, tile)| {
if *tile == GridTile::Wall && cheatable(&grid, (xidx + 1, yidx + 1)) {
cheats.push((xidx + 1, yidx + 1));
}
});
});
let mut saved = HashMap::new();
let no_cheat = simulate(grid.clone(), start, None).unwrap();
let (tx, rx) = mpsc::channel();
cheats.into_par_iter().for_each(|cheat| {
let cheat = simulate(grid.clone(), start, Some(cheat)).unwrap();
let time_saved = no_cheat - cheat;
let _ = tx.send(time_saved);
});
drop(tx);
while let Ok(time_saved) = rx.recv() {
saved
.entry(time_saved)
.and_modify(|count| *count += 1)
.or_insert(1);
}
saved
}
fn cheatable(grid: &[Vec<GridTile>], wall_position: (usize, usize)) -> bool {
let above = grid
.get(wall_position.1 - 1)
.map(|above_row| above_row[wall_position.0]);
let below = grid
.get(wall_position.1 + 1)
.map(|below_row| below_row[wall_position.0]);
let left = grid[wall_position.1].get(wall_position.0 - 1).copied();
let right = grid[wall_position.1].get(wall_position.0 + 1).copied();
[above, below, left, right]
.iter()
.map(|tile| {
if let Some(tile) = tile {
match tile {
GridTile::Wall => 0,
GridTile::Path | GridTile::Start | GridTile::End => 1,
}
} else {
0
}
})
.sum::<u32>()
>= 2
}
fn simulate(
mut grid: Vec<Vec<GridTile>>,
start: (usize, usize),
cheat: Option<(usize, usize)>,
) -> Option<u32> {
if let Some(cheat) = cheat {
grid[cheat.1][cheat.0] = GridTile::Path;
}
let mut visited = HashSet::new();
visited.insert(start);
let mut next_paths = vec![MazeRunner {
coords: start,
visited: visited.clone(),
..Default::default()
}];
let mut arrived: Vec<MazeRunner> = Vec::new();
while !next_paths.is_empty() {
next_paths = next_paths
.iter()
.map(|maze_runner| {
let mut paths = Vec::new();
if let Some(path) = maze_runner.get_next(&grid, Direction::Up) {
paths.push(path);
}
if let Some(path) = maze_runner.get_next(&grid, Direction::Down) {
paths.push(path);
}
if let Some(path) = maze_runner.get_next(&grid, Direction::Left) {
paths.push(path);
}
if let Some(path) = maze_runner.get_next(&grid, Direction::Right) {
paths.push(path);
}
paths
})
.collect_vec()
.concat();
for (idx, maze_runner) in next_paths.clone().iter().enumerate().rev() {
if maze_runner.visited.contains(&maze_runner.coords)
|| visited.contains(&maze_runner.coords)
{
next_paths.remove(idx);
continue;
}
visited.insert(maze_runner.coords);
next_paths[idx].visited.insert(maze_runner.coords);
if maze_runner.state == State::Arrived {
let arrived_reindeer = next_paths.remove(idx);
arrived.push(arrived_reindeer);
}
//log_maze(&grid, maze_runner);
}
}
arrived.sort_by(|a_runner, b_runner| a_runner.visited.len().cmp(&b_runner.visited.len()));
arrived
.first()
.map(|arrived| arrived.visited.len() as u32 - 1)
}
pub fn process_part2(input: &str) -> u32 { pub fn process_part2(input: &str) -> u32 {
simulate_all_2(input, 100).values().copied().sum() simulate_all(input, 100).values().copied().sum()
} }
fn simulate_all_2(input: &str, time_to_saved: usize) -> HashMap<u32, u32> { fn simulate_all(input: &str, time_to_saved: usize) -> HashMap<u32, u32> {
let mut cheats = Vec::new();
let mut start = (0, 0); let mut start = (0, 0);
let grid = input let grid = input
.lines() .lines()
@ -181,20 +43,7 @@ fn simulate_all_2(input: &str, time_to_saved: usize) -> HashMap<u32, u32> {
.collect_vec() .collect_vec()
}) })
.collect_vec(); .collect_vec();
grid[1..grid.len() - 1] let no_cheat = simulate(&grid, start);
.iter()
.enumerate()
.for_each(|(yidx, row)| {
row[1..row.len() - 1]
.iter()
.enumerate()
.for_each(|(xidx, tile)| {
if *tile == GridTile::Wall && cheatable(&grid, (xidx + 1, yidx + 1)) {
cheats.push((xidx + 1, yidx + 1));
}
});
});
let no_cheat = simulate_2(&grid, start);
let mut saved = HashMap::new(); let mut saved = HashMap::new();
for (tile_idx, tile) in no_cheat[..no_cheat.len() - time_to_saved] for (tile_idx, tile) in no_cheat[..no_cheat.len() - time_to_saved]
.iter() .iter()
@ -216,7 +65,7 @@ fn simulate_all_2(input: &str, time_to_saved: usize) -> HashMap<u32, u32> {
saved saved
} }
fn simulate_2(grid: &[Vec<GridTile>], start: (usize, usize)) -> Vec<(usize, usize)> { fn simulate(grid: &[Vec<GridTile>], start: (usize, usize)) -> Vec<(usize, usize)> {
let mut visited = HashSet::new(); let mut visited = HashSet::new();
visited.insert(start); visited.insert(start);
let mut next_paths = vec![MazeRunner { let mut next_paths = vec![MazeRunner {
@ -394,23 +243,9 @@ mod tests {
#[test] #[test]
fn part1() { fn part1() {
let now = Instant::now();
println!("Test 1:");
let result = simulate_all(INPUT);
result
.iter()
.sorted_by(|a, b| a.0.cmp(b.0))
.for_each(|(saved, count)| {
println!("There are {count} cheats that saved {saved} picoseconds");
});
println!("Ran in {}", get_elapsed_string(now.elapsed()));
}
#[test]
fn part1_fast() {
let now = Instant::now(); let now = Instant::now();
println!("Test 2:"); println!("Test 2:");
let result = simulate_all_2(INPUT, 0); let result = simulate_all(INPUT, 0);
result result
.iter() .iter()
.sorted_by(|a, b| a.0.cmp(b.0)) .sorted_by(|a, b| a.0.cmp(b.0))
@ -424,7 +259,7 @@ mod tests {
fn part2() { fn part2() {
let now = Instant::now(); let now = Instant::now();
println!("Test 2:"); println!("Test 2:");
let result = simulate_all_2(INPUT, 2); let result = simulate_all(INPUT, 2);
result result
.iter() .iter()
.sorted_by(|a, b| a.0.cmp(b.0)) .sorted_by(|a, b| a.0.cmp(b.0))