Add Go solutions
This commit is contained in:
parent
500ea7bb33
commit
830825f1e1
11 changed files with 422 additions and 1 deletions
4
.github/README.md
vendored
4
.github/README.md
vendored
|
@ -1,6 +1,8 @@
|
|||
# Advent of Code 2020
|
||||
|
||||
Solutions to the [2020 Advent of Code](https://adventofcode.com/2020).
|
||||
Solutions to the [2020 Advent of Code](https://adventofcode.com/2020), in both Python and Go.
|
||||
|
||||
Go solutions are near direct copies of the Python solutions and may be added a few days afterwards.
|
||||
|
||||
**Key:** ![Completed][check] is completed, ![Incomplete][cross] is incomplete.
|
||||
|
||||
|
|
|
@ -47,6 +47,8 @@ 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
|
||||
|
|
40
01-reportRepair/main.go
Normal file
40
01-reportRepair/main.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -50,6 +50,8 @@ 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.
|
||||
|
|
53
02-passwordPhilosophy/partOne.go
Normal file
53
02-passwordPhilosophy/partOne.go
Normal file
|
@ -0,0 +1,53 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Password struct {
|
||||
plaintext string
|
||||
targetLetter rune
|
||||
minRepeats int
|
||||
maxRepeats int
|
||||
}
|
||||
|
||||
var parserRegex = regexp.MustCompile(`(?m)(\d+)-(\d+) ([a-z]): (.+)`)
|
||||
|
||||
func main() {
|
||||
inputBytes, _ := ioutil.ReadFile("input.txt")
|
||||
inputSlice := strings.Split(strings.TrimSpace(string(inputBytes)), "\n")
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("There are %d valid passwords.\n", num_valid_passwords)
|
||||
}
|
49
02-passwordPhilosophy/partTwo.go
Normal file
49
02-passwordPhilosophy/partTwo.go
Normal file
|
@ -0,0 +1,49 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Password struct {
|
||||
plaintext string
|
||||
targetLetter rune
|
||||
positionOne int
|
||||
positionTwo int
|
||||
}
|
||||
|
||||
var parserRegex = regexp.MustCompile(`(?m)(\d+)-(\d+) ([a-z]): (.+)`)
|
||||
|
||||
func main() {
|
||||
inputBytes, _ := ioutil.ReadFile("input.txt")
|
||||
inputSlice := strings.Split(strings.TrimSpace(string(inputBytes)), "\n")
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("There are %d valid passwords.\n", num_valid_passwords)
|
||||
}
|
|
@ -88,6 +88,8 @@ 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)
|
||||
|
|
60
03-tobogganTrajectory/main.go
Normal file
60
03-tobogganTrajectory/main.go
Normal file
|
@ -0,0 +1,60 @@
|
|||
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
|
||||
}
|
|
@ -135,6 +135,8 @@ 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.
|
||||
|
|
47
04-passportProcessing/partOne.go
Normal file
47
04-passportProcessing/partOne.go
Normal file
|
@ -0,0 +1,47 @@
|
|||
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)
|
||||
|
||||
}
|
162
04-passportProcessing/partTwo.go
Normal file
162
04-passportProcessing/partTwo.go
Normal file
|
@ -0,0 +1,162 @@
|
|||
package main
|
||||
|
||||
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", " ")
|
||||
}
|
||||
|
||||
var passports []Passport
|
||||
for _, x := range inputSlice {
|
||||
passports = append(passports, NewPassport(x))
|
||||
}
|
||||
|
||||
var validPassports int
|
||||
for _, passport := range passports {
|
||||
if passport.Validate() {
|
||||
validPassports += 1
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("There are %d valid passports.", validPassports)
|
||||
|
||||
}
|
||||
|
||||
type Passport struct {
|
||||
byr string // Birth year
|
||||
iyr string // Issue year
|
||||
eyr string // Expiration year
|
||||
hgt string // Height
|
||||
hcl string // Hair colour
|
||||
ecl string // Eye colour
|
||||
pid string // Passport ID
|
||||
cid string // Country ID
|
||||
}
|
||||
|
||||
func (p Passport) Validate() bool {
|
||||
// byr (Birth Year) - four digits; at least 1920 and at most 2002.
|
||||
if p.byr == "" {
|
||||
return false
|
||||
}
|
||||
{
|
||||
i, _ := strconv.Atoi(p.byr)
|
||||
if !(1920 <= i && i <= 2002) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// iyr (Issue Year) - four digits; at least 2010 and at most 2020.
|
||||
if p.iyr == "" {
|
||||
return false
|
||||
}
|
||||
{
|
||||
i, _ := strconv.Atoi(p.iyr)
|
||||
if !(2010 <= i && i <= 2020) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// eyr (Expiration Year) - four digits; at least 2020 and at most 2030.
|
||||
if p.eyr == "" {
|
||||
return false
|
||||
}
|
||||
{
|
||||
i, _ := strconv.Atoi(p.eyr)
|
||||
if !(2020 <= i && i <= 2030) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// hgt (Height) - a number followed by either cm or in:
|
||||
// If cm, the number must be at least 150 and at most 193.
|
||||
// If in, the number must be at least 59 and at most 76.
|
||||
if p.hgt == "" {
|
||||
return false
|
||||
}
|
||||
if strings.Contains(p.hgt, "cm") {
|
||||
i, _ := strconv.Atoi(strings.Trim(p.hgt, "cm"))
|
||||
if !(150 <= i && i <= 193) {
|
||||
return false
|
||||
}
|
||||
} else if strings.Contains(p.hgt, "in") {
|
||||
i, _ := strconv.Atoi(strings.Trim(p.hgt, "in"))
|
||||
if !(59 <= i && i <= 76) {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
// hcl (Hair Color) - a // followed by exactly six characters 0-9 or a-f.
|
||||
if p.hcl == "" {
|
||||
return false
|
||||
}
|
||||
if p.hcl[0] == []byte("#")[0] {
|
||||
if m, _ := regexp.MatchString(`#[0-9a-f]{6}`, p.hcl); !m {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
// ecl (Eye Color) - exactly one of: amb blu brn gry grn hzl oth.
|
||||
if p.ecl == "" {
|
||||
return false
|
||||
}
|
||||
{
|
||||
var contained bool
|
||||
for _, v := range []string{"amb", "blu", "brn", "gry", "grn", "hzl", "oth"} {
|
||||
if p.ecl == v {
|
||||
contained = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !contained {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// pid (Passport ID) - a nine-digit number, including leading zeroes.
|
||||
if len(p.pid) == 9 {
|
||||
_, err := strconv.Atoi(p.pid)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func NewPassport(instr string) Passport {
|
||||
np := Passport{}
|
||||
np.byr = extractField("byr", instr)
|
||||
np.iyr = extractField("iyr", instr)
|
||||
np.eyr = extractField("eyr", instr)
|
||||
np.hgt = extractField("hgt", instr)
|
||||
np.hcl = extractField("hcl", instr)
|
||||
np.ecl = extractField("ecl", instr)
|
||||
np.pid = extractField("pid", instr)
|
||||
np.cid = extractField("cid", instr)
|
||||
return np
|
||||
}
|
||||
|
||||
func extractField(field, instr string) string {
|
||||
fieldRegex := regexp.MustCompile(field + `:([^ ]+)`)
|
||||
matches := fieldRegex.FindAllStringSubmatch(instr, -1)
|
||||
if len(matches) == 0 {
|
||||
return ""
|
||||
}
|
||||
return matches[0][1]
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue