2020: day09: part 1 and 2

This commit is contained in:
Antoine Martin 2020-12-09 06:35:18 +01:00
parent 09a9654a1b
commit a0611f1fb3
6 changed files with 1155 additions and 0 deletions

View file

@ -8,6 +8,7 @@ use aoc2020::day05;
use aoc2020::day06;
use aoc2020::day07;
use aoc2020::day08;
use aoc2020::day09;
fn aoc2020_all(c: &mut Criterion) {
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("day07", |b| b.iter(|| day07::run().unwrap()));
c.bench_function("day08", |b| b.iter(|| day08::run().unwrap()));
c.bench_function("day09", |b| b.iter(|| day09::run().unwrap()));
}
criterion_group! {

1000
aoc2020/input/day09.txt Normal file

File diff suppressed because it is too large Load diff

View 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
View 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);
}
}

View file

@ -6,3 +6,4 @@ pub mod day05;
pub mod day06;
pub mod day07;
pub mod day08;
pub mod day09;

View file

@ -9,6 +9,7 @@ use aoc2020::day05;
use aoc2020::day06;
use aoc2020::day07;
use aoc2020::day08;
use aoc2020::day09;
fn main() -> Result<()> {
let days: &[DayFunc] = &[
@ -20,6 +21,7 @@ fn main() -> Result<()> {
day06::run,
day07::run,
day08::run,
day09::run,
];
aoc::run(days)