feat: day 18 p2 + time

This commit is contained in:
Xavier Morel
2024-12-19 00:23:42 +01:00
parent 4f2be85c30
commit cde9af2880
2 changed files with 39 additions and 67 deletions

View File

@@ -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 13](./src/bin/13.rs) | `133.3µs` | `92.0µs` |
| [Day 14](./src/bin/14.rs) | `210.1µs` | `105.4ms` | | [Day 14](./src/bin/14.rs) | `210.1µs` | `105.4ms` |
| [Day 15](./src/bin/15.rs) | `95.2ms` | `188.1ms` | | [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**
<!--- benchmarking table ---> <!--- benchmarking table --->
--- ---

View File

@@ -42,16 +42,18 @@ impl Pos {
} }
res res
} }
// fn to_string(&self) -> String {
// format!("{},{}", self.x, self.y)
// }
} }
fn parse_input(input: &str) -> HashMap<Pos, usize> { 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<Pos> {
input input
.lines() .lines()
.enumerate() .filter_map(|l| {
.filter_map(|(n, l)| {
if l.is_empty() { if l.is_empty() {
None None
} else { } else {
@@ -59,19 +61,17 @@ fn parse_input(input: &str) -> HashMap<Pos, usize> {
if v.len() < 2 { if v.len() < 2 {
return None; return None;
} }
Some((Pos::init(v.remove(0), v.remove(0)), n)) Some(Pos::init(v.remove(0), v.remove(0)))
} }
}) })
.collect() .collect()
} }
fn bfs(walls: &HashMap<Pos, usize>, start: Pos, end: &Pos) -> Option<Vec<Pos>> { fn bfs(walls: &HashSet<Pos>, start: Pos, end: &Pos) -> Option<Vec<Pos>> {
let mut queue: VecDeque<Pos> = VecDeque::new(); let mut queue: VecDeque<Pos> = VecDeque::new();
let mut visited: HashSet<Pos> = HashSet::new(); let mut visited: HashSet<Pos> = HashSet::new();
let mut parent_map: HashMap<Pos, Pos> = HashMap::new(); let mut parent_map: HashMap<Pos, Pos> = HashMap::new();
let mut blockage_queue: Vec<Pos> = Vec::new();
queue.push_back(start.clone()); queue.push_back(start.clone());
visited.insert(start); visited.insert(start);
while let Some(current) = queue.pop_front() { while let Some(current) = queue.pop_front() {
@@ -89,10 +89,7 @@ fn bfs(walls: &HashMap<Pos, usize>, start: Pos, end: &Pos) -> Option<Vec<Pos>> {
if visited.contains(&n) { if visited.contains(&n) {
continue; continue;
} }
if walls.contains_key(&n) { if walls.contains(&n) {
if !blockage_queue.contains(&n) {
blockage_queue.push(n);
}
continue; continue;
} }
queue.push_back(n.clone()); queue.push_back(n.clone());
@@ -100,62 +97,38 @@ fn bfs(walls: &HashMap<Pos, usize>, start: Pos, end: &Pos) -> Option<Vec<Pos>> {
parent_map.insert(n, current.clone()); 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<Pos> = 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 None
} }
fn print_map(size: &Pos, walls: &HashMap<Pos, usize>, 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<usize> { pub fn part_one(input: &str) -> Option<usize> {
let mut coords = parse_input(input); let coords = parse_input(input);
let (limit, end) = if coords.len() < 100 { let (limit, end) = if coords.len() < 100 {
// Test case
(12, Pos::init(6, 6)) (12, Pos::init(6, 6))
} else { } else {
(1024, Pos::init(70, 70)) (1024, Pos::init(70, 70))
}; };
coords.retain(|_, v| *v < limit); let walls: HashSet<Pos> = 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<Pos> = 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<String> { pub fn part_two(input: &str) -> Option<String> {
@@ -165,12 +138,8 @@ pub fn part_two(input: &str) -> Option<String> {
} else { } else {
Pos::init(70, 70) Pos::init(70, 70)
}; };
let first_failure = get_first_failure(&coords, &end);
print_map(&end, &coords, &[]); coords.get(first_failure).unwrap().to_string().into()
let route = bfs(&coords, Pos::init(0, 0), &end);
println!("{:?}", route);
None
} }
#[cfg(test)] #[cfg(test)]