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
121
122
123
//! # [Day 4: High-Entropy Passphrases](http://adventofcode.com/2017/day/4)
//!
//! A new system policy has been put in place that requires all accounts to
//! use a *passphrase* instead of simply a pass*word*. A passphrase consists
//! of a series of words (lowercase letters) separated by spaces.

/// To ensure security, a valid passphrase must contain no duplicate words.
///
/// For example:
///
/// -   `aa bb cc dd ee` is valid.
///
///     ```
///     # use advent_solutions::advent2017::day04::is_valid_part1;
///     assert_eq!(is_valid_part1("aa bb cc dd ee"), true);
///     ```
///
/// -   `aa bb cc dd aa` is not valid - the word `aa` appears more than
///     once.
///
///     ```
///     # use advent_solutions::advent2017::day04::is_valid_part1;
///     assert_eq!(is_valid_part1("aa bb cc dd aa"), false);
///     ```
///
/// -   `aa bb cc dd aaa` is valid - `aa` and `aaa` count as different
///     words.
///
///     ```
///     # use advent_solutions::advent2017::day04::is_valid_part1;
///     assert_eq!(is_valid_part1("aa bb cc dd aaa"), true);
///     ```
pub fn is_valid_part1(passphrase: &str) -> bool {
    passphrase.split(' ')
        .all(|word| passphrase.split(' ')
            .filter(|w| &word == w)
            .count() == 1
        )
}

/// The system's full passphrase list is available as your puzzle input.
/// *How many passphrases are valid?*
pub fn part1(input: &str) -> usize {
    input.lines()
        .filter(|passphrase| is_valid_part1(passphrase))
        .count()
}

/// For added security, <span title="Because as everyone knows, the number of
/// rules is proportional to the level of security.">yet another system policy
/// </span> has been put in place. Now, a valid passphrase must contain no two
/// words that are anagrams of each other - that is, a passphrase is invalid
/// if any word's letters can be rearranged to form any other word in the
/// passphrase.
///
/// For example:
///
/// -  `abcde fghij` is a valid passphrase.
///
///   ```
///   # use advent_solutions::advent2017::day04::is_valid_part2;
///   assert_eq!(is_valid_part2("abcde fghij"), true);
///   ```
///
/// - `abcde xyz ecdab` is not valid - the letters from the third word can
///   be rearranged to form the first word.
///
///   ```
///   # use advent_solutions::advent2017::day04::is_valid_part2;
///   assert_eq!(is_valid_part2("abcde xyz ecdab"), false);
///   ```
///
/// - `a ab abc abd abf abj` is a valid passphrase, because *all* letters
///   need to be used when forming another word.
///
///   ```
///   # use advent_solutions::advent2017::day04::is_valid_part2;
///   assert_eq!(is_valid_part2("a ab abc abd abf abj"), true);
///   ```
///
/// - `iiii oiii ooii oooi oooo` is valid.
///
///   ```
///   # use advent_solutions::advent2017::day04::is_valid_part2;
///   assert_eq!(is_valid_part2("iiii oiii ooii oooi oooo"), true);
///   ```
///
/// - `oiii ioii iioi iiio` is not valid - any of these words can be
///   rearranged to form any other word.
///
///   ```
///   # use advent_solutions::advent2017::day04::is_valid_part2;
///   assert_eq!(is_valid_part2("oiii ioii iioi iiio"), false);
///   ```
pub fn is_valid_part2(passphrase: &str) -> bool {
    passphrase.split(' ')
        .all(|a| {
            let mut a_chars = a.chars().collect::<Vec<_>>();
            a_chars.sort();

            passphrase.split(' ')
                .filter(|b| {
                    let mut b_chars = b.chars().collect::<Vec<_>>();
                    b_chars.sort();

                    a_chars == b_chars
                })
                .count() == 1
        })
}

/// Under this new system policy, *how many passphrases are valid?*
pub fn part2(input: &str) -> usize {
    input.lines()
        .filter(|passphrase| is_valid_part2(passphrase))
        .count()
}

pub fn parse_input(input: &str) -> &str {
    input
}

test_day!("04", 477, 167);