y2024d20p1 some cleanup before reattempting p2
This commit is contained in:
parent
5ce4e2b51b
commit
cd42646864
@ -1,14 +1,12 @@
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
error::Error,
|
||||
sync::mpsc,
|
||||
};
|
||||
|
||||
use itertools::Itertools;
|
||||
use rayon::prelude::*;
|
||||
|
||||
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)
|
||||
// .iter()
|
||||
// .map(
|
||||
@ -23,147 +21,11 @@ pub fn process_part1(input: &str) -> u32 {
|
||||
// .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 {
|
||||
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> {
|
||||
let mut cheats = Vec::new();
|
||||
fn simulate_all(input: &str, time_to_saved: usize) -> HashMap<u32, u32> {
|
||||
let mut start = (0, 0);
|
||||
let grid = input
|
||||
.lines()
|
||||
@ -181,20 +43,7 @@ fn simulate_all_2(input: &str, time_to_saved: usize) -> HashMap<u32, u32> {
|
||||
.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 no_cheat = simulate_2(&grid, start);
|
||||
let no_cheat = simulate(&grid, start);
|
||||
let mut saved = HashMap::new();
|
||||
for (tile_idx, tile) in no_cheat[..no_cheat.len() - time_to_saved]
|
||||
.iter()
|
||||
@ -216,7 +65,7 @@ fn simulate_all_2(input: &str, time_to_saved: usize) -> HashMap<u32, u32> {
|
||||
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();
|
||||
visited.insert(start);
|
||||
let mut next_paths = vec![MazeRunner {
|
||||
@ -394,23 +243,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
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();
|
||||
println!("Test 2:");
|
||||
let result = simulate_all_2(INPUT, 0);
|
||||
let result = simulate_all(INPUT, 0);
|
||||
result
|
||||
.iter()
|
||||
.sorted_by(|a, b| a.0.cmp(b.0))
|
||||
@ -424,7 +259,7 @@ mod tests {
|
||||
fn part2() {
|
||||
let now = Instant::now();
|
||||
println!("Test 2:");
|
||||
let result = simulate_all_2(INPUT, 2);
|
||||
let result = simulate_all(INPUT, 2);
|
||||
result
|
||||
.iter()
|
||||
.sorted_by(|a, b| a.0.cmp(b.0))
|
||||
|
Loading…
Reference in New Issue
Block a user