From c8fd7ad9ba4f3c04b0eacda954ba8440ba0a8a27 Mon Sep 17 00:00:00 2001 From: AKU Date: Sat, 27 Nov 2021 19:56:01 +0000 Subject: [PATCH] Add 2020-02 Signed-off-by: AKU --- .../2020/02-passwordPhilosophy/README.md | 31 ++++++ .../2020/02-passwordPhilosophy/benchmark.txt | 23 +++++ .../02-passwordPhilosophy/go/challenge.go | 97 ++++++++++++++++++ .../2020/02-passwordPhilosophy/info.json | 17 ++++ .../2020/02-passwordPhilosophy/py/__init__.py | 98 +++++++++++++++++++ 5 files changed, 266 insertions(+) create mode 100644 challenges/2020/02-passwordPhilosophy/README.md create mode 100644 challenges/2020/02-passwordPhilosophy/benchmark.txt create mode 100644 challenges/2020/02-passwordPhilosophy/go/challenge.go create mode 100644 challenges/2020/02-passwordPhilosophy/info.json create mode 100644 challenges/2020/02-passwordPhilosophy/py/__init__.py diff --git a/challenges/2020/02-passwordPhilosophy/README.md b/challenges/2020/02-passwordPhilosophy/README.md new file mode 100644 index 0000000..4a792ff --- /dev/null +++ b/challenges/2020/02-passwordPhilosophy/README.md @@ -0,0 +1,31 @@ +# [Day 2: Password Philosophy](https://adventofcode.com/2020/day/2) + +
Script output + +``` +❯ python .\python\ +AoC 2020: day 2 - Password Philosophy +Python 3.8.5 + +Test cases +1.1 pass +2.1 pass + +Answers +Part 1: 500 +Part 2: 313 + +❯ go run .\go\ +AoC 2020: day 2 - Password Philosophy +Go go1.15.2 + +Test cases +1.1 pass +2.1 pass + +Answers +Part 1: 500 +Part 2: 313 +``` + +
diff --git a/challenges/2020/02-passwordPhilosophy/benchmark.txt b/challenges/2020/02-passwordPhilosophy/benchmark.txt new file mode 100644 index 0000000..aa7f21b --- /dev/null +++ b/challenges/2020/02-passwordPhilosophy/benchmark.txt @@ -0,0 +1,23 @@ +Day 2 (Password Philosophy) benchmark + +Dir: challenges/2020/02-passwordPhilosophy +Runs per part: 50 +-------------------------------------------------------------------------------- +Golang + +benchmark.part.1.avg: 0.001280 seconds +benchmark.part.1.min: 0.000806 seconds +benchmark.part.1.max: 0.002234 seconds +benchmark.part.2.avg: 0.001383 seconds +benchmark.part.2.min: 0.000786 seconds +benchmark.part.2.max: 0.005438 seconds +-------------------------------------------------------------------------------- +Python + +benchmark.part.1.avg: 0.005367 seconds +benchmark.part.1.min: 0.002311 seconds +benchmark.part.1.max: 0.010500 seconds +benchmark.part.2.avg: 0.004618 seconds +benchmark.part.2.min: 0.001737 seconds +benchmark.part.2.max: 0.011591 seconds +-------------------------------------------------------------------------------- diff --git a/challenges/2020/02-passwordPhilosophy/go/challenge.go b/challenges/2020/02-passwordPhilosophy/go/challenge.go new file mode 100644 index 0000000..17b067e --- /dev/null +++ b/challenges/2020/02-passwordPhilosophy/go/challenge.go @@ -0,0 +1,97 @@ +package challenge + +import ( + "regexp" + "strconv" + "strings" + + "github.com/codemicro/adventOfCode/lib/aocgo" +) + +type Challenge struct { + aocgo.BaseChallenge +} + +func (c Challenge) One(instr string) (interface{}, error) { + inputSlice := parse(instr) + + type Password struct { + plaintext string + targetLetter rune + minRepeats int + maxRepeats int + } + + var passwords []Password + for _, line := range inputSlice { + matches := parserRegex.FindAllStringSubmatch(line, -1) + miR, _ := strconv.Atoi(matches[0][1]) + maR, _ := strconv.Atoi(matches[0][2]) + passwords = append(passwords, Password{ + plaintext: matches[0][4], + targetLetter: rune(matches[0][3][0]), + minRepeats: miR, + maxRepeats: maR, + }) + } + + var num_valid_passwords int + + for _, password := range passwords { + var target_letter_count int + for _, char := range password.plaintext { + if char == password.targetLetter { + target_letter_count += 1 + } + } + + if (target_letter_count >= password.minRepeats) && (target_letter_count <= password.maxRepeats) { + num_valid_passwords += 1 + } + } + + return num_valid_passwords, nil +} + +func (c Challenge) Two(instr string) (interface{}, error) { + inputSlice := parse(instr) + + type Password struct { + plaintext string + targetLetter rune + positionOne int + positionTwo int + } + + var passwords []Password + for _, line := range inputSlice { + matches := parserRegex.FindAllStringSubmatch(line, -1) + miR, _ := strconv.Atoi(matches[0][1]) + maR, _ := strconv.Atoi(matches[0][2]) + passwords = append(passwords, Password{ + plaintext: matches[0][4], + targetLetter: rune(matches[0][3][0]), + positionOne: miR - 1, + positionTwo: maR - 1, + }) + } + + var num_valid_passwords int + + for _, password := range passwords { + positionOneMatches := rune(password.plaintext[password.positionOne]) == password.targetLetter + positionTwoMatches := rune(password.plaintext[password.positionTwo]) == password.targetLetter + + if positionOneMatches != positionTwoMatches { + num_valid_passwords += 1 + } + } + + return num_valid_passwords, nil +} + +func parse(instr string) []string { + return strings.Split(strings.TrimSpace(string(instr)), "\n") +} + +var parserRegex = regexp.MustCompile(`(?m)(\d+)-(\d+) ([a-z]): (.+)`) diff --git a/challenges/2020/02-passwordPhilosophy/info.json b/challenges/2020/02-passwordPhilosophy/info.json new file mode 100644 index 0000000..89f5c1c --- /dev/null +++ b/challenges/2020/02-passwordPhilosophy/info.json @@ -0,0 +1,17 @@ +{ + "inputFile": "input.txt", + "testCases": { + "one": [ + { + "input": "1-3 a: abcde\n1-3 b: cdefg\n2-9 c: ccccccccc", + "expected": "2" + } + ], + "two": [ + { + "input": "1-3 a: abcde\n1-3 b: cdefg\n2-9 c: ccccccccc", + "expected": "1" + } + ] + } +} \ No newline at end of file diff --git a/challenges/2020/02-passwordPhilosophy/py/__init__.py b/challenges/2020/02-passwordPhilosophy/py/__init__.py new file mode 100644 index 0000000..521f593 --- /dev/null +++ b/challenges/2020/02-passwordPhilosophy/py/__init__.py @@ -0,0 +1,98 @@ +import re +from typing import List +from aocpy import BaseChallenge + + +class Challenge(BaseChallenge): + + @staticmethod + def one(instr: str) -> int: + input_string = parse(instr) + + class Password: + plaintext: str + target_letter: str + min_repeats: int + max_repeats: int + + def __init__( + self, plaintext: str, target_letter: str, min_repeats: int, max_repeats: int + ) -> None: + self.plaintext = plaintext + self.target_letter = target_letter + self.min_repeats = min_repeats + self.max_repeats = max_repeats + + parser_regex = r"(\d+)-(\d+) ([a-z]): (.+)" + + passwords = [] + + for line in input_string: + m = re.match(parser_regex, line) + passwords.append( + Password(m.group(4), m.group(3), int(m.group(1)), int(m.group(2))) + ) + + num_valid_passwords = 0 + + for password in passwords: + target_letter_count = 0 + for char in password.plaintext: + if char == password.target_letter: + target_letter_count += 1 + + if password.min_repeats <= target_letter_count <= password.max_repeats: + num_valid_passwords += 1 + + return num_valid_passwords + + @staticmethod + def two(instr: str) -> int: + input_string = parse(instr) + + class Password: + plaintext: str + target_letter: str + position_one: int + position_two: int + + def __init__( + self, + plaintext: str, + target_letter: str, + position_one: int, + position_two: int, + ) -> None: + self.plaintext = plaintext + self.target_letter = target_letter + self.position_one = position_one - 1 # No concept of index zero... eurgh + self.position_two = position_two - 1 + + parser_regex = r"(\d+)-(\d+) ([a-z]): (.+)" + + passwords = [] + + for line in input_string: + m = re.match(parser_regex, line) + passwords.append( + Password(m.group(4), m.group(3), int(m.group(1)), int(m.group(2))) + ) + + num_valid_passwords = 0 + + for password in passwords: + position_one_matches = ( + password.plaintext[password.position_one] == password.target_letter + ) + position_two_matches = ( + password.plaintext[password.position_two] == password.target_letter + ) + + if position_one_matches ^ position_two_matches: + num_valid_passwords += 1 + + return num_valid_passwords + + +def parse(instr: str) -> List: + return instr.strip().split("\n") \ No newline at end of file