generated from luke-else/AdventOfCodeXXXX
feat: Day 5 Completed
All checks were successful
Continuous integration / Check (push) Successful in 38s
Continuous integration / Test Suite (push) Successful in 43s
Continuous integration / Rustfmt (push) Successful in 29s
Continuous integration / Clippy (push) Successful in 40s
Continuous integration / build (push) Successful in 41s
All checks were successful
Continuous integration / Check (push) Successful in 38s
Continuous integration / Test Suite (push) Successful in 43s
Continuous integration / Rustfmt (push) Successful in 29s
Continuous integration / Clippy (push) Successful in 40s
Continuous integration / build (push) Successful in 41s
This commit is contained in:
1187
input/day05
1187
input/day05
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
|||||||
|
3-5
|
||||||
|
10-14
|
||||||
|
16-20
|
||||||
|
12-18
|
||||||
|
|
||||||
|
1
|
||||||
|
5
|
||||||
|
8
|
||||||
|
11
|
||||||
|
17
|
||||||
|
32
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
3-5
|
||||||
|
10-14
|
||||||
|
16-20
|
||||||
|
12-18
|
||||||
|
|
||||||
|
1
|
||||||
|
5
|
||||||
|
8
|
||||||
|
11
|
||||||
|
17
|
||||||
|
32
|
||||||
@@ -16,9 +16,9 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
Box::new(day02::Day02 {}),
|
Box::new(day02::Day02 {}),
|
||||||
Box::new(day03::Day03 {}),
|
Box::new(day03::Day03 {}),
|
||||||
Box::new(day04::Day04 {}),
|
Box::new(day04::Day04 {}),
|
||||||
// Box::new(day05::Day05 {}),
|
Box::new(day05::Day05 {}),
|
||||||
// Box::new(day06::Day06 {}),
|
Box::new(day06::Day06 {}),
|
||||||
// Box::new(day07::Day07 {}),
|
Box::new(day07::Day07 {}),
|
||||||
// Box::new(day08::Day08 {}),
|
// Box::new(day08::Day08 {}),
|
||||||
// Box::new(day09::Day09 {}),
|
// Box::new(day09::Day09 {}),
|
||||||
// Box::new(day10::Day10 {}),
|
// Box::new(day10::Day10 {}),
|
||||||
|
|||||||
@@ -5,16 +5,62 @@ pub struct Day05 {}
|
|||||||
impl Solution for Day05 {
|
impl Solution for Day05 {
|
||||||
fn part1(
|
fn part1(
|
||||||
&self,
|
&self,
|
||||||
_input: &mut Vec<String>,
|
input: &mut Vec<String>,
|
||||||
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> {
|
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> {
|
||||||
Ok(Box::new("Ready"))
|
let sep_idx = input.iter().position(|l| l.trim().is_empty());
|
||||||
|
|
||||||
|
let (range_lines, id_lines) = match sep_idx {
|
||||||
|
Some(i) => {
|
||||||
|
let ranges = &input[..i];
|
||||||
|
let ids = &input[i + 1..];
|
||||||
|
(ranges.to_vec(), ids.to_vec())
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// if no blank line, assume all ranges then no ids
|
||||||
|
(input.clone(), Vec::new())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let ranges = self.parse_ranges(&range_lines);
|
||||||
|
let merged = self.merge_ranges(ranges);
|
||||||
|
|
||||||
|
let mut fresh_count: u64 = 0;
|
||||||
|
for line in id_lines {
|
||||||
|
let s = line.trim();
|
||||||
|
if s.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let id: u64 = s.parse().expect("failed to parse ingredient id");
|
||||||
|
if self.is_fresh(&merged, id) {
|
||||||
|
fresh_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Box::new(fresh_count))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part2(
|
fn part2(
|
||||||
&self,
|
&self,
|
||||||
_input: &mut Vec<String>,
|
input: &mut Vec<String>,
|
||||||
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> {
|
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> {
|
||||||
Ok(Box::new("Ready"))
|
let sep_idx = input.iter().position(|l| l.trim().is_empty());
|
||||||
|
|
||||||
|
let (range_lines, _) = match sep_idx {
|
||||||
|
Some(i) => {
|
||||||
|
let ranges = &input[..i];
|
||||||
|
let ids = &input[i + 1..];
|
||||||
|
(ranges.to_vec(), ids.to_vec())
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// if no blank line, assume all ranges then no ids
|
||||||
|
(input.clone(), Vec::new())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let ranges = self.parse_ranges(&range_lines);
|
||||||
|
let merged = self.merge_ranges(ranges);
|
||||||
|
|
||||||
|
let fresh_set = merged.iter().map(|(s, e)| e - s + 1).sum::<u64>();
|
||||||
|
Ok(Box::new(fresh_set))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_day(&self) -> u8 {
|
fn get_day(&self) -> u8 {
|
||||||
@@ -22,7 +68,81 @@ impl Solution for Day05 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Day05 {}
|
impl Day05 {
|
||||||
|
fn parse_ranges(&self, lines: &[String]) -> Vec<(u64, u64)> {
|
||||||
|
let mut ranges: Vec<(u64, u64)> = Vec::new();
|
||||||
|
for line in lines {
|
||||||
|
let s = line.trim();
|
||||||
|
if s.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Expect format "start-end"
|
||||||
|
if let Some(idx) = s.find('-') {
|
||||||
|
let a = &s[..idx];
|
||||||
|
let b = &s[idx + 1..];
|
||||||
|
let start: u64 = a.parse().expect("failed to parse range start");
|
||||||
|
let end: u64 = b.parse().expect("failed to parse range end");
|
||||||
|
// Ensure start <= end (input likely correct, but be defensive)
|
||||||
|
if start <= end {
|
||||||
|
ranges.push((start, end));
|
||||||
|
} else {
|
||||||
|
ranges.push((end, start));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("range line without '-' found: {}", s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ranges
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Merge overlapping/adjacent ranges so membership tests are faster.
|
||||||
|
/// Ranges are inclusive.
|
||||||
|
fn merge_ranges(&self, mut ranges: Vec<(u64, u64)>) -> Vec<(u64, u64)> {
|
||||||
|
if ranges.is_empty() {
|
||||||
|
return ranges;
|
||||||
|
}
|
||||||
|
// sort by start
|
||||||
|
ranges.sort_by_key(|r| r.0);
|
||||||
|
let mut merged: Vec<(u64, u64)> = Vec::new();
|
||||||
|
let mut cur = ranges[0];
|
||||||
|
for &(s, e) in &ranges[1..] {
|
||||||
|
if s <= cur.1.saturating_add(1) {
|
||||||
|
// overlap or adjacent: extend
|
||||||
|
cur.1 = cur.1.max(e);
|
||||||
|
} else {
|
||||||
|
merged.push(cur);
|
||||||
|
cur = (s, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
merged.push(cur);
|
||||||
|
merged
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check whether `x` is inside any merged ranges using binary search.
|
||||||
|
fn is_fresh(&self, merged: &[(u64, u64)], x: u64) -> bool {
|
||||||
|
// find the first range with start > x, then check previous range (if any)
|
||||||
|
// equivalent to upper_bound on start
|
||||||
|
let idx = match merged.binary_search_by(|&(s, _)| {
|
||||||
|
if s > x {
|
||||||
|
std::cmp::Ordering::Greater
|
||||||
|
} else if s <= x {
|
||||||
|
std::cmp::Ordering::Less
|
||||||
|
} else {
|
||||||
|
std::cmp::Ordering::Equal
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
// binary_search_by will never return Equal in this comparator (we used <= vs >),
|
||||||
|
// but handle all cases robustly:
|
||||||
|
Ok(i) => i,
|
||||||
|
Err(i) => i,
|
||||||
|
};
|
||||||
|
if idx == 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let (s, e) = merged[idx - 1];
|
||||||
|
x >= s && x <= e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Test from puzzle input
|
/// Test from puzzle input
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -44,7 +164,7 @@ mod test {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
assert_eq!(answer, "Ready");
|
assert_eq!(answer, "3");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -61,6 +181,6 @@ mod test {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
assert_eq!(answer, "Ready");
|
assert_eq!(answer, "14");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user