y2024d20p1 some cleanup before reattempting p2
This commit is contained in:
parent
5ce4e2b51b
commit
cd42646864
@ -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))
|
||||||
|
Loading…
Reference in New Issue
Block a user