A fairly naive solution to Day 9.
This commit is contained in:
155
src/bin/xmas.rs
Normal file
155
src/bin/xmas.rs
Normal file
@@ -0,0 +1,155 @@
|
||||
use advent2020::errors::TopLevelError;
|
||||
use std::collections::VecDeque;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::ops::RangeInclusive;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct XmasChecker {
|
||||
preamble_length: usize,
|
||||
window: VecDeque<usize>,
|
||||
buffer: Vec<usize>,
|
||||
}
|
||||
|
||||
impl XmasChecker {
|
||||
fn new(preamble_length: usize) -> XmasChecker {
|
||||
XmasChecker {
|
||||
preamble_length,
|
||||
window: VecDeque::with_capacity(preamble_length + 1),
|
||||
buffer: Vec::with_capacity(preamble_length * 10),
|
||||
}
|
||||
}
|
||||
|
||||
fn push(&mut self, value: usize) -> bool {
|
||||
self.buffer.push(value);
|
||||
if self.window.len() != self.preamble_length {
|
||||
self.window.push_back(value);
|
||||
true
|
||||
} else {
|
||||
self.window.push_back(value);
|
||||
for i in 0..self.preamble_length {
|
||||
for j in 0..self.preamble_length {
|
||||
if i != j {
|
||||
let sum = self.window[i] + self.window[j];
|
||||
|
||||
if value == sum {
|
||||
let _ = self.window.pop_front();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let _ = self.window.pop_front();
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn find_range_summing_to(&self, value: usize) -> Option<RangeInclusive<usize>> {
|
||||
for i in 0..self.buffer.len() {
|
||||
for j in i + 1..self.buffer.len() {
|
||||
let possible_range = i..=j;
|
||||
let possible_answer: usize = self.buffer[possible_range].iter().sum();
|
||||
|
||||
if possible_answer == value {
|
||||
return Some(i..=j);
|
||||
}
|
||||
|
||||
if possible_answer > value {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn first_example() {
|
||||
let contents = fs::read_to_string("inputs/day9_test1.txt");
|
||||
let mut xmas_checker = XmasChecker::new(25);
|
||||
|
||||
for line in contents.unwrap().lines() {
|
||||
let next = usize::from_str(line).unwrap();
|
||||
assert!(xmas_checker.push(next));
|
||||
}
|
||||
|
||||
assert!(xmas_checker.clone().push(26));
|
||||
assert!(xmas_checker.clone().push(49));
|
||||
assert!(!xmas_checker.clone().push(100));
|
||||
assert!(!xmas_checker.clone().push(50));
|
||||
|
||||
// add the 45
|
||||
assert!(xmas_checker.push(45));
|
||||
|
||||
assert!(xmas_checker.clone().push(26));
|
||||
assert!(!xmas_checker.clone().push(65));
|
||||
assert!(xmas_checker.clone().push(64));
|
||||
assert!(xmas_checker.clone().push(66));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn second_example() {
|
||||
let contents = fs::read_to_string("inputs/day9_test2.txt");
|
||||
let mut xmas_checker = XmasChecker::new(5);
|
||||
|
||||
for line in contents.unwrap().lines() {
|
||||
let next = usize::from_str(line).unwrap();
|
||||
let result = xmas_checker.push(next);
|
||||
assert!((next == 127) || result);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn third_example() {
|
||||
let contents = fs::read_to_string("inputs/day9_test2.txt");
|
||||
let mut xmas_checker = XmasChecker::new(5);
|
||||
|
||||
for line in contents.unwrap().lines() {
|
||||
let next = usize::from_str(line).unwrap();
|
||||
let result = xmas_checker.push(next);
|
||||
assert!((next == 127) || result);
|
||||
}
|
||||
|
||||
assert_eq!(Some(2..=5), xmas_checker.find_range_summing_to(127));
|
||||
}
|
||||
|
||||
fn main() -> Result<(), TopLevelError> {
|
||||
let filename = env::args().skip(1).next().expect("No file argument given.");
|
||||
let contents = fs::read_to_string(filename)?;
|
||||
let mut xmas_checker = XmasChecker::new(25);
|
||||
|
||||
let mut first_bad_entry = None;
|
||||
|
||||
for line in contents.lines() {
|
||||
let next = usize::from_str(line).unwrap();
|
||||
|
||||
if !xmas_checker.push(next) {
|
||||
println!("Entry {} fails.", next);
|
||||
if first_bad_entry.is_none() {
|
||||
first_bad_entry = Some(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(bad_entry) = first_bad_entry {
|
||||
if let Some(range) = xmas_checker.find_range_summing_to(bad_entry) {
|
||||
println!(" resulting range: {:?}", range);
|
||||
let minimum_entry = xmas_checker.buffer[range.clone()]
|
||||
.iter()
|
||||
.min()
|
||||
.ok_or(TopLevelError::UnknownError)?;
|
||||
println!(" minimum entry: {}", minimum_entry);
|
||||
let maximum_entry = xmas_checker.buffer[range]
|
||||
.iter()
|
||||
.max()
|
||||
.ok_or(TopLevelError::UnknownError)?;
|
||||
println!(" maximum entry: {}", maximum_entry);
|
||||
println!(" sum: {}", minimum_entry + maximum_entry);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
Err(TopLevelError::NoSolutionFound)
|
||||
}
|
||||
Reference in New Issue
Block a user