8
๐ฆ Everybody.Codes 2025 Quest 19 Solutions ๐ฆ
(programming.dev)
Shortest solution so far.
use std::collections::{BTreeMap};
use interval::{
IntervalSet,
ops::Range,
prelude::{Bounded, Empty, Intersection, Union},
};
pub fn solve_part_1(input: &str) -> String {
let mut data = BTreeMap::new();
for v in input.lines().map(|l| {
l.split(",")
.map(|v| v.parse().unwrap())
.collect::<Vec<i64>>()
}) {
data.entry(v[0]).or_insert(vec![]).push((v[1], v[2]));
}
let mut y_ranges = IntervalSet::new(0, 0);
let mut x = 0;
for (wall_x, openings) in data.into_iter() {
let dx = wall_x - x;
let mut new_ranges = IntervalSet::empty();
for interval in y_ranges.into_iter() {
new_ranges = new_ranges.union(&IntervalSet::new(
interval.lower() - dx,
interval.upper() + dx,
));
}
let mut openings_intervalset = IntervalSet::empty();
for (opening_start, opening_size) in openings {
openings_intervalset = openings_intervalset.union(&IntervalSet::new(
opening_start,
opening_start + opening_size - 1,
));
}
y_ranges = new_ranges.intersection(&openings_intervalset);
x = wall_x;
}
let y = y_ranges
.iter()
.flat_map(|i| (i.lower()..=i.upper()))
.find(|y| y % 2 == x % 2)
.unwrap();
((y + x) / 2).to_string()
}
pub fn solve_part_2(input: &str) -> String {
solve_part_1(input)
}
pub fn solve_part_3(input: &str) -> String {
solve_part_1(input)
}
The DP solution to go column by column and compute the min flaps for each cell is correct but too slow. Fortunately this problem can be solved using MATH
# Uses math to calculate the minimum number of flaps needed to reach the last passage at any height.
# This solution relies on a couple of facts:
# 1. The number of flaps needed to reach a passage at (x, y) is ceil((x + y) / 2).
# Proof:
# - Each flap increases your height by 1 and each glide decreases it by 1
# - Suppose you flapped f times and covered a horizontal distance of x
# - So your final height would be y = f - (x - f) = 2f - x
# - Now suppose a passage at position p_x begins at height p_y. To enter it, your height must be, y >= p_y
# - Substituting y, 2f - x >= p_y => 2f - p_x >= p_y
# - Solving for f, f >= (p_x + p_y) / 2
# - Since f is an integer, f = ceil((p_x + p_y) / 2)
# 2. For each wall, the lowest opening gives the smallest lower bound on the cumulative number of flaps.
# The maximum of these bounds is necessary because an earlier high wall may require more flaps than the last wall.
# 3. For this input, that maximum lower bound is attainable through all the walls, so it is the optimal answer.
# This is not true in general: an opening's upper edge or the distance between walls can make the lowest opening unreachable.
def flapsMath(data: str):
flaps = 0
passages = [[int(p) for p in passage.split(',')] for passage in data.splitlines()]
passages.sort(key=lambda p: (p[0], p[1])) # Sort passages so that we always have the lowest opening first
last_seen_x = 0
for x, y, _ in passages:
if x != last_seen_x:
last_seen_x = x
# calculate the minimum number of flaps needed to cross this passage at its lowest opening
# (x + y + 1) // 2 is equivalent to ceil((x + y) / 2) for integers
flaps = max(flaps, (x + y + 1) // 2)
return flaps
An unofficial home for the advent of code community on programming.dev! Other challenges are also welcome!
Advent of Code is an annual Advent calendar of small programming puzzles for a variety of skill sets and skill levels that can be solved in any programming language you like.
Everybody Codes is another collection of programming puzzles with seasonal events.
Solution Threads
| M | T | W | T | F | S | S |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 |
Icon base by Lorc under CC BY 3.0 with modifications to add a gradient
console.log('Hello World')