use std::{
fs::File,
io::{BufRead, BufReader},
path::Path,
};
pub fn solve(input: &Path) -> anyhow::Result<()> {
println!("part one: {}", part_one(input)?);
println!("part two: {}", part_two(input)?);
Ok(())
}
fn part_one(input: &Path) -> anyhow::Result<i32> {
let reader = BufReader::new(File::open(input)?);
let mut reports: Vec<Vec<i32>> = vec![];
for line in reader.lines() {
reports.push(
line?
.split_whitespace()
.map(|n| -> i32 { n.parse().unwrap() })
.collect(),
);
}
let mut safe = 0;
for r in reports {
let mut s = 0;
let mut safes: i32 = 0;
let mut last_level = None;
for current in &r {
if last_level.is_none() {
last_level = Some(current);
continue;
}
let last = last_level.unwrap();
let diff = (current - last).abs();
if diff < 4 && diff > 0 {
match current.cmp(last) {
std::cmp::Ordering::Greater => safes += 1,
std::cmp::Ordering::Less => safes -= 1,
_ => {}
}
if safes.abs() == (r.len() as i32) - 1 {
s = 1;
}
}
last_level = Some(current);
}
safe += s;
}
Ok(safe)
}
fn part_two(input: &Path) -> anyhow::Result<i32> {
let reader = BufReader::new(File::open(input)?);
let mut reports: Vec<Vec<i32>> = vec![];
for line in reader.lines() {
reports.push(
line?
.split_whitespace()
.map(|n| -> i32 { n.parse().unwrap() })
.collect(),
);
}
let mut safe = 0;
for r in reports {
let mut s = 0;
for i in 0..r.len() {
let mut a = r.clone();
a.remove(i);
if is_safe_two(a) == 1 {
s = 1;
break;
}
}
safe += s;
}
Ok(safe)
}
fn is_safe_two(r: Vec<i32>) -> i32 {
let mut s = 0;
let mut safes: i32 = 0;
let mut last_level = None;
for current in &r {
if last_level.is_none() {
last_level = Some(current);
continue;
}
let last = last_level.unwrap();
let diff = (current - last).abs();
if diff < 4 && diff > 0 {
match current.cmp(last) {
std::cmp::Ordering::Greater => safes += 1,
std::cmp::Ordering::Less => safes -= 1,
_ => {}
}
if safes.abs() == (r.len() as i32) - 1 {
s = 1;
}
}
last_level = Some(current);
}
s
}