|
|
@@ -0,0 +1,225 @@
|
|
|
+/*
|
|
|
+--- Day 4: Secure Container ---
|
|
|
+
|
|
|
+You arrive at the Venus fuel depot only to discover it's protected by a password. The Elves had written the password on a sticky note, but someone threw it out.
|
|
|
+
|
|
|
+However, they do remember a few key facts about the password:
|
|
|
+
|
|
|
+ It is a six-digit number.
|
|
|
+ The value is within the range given in your puzzle input.
|
|
|
+ Two adjacent digits are the same (like 22 in 122345).
|
|
|
+ Going from left to right, the digits never decrease; they only ever increase or stay the same (like 111123 or 135679).
|
|
|
+
|
|
|
+Other than the range rule, the following are true:
|
|
|
+
|
|
|
+ 111111 meets these criteria (double 11, never decreases).
|
|
|
+ 223450 does not meet these criteria (decreasing pair of digits 50).
|
|
|
+ 123789 does not meet these criteria (no double).
|
|
|
+
|
|
|
+How many different passwords within the range given in your puzzle input meet these criteria?
|
|
|
+
|
|
|
+Your puzzle input is 402328-864247.
|
|
|
+
|
|
|
+--- Part Two ---
|
|
|
+
|
|
|
+An Elf just remembered one more important detail: the two adjacent matching digits are not part of a larger group of matching digits.
|
|
|
+
|
|
|
+Given this additional criterion, but still ignoring the range rule, the following are now true:
|
|
|
+
|
|
|
+ 112233 meets these criteria because the digits never decrease and all repeated digits are exactly two digits long.
|
|
|
+ 123444 no longer meets the criteria (the repeated 44 is part of a larger group of 444).
|
|
|
+ 111122 meets the criteria (even though 1 is repeated more than twice, it still contains a double 22).
|
|
|
+
|
|
|
+How many different passwords within the range given in your puzzle input meet all of the criteria?
|
|
|
+*/
|
|
|
+
|
|
|
+use std::collections::VecDeque;
|
|
|
+use std::io::stdin;
|
|
|
+
|
|
|
+use crate::puzzle::options::Options;
|
|
|
+use crate::puzzle::traits::{Create, Solve};
|
|
|
+
|
|
|
+pub struct Puzzle {
|
|
|
+ options: Options,
|
|
|
+ lower_bound: i32,
|
|
|
+ upper_bound: i32,
|
|
|
+}
|
|
|
+
|
|
|
+impl Create for Puzzle {
|
|
|
+ fn new(opt: Options) -> Box<dyn Solve> {
|
|
|
+ Box::new(Self {
|
|
|
+ options: opt,
|
|
|
+ lower_bound: if opt.prompt {
|
|
|
+ Self::prompt_for_bound()
|
|
|
+ } else {
|
|
|
+ Self::default_lower_bound()
|
|
|
+ },
|
|
|
+ upper_bound: if opt.prompt {
|
|
|
+ Self::prompt_for_bound()
|
|
|
+ } else {
|
|
|
+ Self::default_upper_bound()
|
|
|
+ },
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl Solve for Puzzle {
|
|
|
+ fn solve(&self) -> i32 {
|
|
|
+ match self.options.puzzle {
|
|
|
+ 1 => self.solve_p1(),
|
|
|
+ 2 => self.solve_p2(),
|
|
|
+ x => panic!("Unknown puzzle {}", x),
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl Puzzle {
|
|
|
+ pub fn solve_p1(&self) -> i32 {
|
|
|
+ let mut num_matches = 0;
|
|
|
+ for value in (&self).lower_bound..(&self).upper_bound + 1 {
|
|
|
+ if Self::is_matching_pattern_1(value) {
|
|
|
+ num_matches += 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ num_matches
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn solve_p2(&self) -> i32 {
|
|
|
+ let mut num_matches = 0;
|
|
|
+ for value in (&self).lower_bound..(&self).upper_bound + 1 {
|
|
|
+ if Self::is_matching_pattern_2(value) {
|
|
|
+ num_matches += 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ num_matches
|
|
|
+ }
|
|
|
+
|
|
|
+ fn is_matching_pattern_1(i: i32) -> bool {
|
|
|
+ let mut previous = 0;
|
|
|
+ let mut has_pair = false;
|
|
|
+ let mut digits: VecDeque<i32> = VecDeque::new();
|
|
|
+
|
|
|
+ {
|
|
|
+ let mut num = i;
|
|
|
+
|
|
|
+ while num > 0 {
|
|
|
+ let mod_num = num % 10;
|
|
|
+ digits.push_front(mod_num);
|
|
|
+ num /= 10;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for digit in digits {
|
|
|
+ if digit < previous {
|
|
|
+ return false;
|
|
|
+ } else if digit == previous {
|
|
|
+ has_pair = true;
|
|
|
+ } else {
|
|
|
+ previous = digit;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ has_pair
|
|
|
+ }
|
|
|
+
|
|
|
+ fn is_matching_pattern_2(i: i32) -> bool {
|
|
|
+ let mut previous = 0;
|
|
|
+ let mut has_pair = false;
|
|
|
+ let mut subsequent_dupes = 0;
|
|
|
+ let mut digits: VecDeque<i32> = VecDeque::new();
|
|
|
+
|
|
|
+ {
|
|
|
+ let mut num = i;
|
|
|
+
|
|
|
+ while num > 0 {
|
|
|
+ let mod_num = num % 10;
|
|
|
+ digits.push_front(mod_num);
|
|
|
+ num /= 10;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for digit in digits {
|
|
|
+ if digit < previous {
|
|
|
+ return false;
|
|
|
+ } else if digit == previous {
|
|
|
+ subsequent_dupes += 1;
|
|
|
+ } else {
|
|
|
+ if subsequent_dupes == 1 {
|
|
|
+ has_pair = true;
|
|
|
+ }
|
|
|
+ previous = digit;
|
|
|
+ subsequent_dupes = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // one last check since abcdXX won't match otherwise
|
|
|
+ if subsequent_dupes == 1 {
|
|
|
+ has_pair = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ has_pair
|
|
|
+ }
|
|
|
+
|
|
|
+ fn prompt_for_bound() -> i32 {
|
|
|
+ println!("enter boundry: ");
|
|
|
+ let mut input = String::new();
|
|
|
+
|
|
|
+ match stdin().read_line(&mut input) {
|
|
|
+ Ok(_) => {}
|
|
|
+ Err(e) => panic!("Failed to read input: {}", e),
|
|
|
+ }
|
|
|
+
|
|
|
+ match input.trim().parse::<i32>() {
|
|
|
+ Ok(i) => i,
|
|
|
+ Err(e) => panic!("failed to parse {}: {}", input, e),
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ fn default_lower_bound() -> i32 {
|
|
|
+ 402328
|
|
|
+ }
|
|
|
+
|
|
|
+ fn default_upper_bound() -> i32 {
|
|
|
+ 864247
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[cfg(test)]
|
|
|
+mod puzzle_1 {
|
|
|
+ use super::Puzzle;
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn match_sample_1() {
|
|
|
+ assert_eq!(Puzzle::is_matching_pattern_1(111111), true)
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn match_sample_2() {
|
|
|
+ assert_eq!(Puzzle::is_matching_pattern_1(223450), false)
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn match_sample_3() {
|
|
|
+ assert_eq!(Puzzle::is_matching_pattern_1(123789), false)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[cfg(test)]
|
|
|
+mod puzzle_2 {
|
|
|
+ use super::Puzzle;
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn match_sample_1() {
|
|
|
+ assert_eq!(Puzzle::is_matching_pattern_2(112233), true)
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn match_sample_2() {
|
|
|
+ assert_eq!(Puzzle::is_matching_pattern_2(123444), false)
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn match_sample_3() {
|
|
|
+ assert_eq!(Puzzle::is_matching_pattern_2(111122), true)
|
|
|
+ }
|
|
|
+}
|