135 lines
2.8 KiB
Rust
135 lines
2.8 KiB
Rust
use std::str::SplitWhitespace;
|
|
|
|
pub fn run() {
|
|
let input = include_str!("input");
|
|
let safe = input
|
|
.lines()
|
|
.map(SplitWhitespaceNumbers::new)
|
|
.filter_map(|mut line| is_safe(&mut line))
|
|
.count();
|
|
|
|
println!("1. {}", safe); // 510
|
|
|
|
let safe_corrected = input
|
|
.lines()
|
|
.map(ExpandedSplitWhitespaceNumbers::new)
|
|
.filter_map(|mut line| is_safe_corrected(&mut line))
|
|
.count();
|
|
println!("2. {}", safe_corrected); // 553
|
|
}
|
|
|
|
struct SplitWhitespaceNumbers<'a> {
|
|
line: SplitWhitespace<'a>,
|
|
}
|
|
|
|
struct ExpandedSplitWhitespaceNumbers {
|
|
line: Vec<i32>,
|
|
skip_index: Option<i32>,
|
|
}
|
|
|
|
impl ExpandedSplitWhitespaceNumbers {
|
|
fn new(line: &str) -> Self {
|
|
let line = SplitWhitespaceNumbers::new(line).collect();
|
|
Self {
|
|
line,
|
|
skip_index: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Iterator for ExpandedSplitWhitespaceNumbers {
|
|
type Item = Vec<i32>;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let mut v = self.line.clone();
|
|
if let Some(index) = self.skip_index {
|
|
if index as usize >= v.len() {
|
|
return None;
|
|
}
|
|
|
|
v.remove(index as usize);
|
|
self.skip_index = Some(index + 1);
|
|
} else {
|
|
self.skip_index = Some(0);
|
|
}
|
|
|
|
Some(v)
|
|
}
|
|
}
|
|
|
|
impl<'a> SplitWhitespaceNumbers<'a> {
|
|
fn new(line: &'a str) -> Self {
|
|
SplitWhitespaceNumbers {
|
|
line: line.split_whitespace(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> Iterator for SplitWhitespaceNumbers<'a> {
|
|
type Item = i32;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let c = self.line.next();
|
|
if c.is_none() {
|
|
return None;
|
|
}
|
|
|
|
let c = c.unwrap();
|
|
let num = c.parse::<i32>().unwrap();
|
|
Some(num)
|
|
}
|
|
}
|
|
|
|
fn is_safe_corrected<T>(numbers: &mut T) -> Option<bool>
|
|
where
|
|
T: Iterator<Item = Vec<i32>>,
|
|
{
|
|
for variant in numbers.into_iter() {
|
|
if is_safe(&mut variant.into_iter()).is_some() {
|
|
return Some(true);
|
|
}
|
|
}
|
|
|
|
None
|
|
}
|
|
|
|
fn is_safe<T>(numbers: &mut T) -> Option<bool>
|
|
where
|
|
T: Iterator<Item = i32>,
|
|
{
|
|
let first = numbers.next().unwrap();
|
|
let second = numbers.next().unwrap();
|
|
let incr = if second - first > 0 { 1 } else { -1 };
|
|
let mut cur = second;
|
|
|
|
if !is_safe_interval(first, second, incr) {
|
|
return None;
|
|
}
|
|
|
|
loop {
|
|
let next = numbers.next();
|
|
if next.is_none() {
|
|
break;
|
|
}
|
|
|
|
let next = next.unwrap();
|
|
if !is_safe_interval(cur, next, incr) {
|
|
return None;
|
|
}
|
|
|
|
cur = next;
|
|
}
|
|
|
|
Some(true)
|
|
}
|
|
|
|
fn is_safe_interval(first: i32, second: i32, incr: i32) -> bool {
|
|
let diff = second - first;
|
|
if diff == 0 {
|
|
return false;
|
|
}
|
|
|
|
let norm = diff * incr;
|
|
norm > 0 && norm < 4
|
|
}
|