Move some days to new templates
This commit is contained in:
parent
04df0f23f7
commit
d4e05f2842
49 changed files with 1097 additions and 391 deletions
|
@ -47,19 +47,29 @@ Your puzzle answer was `253928438`.
|
|||
|
||||
<details><summary>Script output</summary>
|
||||
|
||||
Go output is identical. Run with `go run main.go`.
|
||||
|
||||
```
|
||||
❯ python .\main.py
|
||||
Part one answer is: 1010884
|
||||
Part one answer is: 1010884
|
||||
❯ python .\python\
|
||||
AoC 2020: day 1 - Report Repair
|
||||
|
||||
Part two answer is: 253928438
|
||||
Part two answer is: 253928438
|
||||
Part two answer is: 253928438
|
||||
Part two answer is: 253928438
|
||||
Part two answer is: 253928438
|
||||
Part two answer is: 253928438
|
||||
Test cases
|
||||
1.1 pass
|
||||
2.1 pass
|
||||
|
||||
Answers
|
||||
Part 1: 1010884
|
||||
Part 2: 253928438
|
||||
|
||||
❯ go run .\go\
|
||||
AoC 2020: day 1 - Report Repair
|
||||
Go go1.15.2
|
||||
|
||||
Test cases
|
||||
1.1 pass
|
||||
2.1 pass
|
||||
|
||||
Answers
|
||||
Part 1: 1010884
|
||||
Part 2: 253928438
|
||||
```
|
||||
|
||||
</details>
|
||||
|
|
18
01-reportRepair/go/challenge/common.go
Normal file
18
01-reportRepair/go/challenge/common.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package challenge
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func parse(instr string) []int {
|
||||
inputSlice := strings.Split(strings.TrimSpace(instr), "\n")
|
||||
|
||||
var values []int
|
||||
for _, v := range inputSlice {
|
||||
str, _ := strconv.Atoi(v)
|
||||
values = append(values, str)
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
15
01-reportRepair/go/challenge/partOne.go
Normal file
15
01-reportRepair/go/challenge/partOne.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package challenge
|
||||
|
||||
func PartOne(instr string) int {
|
||||
values := parse(instr)
|
||||
|
||||
for _, i := range values {
|
||||
for _, v := range values {
|
||||
if v+i == 2020 {
|
||||
return v * i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
17
01-reportRepair/go/challenge/partTwo.go
Normal file
17
01-reportRepair/go/challenge/partTwo.go
Normal file
|
@ -0,0 +1,17 @@
|
|||
package challenge
|
||||
|
||||
func PartTwo(instr string) int {
|
||||
values := parse(instr)
|
||||
|
||||
for _, i := range values {
|
||||
for _, v := range values {
|
||||
for _, x := range values {
|
||||
if v+i+x == 2020 {
|
||||
return v * i * x
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
88
01-reportRepair/go/main.go
Normal file
88
01-reportRepair/go/main.go
Normal file
|
@ -0,0 +1,88 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"adventOfCode/01-reportRepair/go/challenge"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
const (
|
||||
year = "2020"
|
||||
day = "1"
|
||||
title = "Report Repair"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Fprintf(color.Output, "%s: day %s - %s\n", color.YellowString("AoC "+year), color.BlueString(day), title)
|
||||
fmt.Fprintf(color.Output, "Go %s\n\n", color.BlueString(runtime.Version()))
|
||||
|
||||
var challengeInput string
|
||||
{
|
||||
inb, err := ioutil.ReadFile("input.txt")
|
||||
if err != nil {
|
||||
fmt.Println("Error: could not open input.txt")
|
||||
os.Exit(-1)
|
||||
}
|
||||
challengeInput = string(inb)
|
||||
}
|
||||
|
||||
runTests()
|
||||
|
||||
fmt.Println("Answers")
|
||||
fmt.Fprintf(color.Output, "Part %s: %s\n", color.BlueString("1"), color.BlueString(strconv.Itoa(challenge.PartOne(challengeInput))))
|
||||
fmt.Fprintf(color.Output, "Part %s: %s\n", color.BlueString("2"), color.BlueString(strconv.Itoa(challenge.PartTwo(challengeInput))))
|
||||
|
||||
}
|
||||
|
||||
type tc struct {
|
||||
Input string `json:"input"`
|
||||
Expected int `json:"expected"`
|
||||
}
|
||||
|
||||
func runTests() {
|
||||
|
||||
testCases := struct {
|
||||
One []tc `json:"one"`
|
||||
Two []tc `json:"two"`
|
||||
}{}
|
||||
|
||||
{
|
||||
inb, err := ioutil.ReadFile("testCases.json")
|
||||
if err != nil {
|
||||
fmt.Println("Error: could not open testCases.json. Skipping tests")
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(inb, &testCases)
|
||||
if err != nil {
|
||||
fmt.Println("Error: could not parse testCases.json. Skipping tests")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("Test cases")
|
||||
|
||||
rt := func(tcs []tc, f func(string) int, n string) {
|
||||
for i, tc := range tcs {
|
||||
fmt.Fprintf(color.Output, "%s ", color.BlueString(n+"."+strconv.Itoa(i+1)))
|
||||
result := f(tc.Input)
|
||||
if result == tc.Expected {
|
||||
fmt.Fprintf(color.Output, "%s", color.GreenString("pass"))
|
||||
} else {
|
||||
fmt.Fprintf(color.Output, "%s (got %s, expected %s)", color.RedString("fail"), color.BlueString(strconv.Itoa(result)), color.BlueString(strconv.Itoa(tc.Expected)))
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
rt(testCases.One, challenge.PartOne, "1")
|
||||
rt(testCases.Two, challenge.PartTwo, "2")
|
||||
|
||||
fmt.Println()
|
||||
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
inputBytes, _ := ioutil.ReadFile("input.txt")
|
||||
inputSlice := strings.Split(strings.TrimSpace(string(inputBytes)), "\n")
|
||||
|
||||
var values []int
|
||||
for _, v := range inputSlice {
|
||||
str, _ := strconv.Atoi(v)
|
||||
values = append(values, str)
|
||||
}
|
||||
|
||||
for _, i := range values {
|
||||
for _, v := range values {
|
||||
if v+i == 2020 {
|
||||
fmt.Println("Part one answer is:", v*i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
|
||||
for _, i := range values {
|
||||
for _, v := range values {
|
||||
for _, x := range values {
|
||||
if v+i+x == 2020 {
|
||||
fmt.Println("Part two answer is:", v*i*x)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
input_string = open("input.txt").read().strip().split("\n")
|
||||
|
||||
values = [int(x) for x in input_string]
|
||||
|
||||
for i in values:
|
||||
for v in values:
|
||||
if v + i == 2020:
|
||||
print("Part one answer is:", v * i)
|
||||
|
||||
print()
|
||||
|
||||
for i in values:
|
||||
for v in values:
|
||||
for x in values:
|
||||
if v + i + x == 2020:
|
||||
print("Part two answer is:", v * i * x)
|
52
01-reportRepair/python/__main__.py
Normal file
52
01-reportRepair/python/__main__.py
Normal file
|
@ -0,0 +1,52 @@
|
|||
import json
|
||||
import sys
|
||||
|
||||
from rich import print
|
||||
|
||||
from partOne import partOne
|
||||
from partTwo import partTwo
|
||||
|
||||
year = "2020"
|
||||
day = "1"
|
||||
title = "Report Repair"
|
||||
|
||||
def run_tests():
|
||||
try:
|
||||
test_cases = open("testCases.json").read()
|
||||
except FileNotFoundError:
|
||||
print("Info: could not open testCases.json. Skipping tests")
|
||||
return
|
||||
|
||||
print("Test cases")
|
||||
|
||||
test_cases = json.loads(test_cases)
|
||||
|
||||
def rt(tcs, f, n):
|
||||
for i, tc in enumerate(tcs):
|
||||
print(f"{n}.{i+1} ", end="")
|
||||
expectedInt = tc["expected"]
|
||||
result = f(str(tc["input"]))
|
||||
if result == expectedInt:
|
||||
print("[green]pass[/green]")
|
||||
else:
|
||||
print(f"[red]fail[/red] (got {result}, expected {expectedInt})")
|
||||
|
||||
rt(test_cases["one"], partOne, 1)
|
||||
rt(test_cases["two"], partTwo, 2)
|
||||
|
||||
print()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(f"[yellow]AoC {year}[/yellow]: day {day} - {title}\n")
|
||||
|
||||
try:
|
||||
challenge_input = open("input.txt").read()
|
||||
except FileNotFoundError:
|
||||
print("Error: could not open input.txt")
|
||||
sys.exit(-1)
|
||||
|
||||
run_tests()
|
||||
|
||||
print("Answers")
|
||||
print("Part 1:", partOne(challenge_input))
|
||||
print("Part 2:", partTwo(challenge_input))
|
4
01-reportRepair/python/common.py
Normal file
4
01-reportRepair/python/common.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from typing import List
|
||||
|
||||
def parse(instr:str) -> List:
|
||||
return [int(x) for x in instr.strip().split("\n")]
|
11
01-reportRepair/python/partOne.py
Normal file
11
01-reportRepair/python/partOne.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
from common import *
|
||||
|
||||
def partOne(instr:str) -> int:
|
||||
values = parse(instr)
|
||||
|
||||
for i in values:
|
||||
for v in values:
|
||||
if v + i == 2020:
|
||||
return v * i
|
||||
|
||||
return 0
|
12
01-reportRepair/python/partTwo.py
Normal file
12
01-reportRepair/python/partTwo.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
from common import *
|
||||
|
||||
def partTwo(instr:str) -> int:
|
||||
values = parse(instr)
|
||||
|
||||
for i in values:
|
||||
for v in values:
|
||||
for x in values:
|
||||
if v + i + x == 2020:
|
||||
return v * i * x
|
||||
|
||||
return 0
|
14
01-reportRepair/testCases.json
Normal file
14
01-reportRepair/testCases.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"one": [
|
||||
{
|
||||
"input": "1721\n979\n366\n299\n675\n1456",
|
||||
"expected": 514579
|
||||
}
|
||||
],
|
||||
"two": [
|
||||
{
|
||||
"input": "1721\n979\n366\n299\n675\n1456",
|
||||
"expected": 241861950
|
||||
}
|
||||
]
|
||||
}
|
|
@ -50,14 +50,30 @@ Your puzzle answer was `313`.
|
|||
|
||||
<details><summary>Script output</summary>
|
||||
|
||||
Go output is identical. Run with `go run partOne.go` and `go run partTwo.go`.
|
||||
|
||||
```
|
||||
❯ python .\partOne.py
|
||||
There are 500 valid passwords.
|
||||
❯ python .\python\
|
||||
AoC 2020: day 2 - Password Philosophy
|
||||
Python 3.8.5
|
||||
|
||||
❯ python .\partTwo.py
|
||||
There are 313 valid passwords.
|
||||
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
|
||||
```
|
||||
|
||||
</details>
|
||||
|
|
12
02-passwordPhilosophy/go/challenge/common.go
Normal file
12
02-passwordPhilosophy/go/challenge/common.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
package challenge
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func parse(instr string) []string {
|
||||
return strings.Split(strings.TrimSpace(string(instr)), "\n")
|
||||
}
|
||||
|
||||
var parserRegex = regexp.MustCompile(`(?m)(\d+)-(\d+) ([a-z]): (.+)`)
|
|
@ -1,25 +1,18 @@
|
|||
package main
|
||||
package challenge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Password struct {
|
||||
plaintext string
|
||||
targetLetter rune
|
||||
minRepeats int
|
||||
maxRepeats int
|
||||
}
|
||||
func PartOne(instr string) int {
|
||||
inputSlice := parse(instr)
|
||||
|
||||
var parserRegex = regexp.MustCompile(`(?m)(\d+)-(\d+) ([a-z]): (.+)`)
|
||||
|
||||
func main() {
|
||||
inputBytes, _ := ioutil.ReadFile("input.txt")
|
||||
inputSlice := strings.Split(strings.TrimSpace(string(inputBytes)), "\n")
|
||||
type Password struct {
|
||||
plaintext string
|
||||
targetLetter rune
|
||||
minRepeats int
|
||||
maxRepeats int
|
||||
}
|
||||
|
||||
var passwords []Password
|
||||
for _, line := range inputSlice {
|
||||
|
@ -49,5 +42,5 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
fmt.Printf("There are %d valid passwords.\n", num_valid_passwords)
|
||||
return num_valid_passwords
|
||||
}
|
|
@ -1,25 +1,18 @@
|
|||
package main
|
||||
package challenge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Password struct {
|
||||
plaintext string
|
||||
targetLetter rune
|
||||
positionOne int
|
||||
positionTwo int
|
||||
}
|
||||
func PartTwo(instr string) int {
|
||||
inputSlice := parse(instr)
|
||||
|
||||
var parserRegex = regexp.MustCompile(`(?m)(\d+)-(\d+) ([a-z]): (.+)`)
|
||||
|
||||
func main() {
|
||||
inputBytes, _ := ioutil.ReadFile("input.txt")
|
||||
inputSlice := strings.Split(strings.TrimSpace(string(inputBytes)), "\n")
|
||||
type Password struct {
|
||||
plaintext string
|
||||
targetLetter rune
|
||||
positionOne int
|
||||
positionTwo int
|
||||
}
|
||||
|
||||
var passwords []Password
|
||||
for _, line := range inputSlice {
|
||||
|
@ -45,5 +38,5 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
fmt.Printf("There are %d valid passwords.\n", num_valid_passwords)
|
||||
return num_valid_passwords
|
||||
}
|
88
02-passwordPhilosophy/go/main.go
Normal file
88
02-passwordPhilosophy/go/main.go
Normal file
|
@ -0,0 +1,88 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"adventOfCode/02-passwordPhilosophy/go/challenge"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
const (
|
||||
year = "2020"
|
||||
day = "2"
|
||||
title = "Password Philosophy"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Fprintf(color.Output, "%s: day %s - %s\n", color.YellowString("AoC "+year), color.BlueString(day), title)
|
||||
fmt.Fprintf(color.Output, "Go %s\n\n", color.BlueString(runtime.Version()))
|
||||
|
||||
var challengeInput string
|
||||
{
|
||||
inb, err := ioutil.ReadFile("input.txt")
|
||||
if err != nil {
|
||||
fmt.Println("Error: could not open input.txt")
|
||||
os.Exit(-1)
|
||||
}
|
||||
challengeInput = string(inb)
|
||||
}
|
||||
|
||||
runTests()
|
||||
|
||||
fmt.Println("Answers")
|
||||
fmt.Fprintf(color.Output, "Part %s: %s\n", color.BlueString("1"), color.BlueString(strconv.Itoa(challenge.PartOne(challengeInput))))
|
||||
fmt.Fprintf(color.Output, "Part %s: %s\n", color.BlueString("2"), color.BlueString(strconv.Itoa(challenge.PartTwo(challengeInput))))
|
||||
|
||||
}
|
||||
|
||||
type tc struct {
|
||||
Input string `json:"input"`
|
||||
Expected int `json:"expected"`
|
||||
}
|
||||
|
||||
func runTests() {
|
||||
|
||||
testCases := struct {
|
||||
One []tc `json:"one"`
|
||||
Two []tc `json:"two"`
|
||||
}{}
|
||||
|
||||
{
|
||||
inb, err := ioutil.ReadFile("testCases.json")
|
||||
if err != nil {
|
||||
fmt.Println("Error: could not open testCases.json. Skipping tests")
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(inb, &testCases)
|
||||
if err != nil {
|
||||
fmt.Println("Error: could not parse testCases.json. Skipping tests")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("Test cases")
|
||||
|
||||
rt := func(tcs []tc, f func(string) int, n string) {
|
||||
for i, tc := range tcs {
|
||||
fmt.Fprintf(color.Output, "%s ", color.BlueString(n+"."+strconv.Itoa(i+1)))
|
||||
result := f(tc.Input)
|
||||
if result == tc.Expected {
|
||||
fmt.Fprintf(color.Output, "%s", color.GreenString("pass"))
|
||||
} else {
|
||||
fmt.Fprintf(color.Output, "%s (got %s, expected %s)", color.RedString("fail"), color.BlueString(strconv.Itoa(result)), color.BlueString(strconv.Itoa(tc.Expected)))
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
rt(testCases.One, challenge.PartOne, "1")
|
||||
rt(testCases.Two, challenge.PartTwo, "2")
|
||||
|
||||
fmt.Println()
|
||||
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
import re
|
||||
|
||||
input_string = open("input.txt").read().strip().split("\n")
|
||||
|
||||
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
|
||||
|
||||
print(f"There are {num_valid_passwords} valid passwords.")
|
|
@ -1,34 +0,0 @@
|
|||
import re
|
||||
|
||||
input_string = open("input.txt").read().strip().split("\n")
|
||||
|
||||
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
|
||||
|
||||
print(f"There are {num_valid_passwords} valid passwords.")
|
54
02-passwordPhilosophy/python/__main__.py
Normal file
54
02-passwordPhilosophy/python/__main__.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
import json
|
||||
import platform
|
||||
import sys
|
||||
|
||||
from rich import print
|
||||
|
||||
from partOne import partOne
|
||||
from partTwo import partTwo
|
||||
|
||||
year = "2020"
|
||||
day = "2"
|
||||
title = "Password Philosophy"
|
||||
|
||||
def run_tests():
|
||||
try:
|
||||
test_cases = open("testCases.json").read()
|
||||
except FileNotFoundError:
|
||||
print("Info: could not open testCases.json. Skipping tests")
|
||||
return
|
||||
|
||||
print("Test cases")
|
||||
|
||||
test_cases = json.loads(test_cases)
|
||||
|
||||
def rt(tcs, f, n):
|
||||
for i, tc in enumerate(tcs):
|
||||
print(f"{n}.{i+1} ", end="")
|
||||
expectedInt = tc["expected"]
|
||||
result = f(str(tc["input"]))
|
||||
if result == expectedInt:
|
||||
print("[green]pass[/green]")
|
||||
else:
|
||||
print(f"[red]fail[/red] (got {result}, expected {expectedInt})")
|
||||
|
||||
rt(test_cases["one"], partOne, 1)
|
||||
rt(test_cases["two"], partTwo, 2)
|
||||
|
||||
print()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(f"[yellow]AoC {year}[/yellow]: day {day} - {title}")
|
||||
print(f"Python {platform.python_version()}\n")
|
||||
|
||||
try:
|
||||
challenge_input = open("input.txt").read()
|
||||
except FileNotFoundError:
|
||||
print("Error: could not open input.txt")
|
||||
sys.exit(-1)
|
||||
|
||||
run_tests()
|
||||
|
||||
print("Answers")
|
||||
print("Part 1:", partOne(challenge_input))
|
||||
print("Part 2:", partTwo(challenge_input))
|
4
02-passwordPhilosophy/python/common.py
Normal file
4
02-passwordPhilosophy/python/common.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from typing import List
|
||||
|
||||
def parse(instr:str) -> List:
|
||||
return instr.strip().split("\n")
|
39
02-passwordPhilosophy/python/partOne.py
Normal file
39
02-passwordPhilosophy/python/partOne.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
import re
|
||||
|
||||
from common import *
|
||||
|
||||
def partOne(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
|
37
02-passwordPhilosophy/python/partTwo.py
Normal file
37
02-passwordPhilosophy/python/partTwo.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
import re
|
||||
|
||||
from common import *
|
||||
|
||||
def partTwo(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
|
14
02-passwordPhilosophy/testCases.json
Normal file
14
02-passwordPhilosophy/testCases.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
|
@ -88,16 +88,26 @@ Your puzzle answer was `9354744432`.
|
|||
|
||||
<details><summary>Script output</summary>
|
||||
|
||||
Go output is identical. Run with `go run main.go`.
|
||||
|
||||
```
|
||||
❯ python .\main.py
|
||||
Pair (3, 1): 292 trees (part one solution)
|
||||
Pair (1, 1): 81 trees
|
||||
Pair (5, 1): 89 trees
|
||||
Pair (7, 1): 101 trees
|
||||
Pair (1, 2): 44 trees
|
||||
Product of all: 9354744432 (part two solution)
|
||||
❯ python .\python\
|
||||
AoC 2020: day 3 - Toboggan Trajectory
|
||||
Python 3.8.5
|
||||
|
||||
Info: could not open testCases.json. Skipping tests
|
||||
|
||||
Answers
|
||||
Part 1: 292
|
||||
Part 2: 9354744432
|
||||
|
||||
❯ go run .\go\
|
||||
AoC 2020: day 3 - Toboggan Trajectory
|
||||
Go go1.15.2
|
||||
|
||||
Info: could not open testCases.json. Skipping tests
|
||||
|
||||
Answers
|
||||
Part 1: 292
|
||||
Part 2: 9354744432
|
||||
```
|
||||
|
||||
</details>
|
||||
|
|
33
03-tobogganTrajectory/go/challenge/common.go
Normal file
33
03-tobogganTrajectory/go/challenge/common.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
package challenge
|
||||
|
||||
import "strings"
|
||||
|
||||
func parse(instr string) [][]rune {
|
||||
inputSlice := strings.Split(strings.TrimSpace(instr), "\n")
|
||||
|
||||
var forest [][]rune
|
||||
for _, line := range inputSlice {
|
||||
forest = append(forest, []rune(line))
|
||||
}
|
||||
return forest
|
||||
}
|
||||
|
||||
var tree_char = []rune("#")[0] // No idea why I can't just do rune("#")
|
||||
|
||||
func findCollisions(forest [][]rune, xOffset, yOffset int) int {
|
||||
var encounteredTrees int
|
||||
var xPointer int
|
||||
var yPointer int
|
||||
|
||||
for yPointer < len(forest) {
|
||||
row := forest[yPointer]
|
||||
targetIndex := xPointer % len(row)
|
||||
if row[targetIndex] == tree_char {
|
||||
encounteredTrees += 1
|
||||
}
|
||||
xPointer += xOffset
|
||||
yPointer += yOffset
|
||||
}
|
||||
|
||||
return encounteredTrees
|
||||
}
|
5
03-tobogganTrajectory/go/challenge/partOne.go
Normal file
5
03-tobogganTrajectory/go/challenge/partOne.go
Normal file
|
@ -0,0 +1,5 @@
|
|||
package challenge
|
||||
|
||||
func PartOne(instr string) int {
|
||||
return findCollisions(parse(instr), 3, 1)
|
||||
}
|
22
03-tobogganTrajectory/go/challenge/partTwo.go
Normal file
22
03-tobogganTrajectory/go/challenge/partTwo.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package challenge
|
||||
|
||||
func PartTwo(instr string) int {
|
||||
forest := parse(instr)
|
||||
|
||||
offsetPairs := [][]int{
|
||||
{3, 1},
|
||||
{1, 1},
|
||||
{5, 1},
|
||||
{7, 1},
|
||||
{1, 2},
|
||||
}
|
||||
|
||||
treeProduct := 1
|
||||
|
||||
for _, pair := range offsetPairs {
|
||||
encounteredTrees := findCollisions(forest, pair[0], pair[1])
|
||||
treeProduct *= encounteredTrees
|
||||
}
|
||||
|
||||
return treeProduct
|
||||
}
|
90
03-tobogganTrajectory/go/main.go
Normal file
90
03-tobogganTrajectory/go/main.go
Normal file
|
@ -0,0 +1,90 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"adventOfCode/03-tobogganTrajectory/go/challenge"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
const (
|
||||
year = "2020"
|
||||
day = "3"
|
||||
title = "Toboggan Trajectory"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Fprintf(color.Output, "%s: day %s - %s\n", color.YellowString("AoC "+year), color.BlueString(day), title)
|
||||
fmt.Fprintf(color.Output, "Go %s\n\n", color.BlueString(runtime.Version()))
|
||||
|
||||
var challengeInput string
|
||||
{
|
||||
inb, err := ioutil.ReadFile("input.txt")
|
||||
if err != nil {
|
||||
fmt.Println("Error: could not open input.txt")
|
||||
os.Exit(-1)
|
||||
}
|
||||
challengeInput = string(inb)
|
||||
}
|
||||
|
||||
runTests()
|
||||
|
||||
fmt.Println("Answers")
|
||||
fmt.Fprintf(color.Output, "Part %s: %s\n", color.BlueString("1"), color.BlueString(strconv.Itoa(challenge.PartOne(challengeInput))))
|
||||
fmt.Fprintf(color.Output, "Part %s: %s\n", color.BlueString("2"), color.BlueString(strconv.Itoa(challenge.PartTwo(challengeInput))))
|
||||
|
||||
}
|
||||
|
||||
type tc struct {
|
||||
Input string `json:"input"`
|
||||
Expected int `json:"expected"`
|
||||
}
|
||||
|
||||
func runTests() {
|
||||
|
||||
testCases := struct {
|
||||
One []tc `json:"one"`
|
||||
Two []tc `json:"two"`
|
||||
}{}
|
||||
|
||||
{
|
||||
inb, err := ioutil.ReadFile("testCases.json")
|
||||
if err != nil {
|
||||
fmt.Println("Info: could not open testCases.json. Skipping tests")
|
||||
fmt.Println()
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(inb, &testCases)
|
||||
if err != nil {
|
||||
fmt.Println("Error: could not parse testCases.json. Skipping tests")
|
||||
fmt.Println()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("Test cases")
|
||||
|
||||
rt := func(tcs []tc, f func(string) int, n string) {
|
||||
for i, tc := range tcs {
|
||||
fmt.Fprintf(color.Output, "%s ", color.BlueString(n+"."+strconv.Itoa(i+1)))
|
||||
result := f(tc.Input)
|
||||
if result == tc.Expected {
|
||||
fmt.Fprintf(color.Output, "%s", color.GreenString("pass"))
|
||||
} else {
|
||||
fmt.Fprintf(color.Output, "%s (got %s, expected %s)", color.RedString("fail"), color.BlueString(strconv.Itoa(result)), color.BlueString(strconv.Itoa(tc.Expected)))
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
rt(testCases.One, challenge.PartOne, "1")
|
||||
rt(testCases.Two, challenge.PartTwo, "2")
|
||||
|
||||
fmt.Println()
|
||||
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var tree_char = []rune("#")[0] // No idea why I can't just do rune("#")
|
||||
|
||||
func main() {
|
||||
inputBytes, _ := ioutil.ReadFile("input.txt")
|
||||
inputSlice := strings.Split(strings.TrimSpace(string(inputBytes)), "\n")
|
||||
|
||||
var forest [][]rune
|
||||
for _, line := range inputSlice {
|
||||
forest = append(forest, []rune(line))
|
||||
}
|
||||
|
||||
offsetPairs := [][]int{
|
||||
{3, 1},
|
||||
{1, 1},
|
||||
{5, 1},
|
||||
{7, 1},
|
||||
{1, 2},
|
||||
}
|
||||
|
||||
treeProduct := 1
|
||||
|
||||
for i, pair := range offsetPairs {
|
||||
encounteredTrees := findCollisions(forest, pair[0], pair[1])
|
||||
treeProduct *= encounteredTrees
|
||||
fmt.Printf("Pair %d: %d trees", i, encounteredTrees)
|
||||
if i == 0 {
|
||||
fmt.Print(" (part one solution)")
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
fmt.Printf("Product of all: %d (part two solution)\n", treeProduct)
|
||||
|
||||
}
|
||||
|
||||
func findCollisions(forest [][]rune, xOffset, yOffset int) int {
|
||||
var encounteredTrees int
|
||||
var xPointer int
|
||||
var yPointer int
|
||||
|
||||
for yPointer < len(forest) {
|
||||
row := forest[yPointer]
|
||||
targetIndex := xPointer % len(row)
|
||||
if row[targetIndex] == tree_char {
|
||||
encounteredTrees += 1
|
||||
}
|
||||
xPointer += xOffset
|
||||
yPointer += yOffset
|
||||
}
|
||||
|
||||
return encounteredTrees
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
input_list = open("input.txt").read().strip().split("\n")
|
||||
|
||||
forest = [[char for char in line] for line in input_list]
|
||||
|
||||
tree_char = "#"
|
||||
|
||||
def find_collisions(forest:list, x_offset:int, y_offset:int) -> int:
|
||||
encountered_trees = 0
|
||||
x_pointer = 0
|
||||
|
||||
for row in forest[::y_offset]:
|
||||
target_index = x_pointer % len(row)
|
||||
if row[target_index] == tree_char:
|
||||
encountered_trees += 1
|
||||
x_pointer += x_offset
|
||||
|
||||
return encountered_trees
|
||||
|
||||
offset_pairs = [
|
||||
(3, 1),
|
||||
(1, 1),
|
||||
(5, 1),
|
||||
(7, 1),
|
||||
(1, 2)
|
||||
]
|
||||
|
||||
tree_product = 1
|
||||
|
||||
for i, pair in enumerate(offset_pairs):
|
||||
encountered_trees = find_collisions(forest, *pair)
|
||||
tree_product *= encountered_trees
|
||||
print(f"Pair {pair}: {encountered_trees} trees", ("(part one solution)" if i == 0 else ""))
|
||||
|
||||
print(f"Product of all: {tree_product} (part two solution)")
|
54
03-tobogganTrajectory/python/__main__.py
Normal file
54
03-tobogganTrajectory/python/__main__.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
import json
|
||||
import platform
|
||||
import sys
|
||||
|
||||
from rich import print
|
||||
|
||||
from partOne import partOne
|
||||
from partTwo import partTwo
|
||||
|
||||
year = "2020"
|
||||
day = "3"
|
||||
title = "Toboggan Trajectory"
|
||||
|
||||
def run_tests():
|
||||
try:
|
||||
test_cases = open("testCases.json").read()
|
||||
except FileNotFoundError:
|
||||
print("Info: could not open testCases.json. Skipping tests\n")
|
||||
return
|
||||
|
||||
print("Test cases")
|
||||
|
||||
test_cases = json.loads(test_cases)
|
||||
|
||||
def rt(tcs, f, n):
|
||||
for i, tc in enumerate(tcs):
|
||||
print(f"{n}.{i+1} ", end="")
|
||||
expectedInt = tc["expected"]
|
||||
result = f(str(tc["input"]))
|
||||
if result == expectedInt:
|
||||
print("[green]pass[/green]")
|
||||
else:
|
||||
print(f"[red]fail[/red] (got {result}, expected {expectedInt})")
|
||||
|
||||
rt(test_cases["one"], partOne, 1)
|
||||
rt(test_cases["two"], partTwo, 2)
|
||||
|
||||
print()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(f"[yellow]AoC {year}[/yellow]: day {day} - {title}")
|
||||
print(f"Python {platform.python_version()}\n")
|
||||
|
||||
try:
|
||||
challenge_input = open("input.txt").read()
|
||||
except FileNotFoundError:
|
||||
print("Error: could not open input.txt")
|
||||
sys.exit(-1)
|
||||
|
||||
run_tests()
|
||||
|
||||
print("Answers")
|
||||
print("Part 1:", partOne(challenge_input))
|
||||
print("Part 2:", partTwo(challenge_input))
|
18
03-tobogganTrajectory/python/common.py
Normal file
18
03-tobogganTrajectory/python/common.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
from typing import List
|
||||
|
||||
tree_char = "#"
|
||||
|
||||
def parse(instr:str) -> List:
|
||||
return [[char for char in line] for line in instr.strip().split("\n")]
|
||||
|
||||
def find_collisions(forest:list, x_offset:int, y_offset:int) -> int:
|
||||
encountered_trees = 0
|
||||
x_pointer = 0
|
||||
|
||||
for row in forest[::y_offset]:
|
||||
target_index = x_pointer % len(row)
|
||||
if row[target_index] == tree_char:
|
||||
encountered_trees += 1
|
||||
x_pointer += x_offset
|
||||
|
||||
return encountered_trees
|
4
03-tobogganTrajectory/python/partOne.py
Normal file
4
03-tobogganTrajectory/python/partOne.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from common import *
|
||||
|
||||
def partOne(instr:str) -> int:
|
||||
return find_collisions(parse(instr), 3, 1)
|
20
03-tobogganTrajectory/python/partTwo.py
Normal file
20
03-tobogganTrajectory/python/partTwo.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
from common import *
|
||||
|
||||
def partTwo(instr:str) -> int:
|
||||
forest = parse(instr)
|
||||
|
||||
tree_product = 1
|
||||
|
||||
offset_pairs = [
|
||||
(3, 1),
|
||||
(1, 1),
|
||||
(5, 1),
|
||||
(7, 1),
|
||||
(1, 2)
|
||||
]
|
||||
|
||||
for i, pair in enumerate(offset_pairs):
|
||||
encountered_trees = find_collisions(forest, *pair)
|
||||
tree_product *= encountered_trees
|
||||
|
||||
return tree_product
|
|
@ -135,13 +135,30 @@ Your puzzle answer was `147`.
|
|||
|
||||
<details><summary>Script output</summary>
|
||||
|
||||
Go output is identical. Run with `go run partOne.go` and `go run partTwo.go`.
|
||||
|
||||
```
|
||||
❯ python .\partOne.py
|
||||
There are 213 valid passports.
|
||||
❯ python .\partTwo.py
|
||||
There are 147 valid passports.
|
||||
❯ python .\python\
|
||||
AoC 2020: day 4 - Passport Processing
|
||||
Python 3.8.5
|
||||
|
||||
Test cases
|
||||
1.1 pass
|
||||
2.1 pass
|
||||
|
||||
Answers
|
||||
Part 1: 213
|
||||
Part 2: 147
|
||||
|
||||
❯ go run .\go\
|
||||
AoC 2020: day 4 - Passport Processing
|
||||
Go go1.15.2
|
||||
|
||||
Test cases
|
||||
1.1 pass
|
||||
2.1 pass
|
||||
|
||||
Answers
|
||||
Part 1: 213
|
||||
Part 2: 147
|
||||
```
|
||||
|
||||
</details>
|
||||
|
|
11
04-passportProcessing/go/challenge/common.go
Normal file
11
04-passportProcessing/go/challenge/common.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
package challenge
|
||||
|
||||
import "strings"
|
||||
|
||||
func parse(instr string) []string {
|
||||
inputSlice := strings.Split(strings.TrimSpace(instr), "\n\n")
|
||||
for i, x := range inputSlice {
|
||||
inputSlice[i] = strings.ReplaceAll(x, "\n", " ")
|
||||
}
|
||||
return inputSlice
|
||||
}
|
36
04-passportProcessing/go/challenge/partOne.go
Normal file
36
04-passportProcessing/go/challenge/partOne.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
package challenge
|
||||
|
||||
import "regexp"
|
||||
|
||||
func PartOne(instr string) int {
|
||||
inputSlice := parse(instr)
|
||||
|
||||
var valid_passports int
|
||||
|
||||
testCases := []*regexp.Regexp{
|
||||
regexp.MustCompile(`byr:([^ ]+)`),
|
||||
regexp.MustCompile(`iyr:([^ ]+)`),
|
||||
regexp.MustCompile(`eyr:([^ ]+)`),
|
||||
regexp.MustCompile(`hgt:([^ ]+)`),
|
||||
regexp.MustCompile(`hcl:([^ ]+)`),
|
||||
regexp.MustCompile(`ecl:([^ ]+)`),
|
||||
regexp.MustCompile(`pid:([^ ]+)`),
|
||||
}
|
||||
|
||||
for _, passport := range inputSlice {
|
||||
valid := true
|
||||
for _, tc := range testCases {
|
||||
if !tc.MatchString(passport) {
|
||||
valid = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if valid {
|
||||
valid_passports += 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return valid_passports
|
||||
}
|
|
@ -1,20 +1,13 @@
|
|||
package main
|
||||
package challenge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
inputBytes, _ := ioutil.ReadFile("input.txt")
|
||||
inputSlice := strings.Split(strings.TrimSpace(string(inputBytes)), "\n\n")
|
||||
|
||||
for i, x := range inputSlice {
|
||||
inputSlice[i] = strings.ReplaceAll(x, "\n", " ")
|
||||
}
|
||||
func PartTwo(instr string) int {
|
||||
inputSlice := parse(instr)
|
||||
|
||||
var passports []Passport
|
||||
for _, x := range inputSlice {
|
||||
|
@ -28,8 +21,7 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
fmt.Printf("There are %d valid passports.", validPassports)
|
||||
|
||||
return validPassports
|
||||
}
|
||||
|
||||
type Passport struct {
|
90
04-passportProcessing/go/main.go
Normal file
90
04-passportProcessing/go/main.go
Normal file
|
@ -0,0 +1,90 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"adventOfCode/04-passportProcessing/go/challenge"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
const (
|
||||
year = "2020"
|
||||
day = "4"
|
||||
title = "Passport Processing"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Fprintf(color.Output, "%s: day %s - %s\n", color.YellowString("AoC "+year), color.BlueString(day), title)
|
||||
fmt.Fprintf(color.Output, "Go %s\n\n", color.BlueString(runtime.Version()))
|
||||
|
||||
var challengeInput string
|
||||
{
|
||||
inb, err := ioutil.ReadFile("input.txt")
|
||||
if err != nil {
|
||||
fmt.Println("Error: could not open input.txt")
|
||||
os.Exit(-1)
|
||||
}
|
||||
challengeInput = string(inb)
|
||||
}
|
||||
|
||||
runTests()
|
||||
|
||||
fmt.Println("Answers")
|
||||
fmt.Fprintf(color.Output, "Part %s: %s\n", color.BlueString("1"), color.BlueString(strconv.Itoa(challenge.PartOne(challengeInput))))
|
||||
fmt.Fprintf(color.Output, "Part %s: %s\n", color.BlueString("2"), color.BlueString(strconv.Itoa(challenge.PartTwo(challengeInput))))
|
||||
|
||||
}
|
||||
|
||||
type tc struct {
|
||||
Input string `json:"input"`
|
||||
Expected int `json:"expected"`
|
||||
}
|
||||
|
||||
func runTests() {
|
||||
|
||||
testCases := struct {
|
||||
One []tc `json:"one"`
|
||||
Two []tc `json:"two"`
|
||||
}{}
|
||||
|
||||
{
|
||||
inb, err := ioutil.ReadFile("testCases.json")
|
||||
if err != nil {
|
||||
fmt.Println("Info: could not open testCases.json. Skipping tests")
|
||||
fmt.Println()
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(inb, &testCases)
|
||||
if err != nil {
|
||||
fmt.Println("Error: could not parse testCases.json. Skipping tests")
|
||||
fmt.Println()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("Test cases")
|
||||
|
||||
rt := func(tcs []tc, f func(string) int, n string) {
|
||||
for i, tc := range tcs {
|
||||
fmt.Fprintf(color.Output, "%s ", color.BlueString(n+"."+strconv.Itoa(i+1)))
|
||||
result := f(tc.Input)
|
||||
if result == tc.Expected {
|
||||
fmt.Fprintf(color.Output, "%s", color.GreenString("pass"))
|
||||
} else {
|
||||
fmt.Fprintf(color.Output, "%s (got %s, expected %s)", color.RedString("fail"), color.BlueString(strconv.Itoa(result)), color.BlueString(strconv.Itoa(tc.Expected)))
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
rt(testCases.One, challenge.PartOne, "1")
|
||||
rt(testCases.Two, challenge.PartTwo, "2")
|
||||
|
||||
fmt.Println()
|
||||
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var testCases = []*regexp.Regexp{
|
||||
regexp.MustCompile(`byr:([^ ]+)`),
|
||||
regexp.MustCompile(`iyr:([^ ]+)`),
|
||||
regexp.MustCompile(`eyr:([^ ]+)`),
|
||||
regexp.MustCompile(`hgt:([^ ]+)`),
|
||||
regexp.MustCompile(`hcl:([^ ]+)`),
|
||||
regexp.MustCompile(`ecl:([^ ]+)`),
|
||||
regexp.MustCompile(`pid:([^ ]+)`),
|
||||
}
|
||||
|
||||
func main() {
|
||||
inputBytes, _ := ioutil.ReadFile("input.txt")
|
||||
inputSlice := strings.Split(strings.TrimSpace(string(inputBytes)), "\n\n")
|
||||
|
||||
for i, x := range inputSlice {
|
||||
inputSlice[i] = strings.ReplaceAll(x, "\n", " ")
|
||||
}
|
||||
|
||||
var valid_passports int
|
||||
|
||||
for _, passport := range inputSlice {
|
||||
valid := true
|
||||
for _, tc := range testCases {
|
||||
if !tc.MatchString(passport) {
|
||||
valid = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if valid {
|
||||
valid_passports += 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fmt.Printf("There are %d valid passports.\n", valid_passports)
|
||||
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
import re
|
||||
|
||||
input_list = [x.replace("\n", " ") for x in open("input.txt").read().strip().split("\n\n")]
|
||||
|
||||
test_cases = [
|
||||
# Regex to match expression, bool if can be skipped
|
||||
[r"byr:([^ ]+)", False],
|
||||
[r"iyr:([^ ]+)", False],
|
||||
[r"eyr:([^ ]+)", False],
|
||||
[r"hgt:([^ ]+)", False],
|
||||
[r"hcl:([^ ]+)", False],
|
||||
[r"ecl:([^ ]+)", False],
|
||||
[r"pid:([^ ]+)", False],
|
||||
[r"cid:([^ ]+)", True]
|
||||
]
|
||||
|
||||
valid_passports = 0
|
||||
|
||||
for passport in input_list:
|
||||
|
||||
results = []
|
||||
for tc in test_cases:
|
||||
results.append([re.search(tc[0], passport) is not None, tc[1]])
|
||||
|
||||
valid = True
|
||||
for r in results:
|
||||
if not (r[0] or r[1]):
|
||||
valid = False
|
||||
break
|
||||
|
||||
valid_passports += 1 if valid else 0
|
||||
|
||||
print(f"There are {valid_passports} valid passports.")
|
54
04-passportProcessing/python/__main__.py
Normal file
54
04-passportProcessing/python/__main__.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
import json
|
||||
import platform
|
||||
import sys
|
||||
|
||||
from rich import print
|
||||
|
||||
from partOne import partOne
|
||||
from partTwo import partTwo
|
||||
|
||||
year = "2020"
|
||||
day = "4"
|
||||
title = "Passport Processing"
|
||||
|
||||
def run_tests():
|
||||
try:
|
||||
test_cases = open("testCases.json").read()
|
||||
except FileNotFoundError:
|
||||
print("Info: could not open testCases.json. Skipping tests\n")
|
||||
return
|
||||
|
||||
print("Test cases")
|
||||
|
||||
test_cases = json.loads(test_cases)
|
||||
|
||||
def rt(tcs, f, n):
|
||||
for i, tc in enumerate(tcs):
|
||||
print(f"{n}.{i+1} ", end="")
|
||||
expectedInt = tc["expected"]
|
||||
result = f(str(tc["input"]))
|
||||
if result == expectedInt:
|
||||
print("[green]pass[/green]")
|
||||
else:
|
||||
print(f"[red]fail[/red] (got {result}, expected {expectedInt})")
|
||||
|
||||
rt(test_cases["one"], partOne, 1)
|
||||
rt(test_cases["two"], partTwo, 2)
|
||||
|
||||
print()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(f"[yellow]AoC {year}[/yellow]: day {day} - {title}")
|
||||
print(f"Python {platform.python_version()}\n")
|
||||
|
||||
try:
|
||||
challenge_input = open("input.txt").read()
|
||||
except FileNotFoundError:
|
||||
print("Error: could not open input.txt")
|
||||
sys.exit(-1)
|
||||
|
||||
run_tests()
|
||||
|
||||
print("Answers")
|
||||
print("Part 1:", partOne(challenge_input))
|
||||
print("Part 2:", partTwo(challenge_input))
|
4
04-passportProcessing/python/common.py
Normal file
4
04-passportProcessing/python/common.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from typing import List
|
||||
|
||||
def parse(instr:str) -> List:
|
||||
return [x.replace("\n", " ") for x in instr.strip().split("\n\n")]
|
36
04-passportProcessing/python/partOne.py
Normal file
36
04-passportProcessing/python/partOne.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
import re
|
||||
|
||||
from common import *
|
||||
|
||||
def partOne(instr:str) -> int:
|
||||
input_list = parse(instr)
|
||||
|
||||
test_cases = [
|
||||
# Regex to match expression, bool if can be skipped
|
||||
[r"byr:([^ ]+)", False],
|
||||
[r"iyr:([^ ]+)", False],
|
||||
[r"eyr:([^ ]+)", False],
|
||||
[r"hgt:([^ ]+)", False],
|
||||
[r"hcl:([^ ]+)", False],
|
||||
[r"ecl:([^ ]+)", False],
|
||||
[r"pid:([^ ]+)", False],
|
||||
[r"cid:([^ ]+)", True]
|
||||
]
|
||||
|
||||
valid_passports = 0
|
||||
|
||||
for passport in input_list:
|
||||
|
||||
results = []
|
||||
for tc in test_cases:
|
||||
results.append([re.search(tc[0], passport) is not None, tc[1]])
|
||||
|
||||
valid = True
|
||||
for r in results:
|
||||
if not (r[0] or r[1]):
|
||||
valid = False
|
||||
break
|
||||
|
||||
valid_passports += 1 if valid else 0
|
||||
|
||||
return valid_passports
|
|
@ -1,6 +1,18 @@
|
|||
import re
|
||||
|
||||
input_list = [x.replace("\n", " ") for x in open("input.txt").read().strip().split("\n\n")]
|
||||
from common import *
|
||||
|
||||
def partTwo(instr:str) -> int:
|
||||
input_list = parse(instr)
|
||||
|
||||
passports = [Passport(x) for x in input_list]
|
||||
|
||||
valid_passports = 0
|
||||
for passport in passports:
|
||||
if passport.validate():
|
||||
valid_passports += 1
|
||||
|
||||
return valid_passports
|
||||
|
||||
class Passport:
|
||||
byr: str # Birth year
|
||||
|
@ -86,13 +98,4 @@ class Passport:
|
|||
else:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
passports = [Passport(x) for x in input_list]
|
||||
|
||||
valid_passports = 0
|
||||
for passport in passports:
|
||||
if passport.validate():
|
||||
valid_passports += 1
|
||||
|
||||
print(f"There are {valid_passports} valid passports.")
|
||||
return True
|
14
04-passportProcessing/testCases.json
Normal file
14
04-passportProcessing/testCases.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"one": [
|
||||
{
|
||||
"input": "ecl:gry pid:860033327 eyr:2020 hcl:#fffffd\nbyr:1937 iyr:2017 cid:147 hgt:183cm\n\niyr:2013 ecl:amb cid:350 eyr:2023 pid:028048884\nhcl:#cfa07d byr:1929\n\nhcl:#ae17e1 iyr:2013\neyr:2024\necl:brn pid:760753108 byr:1931\nhgt:179cm\n\nhcl:#cfa07d eyr:2025 pid:166559648\niyr:2011 ecl:brn hgt:59in",
|
||||
"expected": 2
|
||||
}
|
||||
],
|
||||
"two": [
|
||||
{
|
||||
"input": "eyr:1972 cid:100\nhcl:#18171d ecl:amb hgt:170 pid:186cm iyr:2018 byr:1926\n\niyr:2019\nhcl:#602927 eyr:1967 hgt:170cm\necl:grn pid:012533040 byr:1946\n\nhcl:dab227 iyr:2012\necl:brn hgt:182cm pid:021572410 eyr:2020 byr:1992 cid:277\n\nhgt:59cm ecl:zzz\neyr:2038 hcl:74454a iyr:2023\npid:3556412378 byr:2007\npid:087499704 hgt:74in ecl:grn iyr:2012 eyr:2030 byr:1980\nhcl:#623a2f",
|
||||
"expected": 0
|
||||
}
|
||||
]
|
||||
}
|
|
@ -55,12 +55,14 @@ func runTests() {
|
|||
{
|
||||
inb, err := ioutil.ReadFile("testCases.json")
|
||||
if err != nil {
|
||||
fmt.Println("Error: could not open testCases.json. Skipping tests")
|
||||
fmt.Println("Info: could not open testCases.json. Skipping tests")
|
||||
fmt.Println()
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(inb, &testCases)
|
||||
if err != nil {
|
||||
fmt.Println("Error: could not parse testCases.json. Skipping tests")
|
||||
fmt.Println()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ def run_tests():
|
|||
try:
|
||||
test_cases = open("testCases.json").read()
|
||||
except FileNotFoundError:
|
||||
print("Info: could not open testCases.json. Skipping tests")
|
||||
print("Info: could not open testCases.json. Skipping tests\n")
|
||||
return
|
||||
|
||||
print("Test cases")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue