After a first day of manipulating numbers, Day 2 is all about manipulating caracters and strings. The problem’s context is about verifying that a password is compliant with some simple rules.
For example, let’s take a look at this input set:
1-3 a: abcde 1-3 b: cdefg 2-9 c: ccccccccc
The left-hand part of each line defines the password rule, the right-hand part is the actual password to test. And so, with the example set above, we have the following output:
1-3 a: abcde # Password is valid 1-3 b: cdefg # Password id invalid 2-9 c: ccccccccc # Password is valid
The objective of this first part is to determine how many passwords in your
input data are valid. So, we are simply going to check if the password follows
its rule, and increment a
count variable if it’s actually the case.
A difficulty here might be to correctly parse the input data. Thankfully, they all have the same structure and it’s just a matter of taking things carefully. In the snippet below, I’m taking things really slowly to make sure that every step is clear.
line = "1-3 a: abcde" # This is the first line of the example data set left_part = line.split(": ") # left_part <- "1-3 a" min_max = left_part.split(" ") # min_max <- "1-3" min_value = int(min_max.split("-")) max_value = int(min_max.split("-")) letter = left_part[-1] # The letter is always at the end of left_part password = line.split(": ") # The password is always the right part of line
After that, it is just a matter of creating a
count variable and checking if
the password complies with the rule:
for line in lines: # Do the part above to appropriately parse the input line count = 0 if min_value <= password.count(letter) <= max_value: count += 1
And that should be it for Part 1!
The second part (as every second part) is a little trickier. We are told that the rules are not to be interpreted as we did in Part 1. Instead of representing the lowest and highest number of times a letter must appear in the password, these numbers now represent positions in the password. And so, a password is now considered valid if and only if the given letter is present in exactly one of the positions. To illustrate this new rule, let’s take a look at the example data:
1-3 a: abcde # Valid because 'a' is in position 1 and not in position 3 1-3 b: cdefg # Invalid because 'b' is not in position 1 nor in position 3 2-9 c: ccccccccc # Invalid because 'c' appears in both positions 1 and 3
The snippet written to parse the data is still valid. The names of the variables could change to be more closer to their actual use in the final solution, but that will do for me now). Solving this problem is, once again, a matter of correctly identifying the condition under which a password is valid. Written in pseudocode, it could be summarised with the following declaration:
password[min] == letter or password[max] == letter
But if that is the case,
password[min]must be different from
We can thus write the following program to solve Part 2:
for line in lines: # Do the part to appropriately parse the input line count = 0 if (password[min] == letter or password[max] == letter) and (password[min] != password[max]): count += 1
Concepts and difficulties
In Day 2, the difficulties are mainly concerned with parsing correctly the input data. Looking at the input data, we can quickly identify a structure (or a pattern) that is always present: we need to make use of this pattern when splitting each line.
Then, Day 2’s problem is mostly about writing up fairly simple conditions. So it’s a good way to practice that if you are still struggling with those.