2020: day09: part 1 and 2
This commit is contained in:
parent
09a9654a1b
commit
a0611f1fb3
|
@ -8,6 +8,7 @@ use aoc2020::day05;
|
||||||
use aoc2020::day06;
|
use aoc2020::day06;
|
||||||
use aoc2020::day07;
|
use aoc2020::day07;
|
||||||
use aoc2020::day08;
|
use aoc2020::day08;
|
||||||
|
use aoc2020::day09;
|
||||||
|
|
||||||
fn aoc2020_all(c: &mut Criterion) {
|
fn aoc2020_all(c: &mut Criterion) {
|
||||||
c.bench_function("day01", |b| b.iter(|| day01::run().unwrap()));
|
c.bench_function("day01", |b| b.iter(|| day01::run().unwrap()));
|
||||||
|
@ -18,6 +19,7 @@ fn aoc2020_all(c: &mut Criterion) {
|
||||||
c.bench_function("day06", |b| b.iter(|| day06::run().unwrap()));
|
c.bench_function("day06", |b| b.iter(|| day06::run().unwrap()));
|
||||||
c.bench_function("day07", |b| b.iter(|| day07::run().unwrap()));
|
c.bench_function("day07", |b| b.iter(|| day07::run().unwrap()));
|
||||||
c.bench_function("day08", |b| b.iter(|| day08::run().unwrap()));
|
c.bench_function("day08", |b| b.iter(|| day08::run().unwrap()));
|
||||||
|
c.bench_function("day09", |b| b.iter(|| day09::run().unwrap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
criterion_group! {
|
criterion_group! {
|
||||||
|
|
1000
aoc2020/input/day09.txt
Normal file
1000
aoc2020/input/day09.txt
Normal file
File diff suppressed because it is too large
Load diff
20
aoc2020/input/day09_provided.txt
Normal file
20
aoc2020/input/day09_provided.txt
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
35
|
||||||
|
20
|
||||||
|
15
|
||||||
|
25
|
||||||
|
47
|
||||||
|
40
|
||||||
|
62
|
||||||
|
55
|
||||||
|
65
|
||||||
|
95
|
||||||
|
102
|
||||||
|
117
|
||||||
|
150
|
||||||
|
182
|
||||||
|
127
|
||||||
|
219
|
||||||
|
299
|
||||||
|
277
|
||||||
|
309
|
||||||
|
576
|
130
aoc2020/src/day09.rs
Normal file
130
aoc2020/src/day09.rs
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
use aoc::err;
|
||||||
|
|
||||||
|
const INPUT: &str = include_str!("../input/day09.txt");
|
||||||
|
|
||||||
|
pub fn run() -> aoc::Result<String> {
|
||||||
|
let mut res = String::with_capacity(128);
|
||||||
|
|
||||||
|
writeln!(res, "part 1: {}", part1(INPUT)?)?;
|
||||||
|
writeln!(res, "part 2: {}", part2(INPUT)?)?;
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_pair_sum(data: &[u64], total: u64) -> Option<(u64, u64)> {
|
||||||
|
// on huge entries using a set like in day 01 would be faster, but here it's actually slower,
|
||||||
|
// probably due to relatively small input size
|
||||||
|
for i in 0..data.len() {
|
||||||
|
for j in (i + 1)..data.len() {
|
||||||
|
if data[i] + data[j] == total {
|
||||||
|
return Some((data[i], data[j]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_outlier(numbers: &[u64], preamble_size: usize) -> aoc::Result<(u64, usize)> {
|
||||||
|
// start checking numbers after the preamble only
|
||||||
|
for i in preamble_size..numbers.len() {
|
||||||
|
let preamble = &numbers[(i - preamble_size)..i];
|
||||||
|
let curr = numbers[i];
|
||||||
|
|
||||||
|
match find_pair_sum(preamble, curr) {
|
||||||
|
Some(_) => continue,
|
||||||
|
None => return Ok((curr, i)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(err!("couldn't find number with that property"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(input: &str) -> aoc::Result<u64> {
|
||||||
|
let numbers = input
|
||||||
|
.lines()
|
||||||
|
.map(|line| line.parse::<u64>())
|
||||||
|
.collect::<Result<Vec<u64>, _>>()
|
||||||
|
.map_err(|e| err!("couldn't parse number: {}", e))?;
|
||||||
|
|
||||||
|
let (solution, _) = find_outlier(&numbers, 25)?;
|
||||||
|
|
||||||
|
Ok(solution)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_contiguous_range(numbers: &[u64], total: u64, total_idx: usize) -> aoc::Result<(u64, u64)> {
|
||||||
|
for i in 0..total_idx {
|
||||||
|
for j in (i + 1)..total_idx {
|
||||||
|
let range = &numbers[i..=j];
|
||||||
|
|
||||||
|
if range.iter().sum::<u64>() == total {
|
||||||
|
// it's safe to unwrap here because j > i so the range always has one number
|
||||||
|
let min = range.iter().min().unwrap();
|
||||||
|
let max = range.iter().max().unwrap();
|
||||||
|
|
||||||
|
return Ok((*min, *max));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(err!("couldn't find number with that property"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2(input: &str) -> aoc::Result<u64> {
|
||||||
|
let numbers = input
|
||||||
|
.lines()
|
||||||
|
.map(|line| line.parse::<u64>())
|
||||||
|
.collect::<Result<Vec<u64>, _>>()
|
||||||
|
.map_err(|e| err!("couldn't parse number: {}", e))?;
|
||||||
|
|
||||||
|
let (outlier, idx) = find_outlier(&numbers, 25)?;
|
||||||
|
|
||||||
|
let (min, max) = find_contiguous_range(&numbers, outlier, idx)?;
|
||||||
|
|
||||||
|
Ok(min + max)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const PROVIDED: &str = include_str!("../input/day09_provided.txt");
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_provided() {
|
||||||
|
let numbers = PROVIDED
|
||||||
|
.lines()
|
||||||
|
.map(|line| line.parse::<u64>().unwrap())
|
||||||
|
.collect::<Vec<u64>>();
|
||||||
|
|
||||||
|
assert_eq!(find_outlier(&numbers, 5).unwrap(), (127, 14));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_real() {
|
||||||
|
assert_eq!(part1(INPUT).unwrap(), 248131121);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_provided() {
|
||||||
|
let numbers = PROVIDED
|
||||||
|
.lines()
|
||||||
|
.map(|line| line.parse::<u64>().unwrap())
|
||||||
|
.collect::<Vec<u64>>();
|
||||||
|
|
||||||
|
let (outlier, idx) = find_outlier(&numbers, 5).unwrap();
|
||||||
|
|
||||||
|
let (min, max) = find_contiguous_range(&numbers, outlier, idx).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(min, 15);
|
||||||
|
assert_eq!(max, 47);
|
||||||
|
assert_eq!(min + max, 62);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_real() {
|
||||||
|
assert_eq!(part2(INPUT).unwrap(), 31580383);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,3 +6,4 @@ pub mod day05;
|
||||||
pub mod day06;
|
pub mod day06;
|
||||||
pub mod day07;
|
pub mod day07;
|
||||||
pub mod day08;
|
pub mod day08;
|
||||||
|
pub mod day09;
|
||||||
|
|
|
@ -9,6 +9,7 @@ use aoc2020::day05;
|
||||||
use aoc2020::day06;
|
use aoc2020::day06;
|
||||||
use aoc2020::day07;
|
use aoc2020::day07;
|
||||||
use aoc2020::day08;
|
use aoc2020::day08;
|
||||||
|
use aoc2020::day09;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let days: &[DayFunc] = &[
|
let days: &[DayFunc] = &[
|
||||||
|
@ -20,6 +21,7 @@ fn main() -> Result<()> {
|
||||||
day06::run,
|
day06::run,
|
||||||
day07::run,
|
day07::run,
|
||||||
day08::run,
|
day08::run,
|
||||||
|
day09::run,
|
||||||
];
|
];
|
||||||
|
|
||||||
aoc::run(days)
|
aoc::run(days)
|
||||||
|
|
Loading…
Reference in a new issue