1
0

Compare commits

4 Commits

Author SHA1 Message Date
85de6b1539 day 18 performance improvement 2025-10-21 15:00:51 +02:00
944faf2159 dbg made nicer 2025-10-21 11:33:48 +02:00
d25a45cb52 day 18 part 2 faster with binary search 2025-10-21 11:29:29 +02:00
2d34e77b13 runner 2025-10-21 11:10:59 +02:00
3 changed files with 49 additions and 19 deletions

View File

@@ -1,10 +1,9 @@
use std::{ use std::{collections::VecDeque, fs::read_to_string};
collections::{HashMap, HashSet, VecDeque},
fs::read_to_string,
};
use itertools::Itertools; use itertools::Itertools;
use crate::utils::grid::Grid;
pub fn day_main() { pub fn day_main() {
let input = read_to_string("input/day18.txt").unwrap(); let input = read_to_string("input/day18.txt").unwrap();
let input = input.trim(); let input = input.trim();
@@ -18,30 +17,33 @@ fn part1(input: &str) -> RiddleResult {
solve1(input, 1024, 70) solve1(input, 1024, 70)
} }
fn solve1(input: &str, n: usize, coord_max: i32) -> usize { fn solve1(input: &str, n: usize, coord_max: i64) -> usize {
let points = parse(input); let points = parse(input);
sp(&points[..n], coord_max).unwrap() sp(&points[..n], coord_max).unwrap()
} }
fn sp(points: &[(i32, i32)], coord_max: i32) -> Option<usize> { fn sp(points: &[(i64, i64)], coord_max: i64) -> Option<usize> {
let pointss: HashSet<&(i32, i32)> = HashSet::from_iter(points); let mut pcheck = Grid::from_default(coord_max + 1, coord_max + 1);
let mut visited = HashMap::new(); for p in points {
pcheck.set(*p, true);
}
let mut visited = Grid::from_default(coord_max + 1, coord_max + 1);
let mut queue = VecDeque::from_iter([(0, 0, 0)]); let mut queue = VecDeque::from_iter([(0, 0, 0)]);
while let Some((x, y, c)) = queue.pop_front() { while let Some((x, y, c)) = queue.pop_front() {
if x == coord_max && y == coord_max { if x == coord_max && y == coord_max {
return Some(c); return Some(c);
} }
if visited.contains_key(&(x, y)) { if visited.get((x, y)) == Some(&true) {
continue; continue;
} }
visited.insert((x, y), c); visited.set((x, y), true);
for (dx, dy) in [(0, 1), (1, 0), (0, -1), (-1, 0)] { for (dx, dy) in [(0, 1), (1, 0), (0, -1), (-1, 0)] {
let (a, b) = (x + dx, y + dy); let (a, b) = (x + dx, y + dy);
if (0..=coord_max).contains(&a) if (0..=coord_max).contains(&a)
&& (0..=coord_max).contains(&b) && (0..=coord_max).contains(&b)
&& !pointss.contains(&(a, b)) && pcheck.get((a, b)) == Some(&false)
{ {
queue.push_back((a, b, c + 1)); queue.push_back((a, b, c + 1));
} }
@@ -50,7 +52,7 @@ fn sp(points: &[(i32, i32)], coord_max: i32) -> Option<usize> {
None None
} }
fn parse(input: &str) -> Vec<(i32, i32)> { fn parse(input: &str) -> Vec<(i64, i64)> {
input input
.trim() .trim()
.lines() .lines()
@@ -67,14 +69,39 @@ fn part2(input: &str) -> String {
solve2(input, 1024, 70) solve2(input, 1024, 70)
} }
fn solve2(input: &str, fixed: usize, max_coord: i32) -> String { fn solve2(input: &str, fixed: usize, max_coord: i64) -> String {
let points = parse(input); let points = parse(input);
for i in fixed..points.len() {
if let None = sp(&points[..=i], max_coord) { // we want the first point with which there is no shortest path
return format!("{},{}", points[i].0, points[i].1); let mut i = fixed;
let mut jump = (points.len() - fixed) / 2;
#[cfg(debug_assertions)]
let mut loops = 0;
loop {
#[cfg(debug_assertions)]
{
loops += 1;
}
let l = sp(&points[..i - 1], max_coord);
let r = sp(&points[..i], max_coord);
if l.is_some() && r.is_none() {
#[cfg(debug_assertions)]
{
let iters_needed = i - fixed;
dbg!(loops, iters_needed);
}
return format!("{},{}", points[i - 1].0, points[i - 1].1);
}
if l.is_some() {
i += jump;
} else {
i -= jump;
}
jump /= 2;
if jump == 0 {
jump += 1;
} }
} }
unreachable!()
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -28,7 +28,6 @@ fn part1(input: &str) -> RiddleResult {
} }
} }
let sets = sets.iter().unique().collect_vec(); let sets = sets.iter().unique().collect_vec();
dbg!(sets.len());
sets.iter() sets.iter()
.filter(|set| set.iter().any(|t| t.starts_with("t"))) .filter(|set| set.iter().any(|t| t.starts_with("t")))
.count() .count()

View File

@@ -22,6 +22,7 @@ fn main() {
(15, day15::day_main), (15, day15::day_main),
(16, day16::day_main), (16, day16::day_main),
(17, day17::day_main), (17, day17::day_main),
(18, day18::day_main),
(19, day19::day_main), (19, day19::day_main),
(21, day21::day_main), (21, day21::day_main),
(22, day22::day_main), (22, day22::day_main),
@@ -29,17 +30,20 @@ fn main() {
(23, day23::day_main), (23, day23::day_main),
(24, day24::day_main), (24, day24::day_main),
(25, day25::day_main), (25, day25::day_main),
(18, day18::day_main),
// PLACEHOLDER // PLACEHOLDER
]); ]);
let day: Option<u8> = args().nth(1).and_then(|a| a.parse().ok()); let day: Option<u8> = args().nth(1).and_then(|a| a.parse().ok());
let Some(day) = day else { let Some(day) = day else {
let start = Instant::now();
mains mains
.iter() .iter()
.sorted_by_key(|entry| entry.0) .sorted_by_key(|entry| entry.0)
.for_each(|(d, f)| { .for_each(|(d, f)| {
run(*d, f); run(*d, f);
}); });
let duration = start.elapsed();
println!();
println!("{COLOR}{ITALIC}All tasks took {duration:?}{RESET_FORMATTING}");
return; return;
}; };