Skip to content

Commit 00453e3

Browse files
committed
2024 day2
1 parent 9bfc1dc commit 00453e3

File tree

7 files changed

+791
-0
lines changed

7 files changed

+791
-0
lines changed

Diff for: 2023/src/day5.rs

+206
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,18 @@ struct RangeMap {
1010
dst: Range<usize>,
1111
}
1212

13+
impl PartialOrd for RangeMap {
14+
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
15+
Some(self.cmp(other))
16+
}
17+
}
18+
19+
impl Ord for RangeMap {
20+
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
21+
self.src.start.cmp(&other.src.start)
22+
}
23+
}
24+
1325
impl FromStr for RangeMap {
1426
type Err = Box<dyn Error>;
1527

@@ -105,9 +117,153 @@ fn part1(input: &Input) -> usize {
105117
lowest_location.unwrap()
106118
}
107119

120+
fn intersect(a: &Range<usize>, b: &Range<usize>) -> Option<Range<usize>> {
121+
let start = std::cmp::max(a.start, b.start);
122+
let end = std::cmp::min(a.end, b.end);
123+
if end > start {
124+
Some(start..end)
125+
} else {
126+
None
127+
}
128+
}
129+
130+
fn remove(whole: &Range<usize>, to_remove: &Range<usize>) -> Option<(Range<usize>, Option<Range<usize>>)> {
131+
let mut before = None;
132+
let mut after = None;
133+
if to_remove.start > whole.start {
134+
before = Some(whole.start..to_remove.start);
135+
}
136+
if to_remove.end < whole.end {
137+
after = Some(to_remove.end..whole.end);
138+
}
139+
if before.as_ref().is_some_and(|r| r.is_empty()) {
140+
before = None;
141+
}
142+
if after.as_ref().is_some_and(|r| r.is_empty()) {
143+
after = None;
144+
}
145+
146+
match (before, after) {
147+
(Some(before), Some(after)) => Some((before, Some(after))),
148+
(Some(before), None) => Some((before, None)),
149+
(None, Some(after)) => Some((after, None)),
150+
(None, None) => None,
151+
}
152+
}
153+
154+
fn find_lowest(input: &Input, in_range: &Range<usize>, current_type: &str) -> usize {
155+
156+
println!("find_lowest({:?}, {:?})", in_range, current_type);
157+
let mut lowest_location = None;
158+
let mut remaining = Vec::new();
159+
remaining.push(RangeMap { src: in_range.clone(), dst: in_range.clone() });
160+
161+
let map = input.maps.get(current_type).expect("Couldn't find map!");
162+
let mut range_index = 0;
163+
while range_index < map.ranges.len() || remaining.len() > 0 {
164+
let r = if range_index < map.ranges.len() {
165+
let r = &map.ranges[range_index];
166+
range_index += 1;
167+
r.clone()
168+
} else {
169+
let r = remaining.pop().unwrap();
170+
if r.src.start == r.src.end {
171+
continue;
172+
}
173+
r
174+
};
175+
176+
if let Some(overlap) = intersect(&r.src, & in_range) {
177+
let offset = overlap.start - r.src.start;
178+
let dst = r.dst.start + offset .. r.dst.start + offset + overlap.len();
179+
let location = if map.to == "location" {
180+
r.dst.start
181+
} else {
182+
find_lowest(input, &dst, &map.to)
183+
};
184+
185+
if let Some(ref mut lowest) = &mut lowest_location {
186+
*lowest = std::cmp::min(*lowest, location);
187+
} else {
188+
assert_ne!(0, location);
189+
lowest_location = Some(location);
190+
}
191+
192+
let remaining_intial_len = remaining.len();
193+
for i in 0..remaining_intial_len {
194+
let remove_result = remove(&remaining[i].src, &overlap);
195+
println!("remove({:?}, {:?}) = {:?}", remaining[i].src, overlap, remove_result);
196+
if let Some((src_before, src_after)) = remove_result {
197+
let offset = remaining[i].dst.start as isize - remaining[i].src.start as isize;
198+
remaining[i].dst = (src_before.start as isize + offset) as usize .. (src_before.end as isize + offset) as usize;
199+
remaining[i].src = src_before;
200+
if let Some(src_after) = src_after {
201+
remaining.push(RangeMap {
202+
dst: (src_after.start as isize + offset) as usize .. (src_after.end as isize + offset) as usize,
203+
src: src_after,
204+
});
205+
}
206+
} else {
207+
remaining[i].src = 0..0;
208+
remaining[i].dst = 0..0;
209+
}
210+
}
211+
}
212+
}
213+
214+
if let Some(lowest) = lowest_location {
215+
lowest
216+
} else if map.to == "location" {
217+
in_range.start
218+
} else {
219+
find_lowest(input, in_range, &map.to)
220+
}
221+
}
222+
223+
#[aoc(day5, part2)]
224+
fn part2(input: &Input) -> usize {
225+
let mut lowest_location = None;
226+
for seed_range in input.seeds.chunks_exact(2) {
227+
let seed_range = seed_range[0]..seed_range[0]+seed_range[1];
228+
let location = find_lowest(input, &seed_range, "seed");
229+
230+
if let Some(ref mut lowest) = &mut lowest_location {
231+
*lowest = std::cmp::min(*lowest, location);
232+
} else {
233+
lowest_location = Some(location);
234+
}
235+
}
236+
lowest_location.unwrap()
237+
}
238+
108239
#[cfg(test)]
109240
mod tests {
241+
use core::panic;
242+
110243
use super::*;
244+
#[test]
245+
fn test_intersect() {
246+
for x1 in 0..5 {
247+
for x2 in x1..5 {
248+
for y1 in 0..5 {
249+
for y2 in y1..5 {
250+
let x = x1..x2;
251+
let y = y1..y2;
252+
let i = intersect(&x, &y);
253+
for z in 0..5 {
254+
let in_both = x.contains(&z) && y.contains(&z);
255+
match (i.as_ref(), in_both) {
256+
(Some(i), in_both) =>
257+
assert_eq!(i.contains(&z), in_both),
258+
(None, false) => {},
259+
_ => panic!("{:?} {:?} {} {:?} {}", x, y, z, i, in_both),
260+
}
261+
}
262+
}
263+
}
264+
}
265+
}
266+
}
111267

112268
#[test]
113269
fn part1_example() {
@@ -148,4 +304,54 @@ humidity-to-location map:
148304
"#.trim());
149305
assert_eq!(part1(&input), 35);
150306
}
307+
308+
#[test]
309+
fn part2_example() {
310+
let input = parse_input(r#"
311+
seeds: 79 14 55 13
312+
313+
seed-to-soil map:
314+
50 98 2
315+
52 50 48
316+
317+
soil-to-fertilizer map:
318+
0 15 37
319+
37 52 2
320+
39 0 15
321+
322+
fertilizer-to-water map:
323+
49 53 8
324+
0 11 42
325+
42 0 7
326+
57 7 4
327+
328+
water-to-light map:
329+
88 18 7
330+
18 25 70
331+
332+
light-to-temperature map:
333+
45 77 23
334+
81 45 19
335+
68 64 13
336+
337+
temperature-to-humidity map:
338+
0 69 1
339+
1 0 69
340+
341+
humidity-to-location map:
342+
60 56 37
343+
56 93 4
344+
"#.trim());
345+
346+
assert_eq!(46, find_lowest(&input, &(46..47), "humidity"));
347+
assert_eq!(46, find_lowest(&input, &(45..46), "temperature"));
348+
assert_eq!(46, find_lowest(&input, &(77..78), "light"));
349+
assert_eq!(46, find_lowest(&input, &(84..85), "water"));
350+
assert_eq!(46, find_lowest(&input, &(84..85), "fertilizer"));
351+
assert_eq!(46, find_lowest(&input, &(84..85), "soil"));
352+
assert_eq!(46, find_lowest(&input, &(82..83), "seed"));
353+
assert_eq!(46, find_lowest(&input, &(79..93), "seed"));
354+
355+
// assert_eq!(part2(&input), 46);
356+
}
151357
}

Diff for: 2024/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
target/*
2+
input/*

0 commit comments

Comments
 (0)