day5: bugfixes for rangeset
This commit is contained in:
64
src/day5.rs
64
src/day5.rs
@@ -1,4 +1,4 @@
|
|||||||
use std::cmp::{max, min};
|
use std::cmp::max;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
|
|
||||||
@@ -43,45 +43,47 @@ impl RangeSet {
|
|||||||
Self { ranges: Vec::new() }
|
Self { ranges: Vec::new() }
|
||||||
}
|
}
|
||||||
fn simplify(&mut self) {
|
fn simplify(&mut self) {
|
||||||
// sort the ranges by start
|
|
||||||
if self.ranges.len() < 2 {
|
if self.ranges.len() < 2 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut modified = true;
|
let mut modified = true;
|
||||||
while modified {
|
while modified {
|
||||||
let mut new_ranges = Vec::new();
|
|
||||||
modified = false;
|
modified = false;
|
||||||
|
// sort the ranges by start
|
||||||
self.ranges.sort_by_key(|s| s.start);
|
self.ranges.sort_by_key(|s| s.start);
|
||||||
for chunk in self.ranges.chunks(2) {
|
let mut new_ranges = Vec::new();
|
||||||
if chunk.len() == 1 {
|
let mut pos = 1;
|
||||||
new_ranges.push(chunk[0].clone());
|
|
||||||
continue;
|
while pos <= self.ranges.len() {
|
||||||
|
// part of a disgusting hack to avoid skipping or double adding at the end
|
||||||
|
if pos == self.ranges.len() {
|
||||||
|
pos -= 1;
|
||||||
}
|
}
|
||||||
let (l, r) = (&chunk[0], &chunk[1]);
|
let (l, r) = (&self.ranges[pos - 1], &self.ranges[pos]);
|
||||||
|
|
||||||
if r.start <= l.end + 1 {
|
if r.start <= l.end + 1 {
|
||||||
modified = true;
|
modified = true;
|
||||||
new_ranges.push((min(r.start, l.start), max(l.end, r.end)).into())
|
new_ranges.push((l.start, max(l.end, r.end)).into());
|
||||||
} else {
|
// if we merged, skip checking the next range to avoid double-adding it
|
||||||
new_ranges.push(l.clone());
|
// this screws us up at the very end, so need the disgusting hack above
|
||||||
new_ranges.push(r.clone());
|
pos += 2;
|
||||||
}
|
} else if pos < self.ranges.len() - 1 {
|
||||||
}
|
// keep only the lhs if we didn't merge
|
||||||
if !self.ranges.len().is_multiple_of(2) && new_ranges.len() >= 2 {
|
new_ranges.push(l.clone());
|
||||||
let (l, r) = (new_ranges.pop().unwrap(), new_ranges.pop().unwrap());
|
pos += 1;
|
||||||
if r.start <= l.end + 1 && r.end >= l.start - 1 {
|
|
||||||
modified = true;
|
|
||||||
new_ranges.push((min(r.start, l.start), max(l.end, r.end)).into())
|
|
||||||
} else {
|
} else {
|
||||||
|
// at the end, keep both sides, otherwise the rhs gets excluded (if it didn't merge)
|
||||||
new_ranges.push(l.clone());
|
new_ranges.push(l.clone());
|
||||||
new_ranges.push(r.clone());
|
new_ranges.push(r.clone());
|
||||||
|
pos += 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ranges = new_ranges;
|
self.ranges = new_ranges;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn add(&mut self, s: Span) {
|
fn add(&mut self, s: Span) {
|
||||||
self.ranges.push(s);
|
self.ranges.push(s);
|
||||||
self.simplify()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,6 +113,15 @@ fn parse(input: &str) -> Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[aoc(day5, part1)]
|
||||||
|
fn part1(input: &Database) -> u64 {
|
||||||
|
input
|
||||||
|
.available_ingredients
|
||||||
|
.iter()
|
||||||
|
.filter(|i| input.fresh_ingredients.iter().any(|r| r.contains(i)))
|
||||||
|
.count() as u64
|
||||||
|
}
|
||||||
|
|
||||||
#[aoc_generator(day5, part2)]
|
#[aoc_generator(day5, part2)]
|
||||||
fn parse2(input: &str) -> Database2 {
|
fn parse2(input: &str) -> Database2 {
|
||||||
let mut fresh_ingredients = Vec::new();
|
let mut fresh_ingredients = Vec::new();
|
||||||
@@ -124,22 +135,13 @@ fn parse2(input: &str) -> Database2 {
|
|||||||
Database2 { fresh_ingredients }
|
Database2 { fresh_ingredients }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[aoc(day5, part1)]
|
|
||||||
fn part1(input: &Database) -> u64 {
|
|
||||||
input
|
|
||||||
.available_ingredients
|
|
||||||
.iter()
|
|
||||||
.filter(|i| input.fresh_ingredients.iter().any(|r| r.contains(i)))
|
|
||||||
.count() as u64
|
|
||||||
}
|
|
||||||
|
|
||||||
#[aoc(day5, part2)]
|
#[aoc(day5, part2)]
|
||||||
fn part2(input: &Database2) -> u64 {
|
fn part2(input: &Database2) -> u64 {
|
||||||
let mut all_ingredients = RangeSet::new();
|
let mut all_ingredients = RangeSet::new();
|
||||||
for r in &input.fresh_ingredients {
|
for r in &input.fresh_ingredients {
|
||||||
all_ingredients.add(r.clone())
|
all_ingredients.add(r.clone());
|
||||||
}
|
}
|
||||||
|
all_ingredients.simplify();
|
||||||
all_ingredients.ranges.iter().map(|r| r.len()).sum::<u64>()
|
all_ingredients.ranges.iter().map(|r| r.len()).sum::<u64>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user