79 lines
2.2 KiB
Rust

use std::cmp::Ordering;
use crate::common::{parse_input, Level};
fn task1() {
let raw_input = include_str!("./input.txt");
let safe_levels = parse_input(raw_input)
.into_iter()
.map(LevelState::from)
.filter(LevelState::is_all_safe)
.count();
println!("The solution to task 1 is {safe_levels}")
}
#[derive(PartialOrd, PartialEq, Debug, Copy, Clone)]
pub(crate) enum State {
Increase(usize),
Decrease(usize),
Stable,
}
impl State {
pub(crate) fn from_values(first: usize, second: usize) -> Self {
match second.cmp(&first) {
Ordering::Less => Self::Decrease(first.abs_diff(second)),
Ordering::Greater => Self::Increase(first.abs_diff(second)),
Ordering::Equal => Self::Stable,
}
}
pub(crate) fn is_safely_increasing(&self) -> bool {
matches!(self, State::Increase(1..=3))
}
pub(crate) fn is_safely_decreasing(&self) -> bool {
matches!(self, State::Decrease(1..=3))
}
}
pub(crate) struct LevelState(pub(crate) Vec<State>);
impl From<Level> for LevelState {
fn from(level: Level) -> Self {
let mut previous = None;
let mut level_state = Vec::with_capacity(level.0.len());
for current in level.0 {
if let Some(previous) = previous {
level_state.push(State::from_values(previous, current))
} else {
level_state.push(State::Stable);
}
previous = Some(current);
}
Self(level_state)
}
}
impl LevelState {
pub(crate) fn is_all_safe(&self) -> bool {
self.is_all_safely_increasing() || self.is_all_safely_decreasing()
}
fn is_all_safely_increasing(&self) -> bool {
self.is_all_changing(State::is_safely_increasing)
}
fn is_all_safely_decreasing(&self) -> bool {
self.is_all_changing(State::is_safely_decreasing)
}
fn is_all_changing(&self, verify: fn(&State) -> bool) -> bool {
let states = &self.0;
match &states[..] {
[State::Stable, tail @ ..] if tail.iter().all(verify) => true,
[State::Stable] | [] => true,
_ => false,
}
}
}