1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
//! This is my solution for [Advent of Code - Day 1 - _Sonar Sweep_](https://adventofcode.com/2021/day/1)
//!
//! The challenge today was to analyse a sequence of integer depths and determine a measure of
//! how often these were increasing.
//!
//! For part one, the challenge was to count the number of values that were greater than the
//! previous value in the list. [`count_increments`] has been written to do that by chaining
//! built-in methods on Rust's iterators.
//!
//! Part two expands on that, requiring the same count be run on the sums of a moving window of
//! three consecutive values over the input. [`sum_windows`] provides a vector of these sums, which
//! is suitable to then be passed to [`count_increments`] to produce the final answer. For this I
//! originally included itertools to use their `izip!` macro to zip three iterators together, each
//! offset by one more. I updated it to use [`slice::windows`] thanks to [@bjgill's](https://github.com/bjgill/advent-of-code-2021/blob/1f086dcb6d5cd9bc1152a9a0db87d16b67d2cdb2/src/bin/day1.rs#L20)
//! comment on the x-gov slack channel.
use std::fs;
/// This is the entry point for the day's puzzle solutions. It will load the input file, parse it
/// into a `Vec<i32>` and pass it to the relevant functions for each part.
pub fn run() {
let contents = fs::read_to_string("res/day-1-input").expect("Failed to read file");
let depths = contents
.lines()
.flat_map(|line| line.parse::<i32>().ok())
.collect();
println!(
"There are {} steps that increment",
count_increments(&depths)
);
println!(
"There are {} summed windows that increment",
count_increments(&sum_windows(&depths))
);
}
/// Iterate over a moving window of pairs, returning the count where the second number is greater
/// that the first.
///
/// # Example from puzzle specification
/// ```rust
/// let input = vec![
/// 199, // N/A - first item
/// 200, // yes
/// 208, // yes
/// 210, // yes
/// 200, // no
/// 207, // yes
/// 240, // yes
/// 269, // yes
/// 260, // no
/// 263 // yes
/// ];
///
/// assert_eq!(count_increments(&input), 7);
/// ```
fn count_increments(depths: &Vec<i32>) -> usize {
return depths
.iter()
// combine with itself, offset by one so that we're iterating over pairs of consecutive
// values
.zip(depths.iter().skip(1))
// include only those that increment
.filter(|(prev, curr)| curr > prev)
// return the count of number of entries that increment
.count();
}
/// Iterate over a moving window of three consecutive items, returning a vector where each item is
/// the sum of te current window.
///
/// # Example from puzzle specification
/// ```rust
/// assert_eq!(
/// sum_windows(&input),
/// vec!(
/// 607, // 199 + 200 + 208
/// 618, // 200 + 208 + 210
/// 618, // 208 + 210 + 200
/// 617, // 210 + 200 + 207
/// 647, // 200 + 207 + 240
/// 716, // 207 + 240 + 269
/// 769, // 240 + 269 + 260
/// 792 // 269 + 260 + 263
/// )
/// );
/// ```
fn sum_windows(depths: &Vec<i32>) -> Vec<i32> {
// create the moving window by combining iterators over the input offset by 0, 1, and 2
return depths
.windows(3)
// map those to the sum of the window
.map(|window| window.iter().sum())
// and coerce to the expected output type
.collect();
}
#[cfg(test)]
mod tests {
use crate::day_1::{count_increments, sum_windows};
#[test]
fn can_count_increments() {
assert_eq!(count_increments(&test_data()), 7)
}
fn test_data() -> Vec<i32> {
vec![199, 200, 208, 210, 200, 207, 240, 269, 260, 263]
}
#[test]
fn can_iterate_windows() {
assert_eq!(
sum_windows(&test_data()),
vec!(607, 618, 618, 617, 647, 716, 769, 792)
);
assert_eq!(count_increments(&sum_windows(&test_data())), 5);
}
}
