From cde9af28806b095dc745648000eed918035d9f8a Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 19 Dec 2024 00:23:42 +0100 Subject: [PATCH] feat: day 18 p2 + time --- README.md | 5 ++- src/bin/18.rs | 101 +++++++++++++++++--------------------------------- 2 files changed, 39 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index 86732b8..5365520 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,11 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www. | [Day 13](./src/bin/13.rs) | `133.3µs` | `92.0µs` | | [Day 14](./src/bin/14.rs) | `210.1µs` | `105.4ms` | | [Day 15](./src/bin/15.rs) | `95.2ms` | `188.1ms` | +| [Day 16](./src/bin/16.rs) | `-` | `-` | +| [Day 17](./src/bin/17.rs) | `1.5ms` | `-` | +| [Day 18](./src/bin/18.rs) | `2.1ms` | `5.0ms` | -**Total: 13267.00ms** +**Total: 13275.60ms** --- diff --git a/src/bin/18.rs b/src/bin/18.rs index 0c10f29..c143a99 100644 --- a/src/bin/18.rs +++ b/src/bin/18.rs @@ -42,16 +42,18 @@ impl Pos { } res } - // fn to_string(&self) -> String { - // format!("{},{}", self.x, self.y) - // } } -fn parse_input(input: &str) -> HashMap { +impl std::fmt::Display for Pos { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!(f, "{},{}", self.x, self.y) + } +} + +fn parse_input(input: &str) -> Vec { input .lines() - .enumerate() - .filter_map(|(n, l)| { + .filter_map(|l| { if l.is_empty() { None } else { @@ -59,19 +61,17 @@ fn parse_input(input: &str) -> HashMap { if v.len() < 2 { return None; } - Some((Pos::init(v.remove(0), v.remove(0)), n)) + Some(Pos::init(v.remove(0), v.remove(0))) } }) .collect() } -fn bfs(walls: &HashMap, start: Pos, end: &Pos) -> Option> { +fn bfs(walls: &HashSet, start: Pos, end: &Pos) -> Option> { let mut queue: VecDeque = VecDeque::new(); let mut visited: HashSet = HashSet::new(); let mut parent_map: HashMap = HashMap::new(); - let mut blockage_queue: Vec = Vec::new(); - queue.push_back(start.clone()); visited.insert(start); while let Some(current) = queue.pop_front() { @@ -89,10 +89,7 @@ fn bfs(walls: &HashMap, start: Pos, end: &Pos) -> Option> { if visited.contains(&n) { continue; } - if walls.contains_key(&n) { - if !blockage_queue.contains(&n) { - blockage_queue.push(n); - } + if walls.contains(&n) { continue; } queue.push_back(n.clone()); @@ -100,62 +97,38 @@ fn bfs(walls: &HashMap, start: Pos, end: &Pos) -> Option> { parent_map.insert(n, current.clone()); } } - blockage_queue.sort_by_cached_key(|p| walls.get(p).unwrap()); - - // Sort blockage queue by wall number ?! - for new_start in blockage_queue { - let mut queue: VecDeque = VecDeque::new(); - let mut visited = visited.clone(); - queue.push_back(new_start.clone()); - while let Some(current) = queue.pop_front() { - if current == *end { - println!("Found end by removing {:?}!", new_start); - println!("Wall at time: {}", walls.get(&new_start)?); - break; - } - for n in current.neighbors(end) { - if visited.contains(&n) { - continue; - } - if walls.contains_key(&n) { - continue; - } - queue.push_back(n.clone()); - visited.insert(n.clone()); - } - } - } - None } -fn print_map(size: &Pos, walls: &HashMap, path: &[Pos]) { - for y in 0..=size.y { - for x in 0..=size.x { - let p = Pos::init(x, y); - if path.contains(&p) { - print!("O"); - } else if walls.contains_key(&p) { - print!("#"); - } else { - print!("."); - } - } - println!(); - } -} - pub fn part_one(input: &str) -> Option { - let mut coords = parse_input(input); + let coords = parse_input(input); let (limit, end) = if coords.len() < 100 { - // Test case (12, Pos::init(6, 6)) } else { (1024, Pos::init(70, 70)) }; - coords.retain(|_, v| *v < limit); + let walls: HashSet = coords.into_iter().take(limit).collect(); + bfs(&walls, Pos::init(0, 0), &end).map(|r| r.len()) +} - bfs(&coords, Pos::init(0, 0), &end).map(|r| r.len()) +fn get_first_failure(coords: &[Pos], end: &Pos) -> usize { + let mut last_success = 0; + let mut first_failure = coords.len(); + + while last_success < first_failure - 1 { + let limit = last_success + (first_failure - last_success) / 2; + // println!(" {} <~~ {}? ~~> {}", last_success, limit, first_failure); + let walls: HashSet = coords.iter().take(limit + 1).cloned().collect(); + + if bfs(&walls, Pos::init(0, 0), end).is_some() { + // println!(" -> Success"); + last_success = limit; + } else { + // println!(" -> Failure"); + first_failure = limit; + } + } + first_failure } pub fn part_two(input: &str) -> Option { @@ -165,12 +138,8 @@ pub fn part_two(input: &str) -> Option { } else { Pos::init(70, 70) }; - - print_map(&end, &coords, &[]); - - let route = bfs(&coords, Pos::init(0, 0), &end); - println!("{:?}", route); - None + let first_failure = get_first_failure(&coords, &end); + coords.get(first_failure).unwrap().to_string().into() } #[cfg(test)]