93 lines
2.4 KiB
Rust
93 lines
2.4 KiB
Rust
use std::fs::File;
|
|
use std::io::prelude::*;
|
|
use std::io::BufReader;
|
|
use std::time::Instant;
|
|
|
|
use anyhow::Result;
|
|
|
|
const INPUT: &str = "input/input.txt";
|
|
|
|
fn find_invalid_num(nums: &[usize], preamble: usize) -> Option<usize> {
|
|
if let Some(num) = nums.windows(preamble + 1).find(|chunk| {
|
|
for num in &chunk[0..preamble] {
|
|
for other_num in &chunk[0..preamble] {
|
|
if num != other_num && num + other_num == chunk[preamble] {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
true
|
|
}) {
|
|
return Some(num[preamble]);
|
|
}
|
|
None
|
|
}
|
|
|
|
fn find_encryption_weakness(nums: &[usize], invalid_num: usize) -> Option<usize> {
|
|
let mut window_size = 2;
|
|
while window_size < 1000 {
|
|
if let Some(weakness) = nums
|
|
.windows(window_size)
|
|
.find(|chunk| chunk.iter().sum::<usize>() == invalid_num)
|
|
{
|
|
return Some(
|
|
weakness.iter().min().expect("non-empty slice")
|
|
+ weakness.iter().max().expect("non-empty slice"),
|
|
);
|
|
} else {
|
|
window_size += 1;
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
fn solve_part1(input_path: &str, preamble: usize) -> Result<usize> {
|
|
let file = File::open(input_path)?;
|
|
let reader = BufReader::new(file);
|
|
|
|
let nums = reader
|
|
.lines()
|
|
.map(|line| Ok(line?.parse()?))
|
|
.collect::<Result<Vec<usize>>>()?;
|
|
Ok(find_invalid_num(&nums, preamble).unwrap())
|
|
}
|
|
|
|
fn solve_part2(input_path: &str, invalid_num: usize) -> Result<usize> {
|
|
let file = File::open(input_path)?;
|
|
let reader = BufReader::new(file);
|
|
|
|
let nums = reader
|
|
.lines()
|
|
.map(|line| Ok(line?.parse()?))
|
|
.collect::<Result<Vec<usize>>>()?;
|
|
Ok(find_encryption_weakness(&nums, invalid_num).unwrap())
|
|
}
|
|
|
|
fn main() {
|
|
let mut now = Instant::now();
|
|
let part1 = solve_part1(INPUT, 25).unwrap();
|
|
println!("Part 1: {}", part1);
|
|
println!("(elapsed: {:?})", now.elapsed());
|
|
now = Instant::now();
|
|
println!("");
|
|
println!("Part 2: {}", solve_part2(INPUT, part1).unwrap());
|
|
println!("(elapsed: {:?})", now.elapsed());
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
const TEST_INPUT: &str = "input/test.txt";
|
|
|
|
#[test]
|
|
fn solves_part1() {
|
|
assert_eq!(solve_part1(TEST_INPUT, 5).unwrap(), 127);
|
|
}
|
|
|
|
#[test]
|
|
fn solves_part2() {
|
|
assert_eq!(solve_part2(TEST_INPUT, 127).unwrap(), 62);
|
|
}
|
|
}
|