summary refs log tree commit diff stats
path: root/2020/day-02/README.org
diff options
context:
space:
mode:
Diffstat (limited to '2020/day-02/README.org')
-rw-r--r--2020/day-02/README.org133
1 files changed, 133 insertions, 0 deletions
diff --git a/2020/day-02/README.org b/2020/day-02/README.org
new file mode 100644
index 0000000..93b1af0
--- /dev/null
+++ b/2020/day-02/README.org
@@ -0,0 +1,133 @@
+#+SETUPFILE: ~/.emacs.d/org-templates/level-3.org
+#+HTML_LINK_UP: ../../../writings/#aoc
+#+OPTIONS: toc:2
+#+EXPORT_FILE_NAME: index
+#+TITLE: Day 02 - Password Philosophy
+
+* Puzzle
+- This puzzle is taken from: https://adventofcode.com/2020/day/2
+
+Your flight departs in a few days from the coastal airport; the easiest
+way down to the coast from here is via toboggan.
+
+The shopkeeper at the North Pole Toboggan Rental Shop is having a bad
+day. "Something's wrong with our computers; we can't log in!" You ask if
+you can take a look.
+
+Their password database seems to be a little corrupted: some of the
+passwords wouldn't have been allowed by the Official Toboggan Corporate
+Policy that was in effect when they were chosen.
+
+To try to debug the problem, they have created a list (your puzzle
+input) of passwords (according to the corrupted database) and the
+corporate policy when that password was set.
+
+For example, suppose you have the following list:
+#+BEGIN_SRC
+1-3 a: abcde
+1-3 b: cdefg
+2-9 c: ccccccccc
+#+END_SRC
+
+Each line gives the password policy and then the password. The password
+policy indicates the lowest and highest number of times a given letter
+must appear for the password to be valid. For example, 1-3 a means that
+the password must contain a at least 1 time and at most 3 times.
+
+In the above example, 2 passwords are valid. The middle password, cdefg,
+is not; it contains no instances of b, but needs at least 1. The first
+and third passwords are valid: they contain one a or nine c, both within
+the limits of their respective policies.
+
+How many passwords are valid according to their policies?
+** Part 2
+While it appears you validated the passwords correctly, they don't seem
+to be what the Official Toboggan Corporate Authentication System is
+expecting.
+
+The shopkeeper suddenly realizes that he just accidentally explained the
+password policy rules from his old job at the sled rental place down the
+street! The Official Toboggan Corporate Policy actually works a little
+differently.
+
+Each policy actually describes two positions in the password, where 1
+means the first character, 2 means the second character, and so on. (Be
+careful; Toboggan Corporate Policies have no concept of "index zero"!)
+Exactly one of these positions must contain the given letter. Other
+occurrences of the letter are irrelevant for the purposes of policy
+enforcement.
+
+Given the same example list from above:
+
+- =1-3 a: abcde= is valid: position 1 contains a and position 3 does not.
+- =1-3 b: cdefg= is invalid: neither position 1 nor position 3 contains b.
+- =2-9 c: ccccccccc= is invalid: both position 2 and position 9 contain c.
+
+How many passwords are valid according to the new interpretation of the
+policies?
+* Solution
+Raku grammar is used to parse the file. I took the grammar from [[https://git.tyil.nl/advent-of-code/tree/2020/02.raku][tyil]]'s
+solution.
+#+BEGIN_SRC raku
+# Password grammar was taken from tyil's solution.
+grammar Password {
+    rule TOP { <num> '-' <num> <letter> ':' <password> }
+    token num { \d+ }
+    token letter { \w }
+    token password { \w+ }
+}
+#+END_SRC
+
+The program takes a positional input =$part= which instructs it on which
+part it should solve. The default is to solve for part 1.
+
+=$valid_passwords= stores the number of passwords that are considered
+valid. The checks are made inside the =if/elsif= loop & it continues from
+there only if the password is considered valid.
+#+BEGIN_SRC raku
+sub MAIN (
+    # Part to run.
+    Int $part where * == 1|2 = 1
+) {
+    my $valid_passwords = 0;
+
+    for "input".IO.lines -> $entry {
+        if Password.parse($entry) -> $match {
+            if $part == 1 {
+                ...
+            } elsif $part == 2 {
+                ...
+            }
+            # All checks were completed & this is a valid password.
+            $valid_passwords++;
+        }
+    }
+    say "Part $part: " ~ $valid_passwords;
+}
+#+END_SRC
+
+Nothing fancy is done, we just count the number of times each character
+is used & then perform the check.
+#+BEGIN_SRC raku
+my %chars;
+$match<password>.comb.map({ %chars{$_}++ });
+
+# Check if the letter exists in the password.
+next unless %chars{$match<letter>};
+
+# Check for length.
+next unless $match<num>[0].Int <= %chars{$match<letter>};
+next unless %chars{$match<letter>} <= $match<num>[1].Int;
+#+END_SRC
+** Part 2
+This part too just performs the check.
+#+BEGIN_SRC raku
+elsif $part == 2 {
+    my $combed = $match<password>.comb;
+    my $first = $match<num>[0].Int - 1;
+    my $second = $match<num>[1].Int - 1;
+
+    next if $combed[$first] eq $combed[$second];
+    next unless $combed[$first] eq $match<letter> || $combed[$second] eq $match<letter>;
+}
+#+END_SRC