--- /dev/null
+fn input() -> &'static str {
+ include_str!("../input/day02.txt")
+}
+
+fn parse(input: &str) -> Vec<Vec<i32>> {
+ input
+ .split_terminator('\n')
+ .map(|l| l.split_whitespace().map(|n| n.parse().unwrap()).collect())
+ .collect()
+}
+
+fn is_monotonic(d: &[i32]) -> bool {
+ let (inc, dec, _) = d
+ .iter()
+ .fold((0, 0, None as Option<i32>), |(inc, dec, k), n| match k {
+ Some(k) => {
+ if n - k > inc {
+ (n - k, dec, Some(*n))
+ } else if n - k < dec {
+ (inc, n - k, Some(*n))
+ } else {
+ (inc, dec, Some(*n))
+ }
+ }
+ None => (inc, dec, Some(*n)),
+ });
+ inc > 0 && dec == 0 || inc == 0 && dec < 0
+}
+
+fn safe_gaps(d: &[i32]) -> bool {
+ d.iter()
+ .zip(d.iter().skip(1))
+ .map(|(l, &r)| l.abs_diff(r))
+ .all(|t| (1..=3).contains(&t))
+}
+
+fn is_safe(d: &[i32]) -> bool {
+ is_monotonic(d) && safe_gaps(d)
+}
+
+fn is_safe_dampened(d: &[i32]) -> bool {
+ is_safe(d)
+ || (0..d.len())
+ .map(|i| d.iter().take(i).chain(d.iter().skip(i + 1)))
+ .map(|v| is_safe(&v.copied().collect::<Vec<_>>()))
+ .any(|x| x)
+}
+
+pub fn part1() {
+ let vecs = parse(input());
+ let n = vecs.iter().map(|v| is_safe(v)).filter(|&x| x).count();
+ println!("Day 2 Part 1: {}", n);
+}
+
+pub fn part2() {
+ let vecs = parse(input());
+ let n = vecs
+ .iter()
+ .map(|v| is_safe_dampened(v))
+ .filter(|&x| x)
+ .count();
+ println!("Day 2 Part 2: {}", n);
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ const INPUT_STR: &str = concat!(
+ "7 6 4 2 1\n",
+ "1 2 7 8 9\n",
+ "9 7 6 2 1\n",
+ "1 3 2 4 5\n",
+ "8 6 4 4 1\n",
+ "1 3 6 7 9\n",
+ );
+
+ #[test]
+ fn test_parse() {
+ assert_eq!(
+ parse(INPUT_STR),
+ vec![
+ vec![7, 6, 4, 2, 1],
+ vec![1, 2, 7, 8, 9],
+ vec![9, 7, 6, 2, 1],
+ vec![1, 3, 2, 4, 5],
+ vec![8, 6, 4, 4, 1],
+ vec![1, 3, 6, 7, 9],
+ ]
+ )
+ }
+
+ #[test]
+ fn test_monotonicity() {
+ let vecs = parse(INPUT_STR);
+ assert_eq!(
+ vecs.iter().map(|v| is_monotonic(v)).collect::<Vec<_>>(),
+ vec![true, true, true, false, true, true]
+ )
+ }
+
+ #[test]
+ fn test_safe_gaps() {
+ let vecs = parse(INPUT_STR);
+ assert_eq!(
+ vecs.iter().map(|v| safe_gaps(v)).collect::<Vec<_>>(),
+ vec![true, false, false, true, false, true]
+ )
+ }
+
+ #[test]
+ fn test_dampened_gaps() {
+ let vecs = parse(INPUT_STR);
+ assert_eq!(
+ vecs.iter().map(|v| is_safe_dampened(v)).collect::<Vec<_>>(),
+ vec![true, false, false, true, true, true]
+ )
+ }
+}