Day 19
This commit is contained in:
parent
187e3c8b07
commit
31c9a768ec
|
@ -0,0 +1,71 @@
|
|||
use itertools::Itertools;
|
||||
|
||||
use crate::util::maps::World;
|
||||
|
||||
pub fn day18() {
|
||||
let bytes: Vec<(usize, usize)> = crate::input(18)
|
||||
.lines()
|
||||
.map(|line| {
|
||||
line.split(",")
|
||||
.map(|b| b.parse::<usize>().unwrap())
|
||||
.collect_tuple()
|
||||
.unwrap()
|
||||
})
|
||||
.collect();
|
||||
|
||||
let world_with_bytes = |b| {
|
||||
let mut world = World::from_2d_vec(vec![vec![false; 71]; 71]);
|
||||
for &(x, y) in bytes.iter().take(b) {
|
||||
world.set(x, y, true);
|
||||
}
|
||||
world
|
||||
};
|
||||
|
||||
let mut low_bound = 0;
|
||||
let mut high_bound = bytes.len();
|
||||
loop {
|
||||
if high_bound - low_bound <= 1 {
|
||||
break;
|
||||
}
|
||||
let i = low_bound + (high_bound - low_bound) / 2;
|
||||
|
||||
let world = (world_with_bytes)(i);
|
||||
let path_length = path_costs(&world, 0, 0).get(70, 70).unwrap();
|
||||
|
||||
if path_length == u64::MAX {
|
||||
high_bound = i;
|
||||
} else {
|
||||
low_bound = i;
|
||||
}
|
||||
}
|
||||
|
||||
let (last_byte_x, last_byte_y) = bytes[high_bound - 1];
|
||||
println!("After a byte falls at ({last_byte_x}, {last_byte_y}), there is no way out! The researchers perish!");
|
||||
}
|
||||
|
||||
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);
|
||||
calculate_path_costs(world, x, y, 0, &mut costs);
|
||||
costs
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
use itertools::Itertools;
|
||||
use rayon::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub fn day19() {
|
||||
let input = crate::input(19);
|
||||
let (towels_input, designs_input) = input.split("\n\n").collect_tuple().unwrap();
|
||||
let towels: Vec<&str> = towels_input.split(", ").collect();
|
||||
let designs: Vec<&str> = designs_input.lines().collect();
|
||||
|
||||
let ways_to_make_designs: Vec<u64> = designs
|
||||
.par_iter()
|
||||
.map(|design| make_pattern_from_towels(design, &towels))
|
||||
.collect();
|
||||
|
||||
let possible_designs_count = ways_to_make_designs
|
||||
.iter()
|
||||
.filter(|&&ways| ways != 0)
|
||||
.count();
|
||||
println!("{possible_designs_count} designs are possible to make.");
|
||||
|
||||
let total_ways: u64 = ways_to_make_designs.iter().sum();
|
||||
println!("{total_ways} ways to make a design are possible.");
|
||||
}
|
||||
|
||||
fn make_pattern_from_towels(design: &str, towels: &Vec<&str>) -> u64 {
|
||||
fn make_pattern(design: &str, towels: &Vec<&str>, memo: &mut HashMap<String, u64>) -> u64 {
|
||||
if let Some(&ways) = memo.get(design) {
|
||||
return ways;
|
||||
}
|
||||
if design.is_empty() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
let ways = towels
|
||||
.iter()
|
||||
.map(|towel| match design.strip_prefix(towel) {
|
||||
Some(subdesign) => make_pattern(subdesign, towels, memo),
|
||||
None => 0,
|
||||
})
|
||||
.sum();
|
||||
memo.insert(design.into(), ways);
|
||||
ways
|
||||
}
|
||||
|
||||
let mut memo: HashMap<String, u64> = HashMap::new();
|
||||
make_pattern(design, towels, &mut memo)
|
||||
}
|
|
@ -34,10 +34,12 @@ mod day15;
|
|||
mod day16;
|
||||
#[allow(dead_code)]
|
||||
mod day17;
|
||||
#[allow(dead_code)]
|
||||
mod day18;
|
||||
mod day19;
|
||||
|
||||
fn main() {
|
||||
day18::day18();
|
||||
day19::day19();
|
||||
}
|
||||
|
||||
pub fn input(day: u8) -> String {
|
||||
|
|
Loading…
Reference in New Issue