Day 20
This commit is contained in:
parent
31c9a768ec
commit
79c8ed5744
|
@ -0,0 +1,78 @@
|
||||||
|
use crate::util::maps::*;
|
||||||
|
|
||||||
|
const CHEAT_DURATION: u64 = 20;
|
||||||
|
|
||||||
|
pub fn day20() {
|
||||||
|
let input = World::from_string(&crate::input(20));
|
||||||
|
let maze = input.map(|&c| c == '#');
|
||||||
|
let (ex, ey, _) = input.enumerate().find(|(_, _, &c)| c == 'E').unwrap();
|
||||||
|
|
||||||
|
let costs = path_costs(&maze, ex, ey);
|
||||||
|
|
||||||
|
let free_spaces: Vec<(usize, usize)> = maze
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(x, y, &b)| if !b { Some((x, y)) } else { None })
|
||||||
|
.collect();
|
||||||
|
let all_cheats: Vec<u64> = free_spaces
|
||||||
|
.iter()
|
||||||
|
.flat_map(|&(ax, ay)| {
|
||||||
|
free_spaces
|
||||||
|
.iter()
|
||||||
|
.filter_map(|&(bx, by)| {
|
||||||
|
if ax == bx && ay == by {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let taxi_cost = taxicab_distance(ax, ay, bx, by) as u64;
|
||||||
|
if taxi_cost > CHEAT_DURATION {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let a_cost = costs.get(ax, ay).unwrap();
|
||||||
|
let b_cost = costs.get(bx, by).unwrap();
|
||||||
|
// a cheat's timesave is the cost of a - the cost of b, minus the time it takes to do the cheat
|
||||||
|
// and we return None for cheats that have negative timesave (why would you cheat to do worse?)
|
||||||
|
a_cost.checked_sub(b_cost)?.checked_sub(taxi_cost)
|
||||||
|
})
|
||||||
|
.collect::<Vec<u64>>()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let good_cheats = all_cheats
|
||||||
|
.iter()
|
||||||
|
.filter(|&&advantage| advantage >= 100)
|
||||||
|
.count();
|
||||||
|
|
||||||
|
println!("{good_cheats}");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path_costs(world: &World<bool>, x: usize, y: usize) -> World<u64> {
|
||||||
|
fn calculate_path_costs(
|
||||||
|
world: &World<bool>,
|
||||||
|
x: usize,
|
||||||
|
y: usize,
|
||||||
|
cost_so_far: u64,
|
||||||
|
costs: &mut World<u64>,
|
||||||
|
) {
|
||||||
|
let adjacents = world
|
||||||
|
.adjacent_locations(x, y)
|
||||||
|
.into_iter()
|
||||||
|
.filter(|&(nx, ny)| !world.get(nx, ny).unwrap());
|
||||||
|
for (nx, ny) in adjacents {
|
||||||
|
let cost = cost_so_far + 1;
|
||||||
|
let old_cost = costs.get(nx, ny).unwrap();
|
||||||
|
if cost < old_cost {
|
||||||
|
costs.set(nx, ny, cost);
|
||||||
|
calculate_path_costs(world, nx, ny, cost, costs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut costs = World::from_dimensions(world.width(), world.height(), u64::MAX);
|
||||||
|
costs.set(x, y, 0);
|
||||||
|
calculate_path_costs(world, x, y, 0, &mut costs);
|
||||||
|
costs
|
||||||
|
}
|
||||||
|
|
||||||
|
fn taxicab_distance(ax: usize, ay: usize, bx: usize, by: usize) -> usize {
|
||||||
|
let dx = if ax < bx { bx - ax } else { ax - bx };
|
||||||
|
let dy = if ay < by { by - ay } else { ay - by };
|
||||||
|
dx + dy
|
||||||
|
}
|
39
src/main.rs
39
src/main.rs
|
@ -3,22 +3,6 @@ pub mod util;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
mod day1;
|
mod day1;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
mod day2;
|
|
||||||
#[allow(dead_code)]
|
|
||||||
mod day3;
|
|
||||||
#[allow(dead_code)]
|
|
||||||
mod day4;
|
|
||||||
#[allow(dead_code)]
|
|
||||||
mod day5;
|
|
||||||
#[allow(dead_code)]
|
|
||||||
mod day6;
|
|
||||||
#[allow(dead_code)]
|
|
||||||
mod day7;
|
|
||||||
#[allow(dead_code)]
|
|
||||||
mod day8;
|
|
||||||
#[allow(dead_code)]
|
|
||||||
mod day9;
|
|
||||||
#[allow(dead_code)]
|
|
||||||
mod day10;
|
mod day10;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
mod day11;
|
mod day11;
|
||||||
|
@ -36,10 +20,28 @@ mod day16;
|
||||||
mod day17;
|
mod day17;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
mod day18;
|
mod day18;
|
||||||
|
#[allow(dead_code)]
|
||||||
mod day19;
|
mod day19;
|
||||||
|
#[allow(dead_code)]
|
||||||
|
mod day2;
|
||||||
|
mod day20;
|
||||||
|
#[allow(dead_code)]
|
||||||
|
mod day3;
|
||||||
|
#[allow(dead_code)]
|
||||||
|
mod day4;
|
||||||
|
#[allow(dead_code)]
|
||||||
|
mod day5;
|
||||||
|
#[allow(dead_code)]
|
||||||
|
mod day6;
|
||||||
|
#[allow(dead_code)]
|
||||||
|
mod day7;
|
||||||
|
#[allow(dead_code)]
|
||||||
|
mod day8;
|
||||||
|
#[allow(dead_code)]
|
||||||
|
mod day9;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
day19::day19();
|
day20::day20();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input(day: u8) -> String {
|
pub fn input(day: u8) -> String {
|
||||||
|
@ -47,7 +49,8 @@ pub fn input(day: u8) -> String {
|
||||||
let token = std::env::var("AOC_TOKEN").expect("AOC_TOKEN must be set in .env file");
|
let token = std::env::var("AOC_TOKEN").expect("AOC_TOKEN must be set in .env file");
|
||||||
|
|
||||||
let client = reqwest::blocking::Client::new();
|
let client = reqwest::blocking::Client::new();
|
||||||
client.get(format!("https://adventofcode.com/2024/day/{}/input", day))
|
client
|
||||||
|
.get(format!("https://adventofcode.com/2024/day/{}/input", day))
|
||||||
.header("cookie", format!("session={}", token))
|
.header("cookie", format!("session={}", token))
|
||||||
.send()
|
.send()
|
||||||
.expect("Failed to get input")
|
.expect("Failed to get input")
|
||||||
|
|
Loading…
Reference in New Issue