Add Go solutions

This commit is contained in:
akp 2020-12-04 19:44:25 +00:00
parent 500ea7bb33
commit 830825f1e1
No known key found for this signature in database
GPG key ID: D3E7EAA31B39637E
11 changed files with 422 additions and 1 deletions

4
.github/README.md vendored
View file

@ -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.

View file

@ -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
View 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)
}
}
}
}
}

View file

@ -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.

View 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)
}

View 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)
}

View file

@ -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)

View 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
}

View file

@ -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.

View 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)
}

View 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]
}