Hello Again! We’ll be looking at the solution for puzzles on Day-02 of Advent of Code using rust.
Spoilers Ahead! The full solution available to this puzzle is available here
Puzzle Part 01:
Given a list of passwords find the number of passwords that match a password policy, wherein the input looks like:
On line 1: 1-3
represents the minimum(1)-maximum(3) number of occurences of the letter a
. Similarly on line 3: 2-9
represents the minimum(2)-maximum(9) number of occurences of the character c
. The is our password policy.
The problem is to evaluate if the password string on the right, (for eg. abcde on line1) is valid based on the policy provided on a given line and if so, how many such passwords we have in the input. (if this is slightly confusing, going through the problem statement in the link mentioned above, might help).
Now that we have the problem out of the way, let’s break this down into how we could solve it.
The algorithm to solve the problem would look something like:
- Parse the input.txt file and convert that into an array of lines
- Each line represents a
policy : password
combination. So let’s parse these values into variables. We denote this combination using the variablepolicy_password
in the code snippets below. - Find the frequency of all characters in the password. For our usecase we can use a
HashMap<char, i32>
in order to keep track of all the occurences of a specified character. - Then we can lookup the hashmap for the letter mentioned in our policy, and if it meets our min-max bounds. If it meets these conditions, hurray! the password is valid, else it is not.
- Finally, return a
count
of all such valid passwords.
Now that we know how to go about the validation, let’s write some basic logic to parse the values into variables, setup some structs and traits for better extensibility. If you think about it, a Password Policy is something that could change in the future. (you’ll see in part 02, that it does change, in fact.)
Let’s write some logic to parse the input line. The logic uses basic string .split
and indices to parse values, because the input is deterministic and all values are valid inputs (although, the error handling could be slightly bettter 😅)
The crop_letters_after
function takes in a string slice and a position, and returns a cropped string with characters from 0 to position
:
There are some other ways of parsing the input. For eg. we could also use regex to parse the string, into named capture groups (or) if you want to go the extra mile use a custom parser combinator like nom.
Now let’s implement the ValidatePassword
trait for our PasswordPolicy. The validate
function returns true / false depending on whether the given password, meets the criteria.
Finally, we have a simple counter that increments for every .validate
that returns true. The value of the counter represents the number of valid passwords.
Puzzle Part 02
As I hinted upon earlier, the Part 02 the input passwords are still the same, but the policy is different. Let’s look at the sample input again:
The main difference from Part 01, here is: On line 1: 1-3
no longer represents the number of occurences of letter ‘a’, but rather represents the index at which the letter ‘a’ should be present in the given password string. Note that the password is NOT zero-indexed but indexed from 1.
Let’s rename our PasswordPolicy
struct to OldPasswordPolicy
define a new struct called NewPasswordPolicy
.
Alright! Now lets initial the new Password Policy. Since we have two PolicyTypes
we can have an enum
that can be later used to switch between implementations, as necessary.
The PartialEq
trait is derived here, so that we can match / equate enum values.
The logic we used to parse the input is still the same, as the input hasn’t changed. However our policy
should be an instance of NewPasswordPolicy
and we wrap the logic inside a function is_valid
which abstracts away the implementation details of the validation performed for a given PolicyType.
Now let’s implement our ValidatePassword
trait for the new policy.
There’s some glue code required to call these functions, and to parse the input file which can be found in the full solution linked above.
That’s all for AOC Day 02. See you tomorrow!