Compare commits
5 Commits
b8cd01b914
...
4e10039bfb
Author | SHA1 | Date | |
---|---|---|---|
4e10039bfb | |||
b0147157f1 | |||
1fd91cb343 | |||
dbfedc2c4d | |||
c8cc6d34ae |
|
@ -9,25 +9,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.annabunch.es/annabunches/adventofcode/2020/lib/fileutils"
|
"git.annabunch.es/annabunches/adventofcode/2020/lib/fileutils"
|
||||||
|
"git.annabunch.es/annabunches/adventofcode/2020/lib/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func splitPassports(input []string) []string {
|
|
||||||
converted := []string{}
|
|
||||||
|
|
||||||
current := ""
|
|
||||||
for _, line := range input {
|
|
||||||
if line == "" {
|
|
||||||
converted = append(converted, current)
|
|
||||||
current = ""
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
current += " " + line
|
|
||||||
}
|
|
||||||
|
|
||||||
return converted
|
|
||||||
}
|
|
||||||
|
|
||||||
func countValidPassports(input []string, step string) int {
|
func countValidPassports(input []string, step string) int {
|
||||||
total := 0
|
total := 0
|
||||||
for _, line := range input {
|
for _, line := range input {
|
||||||
|
@ -147,7 +131,7 @@ func makeInt(input string) int {
|
||||||
func main() {
|
func main() {
|
||||||
step := os.Args[1]
|
step := os.Args[1]
|
||||||
values := fileutils.InputParserStrings(os.Args[2])
|
values := fileutils.InputParserStrings(os.Args[2])
|
||||||
values = splitPassports(values)
|
values = util.SplitOnBlankLine(values)
|
||||||
|
|
||||||
fmt.Println("Valid Passports:", countValidPassports(values, step))
|
fmt.Println("Valid Passports:", countValidPassports(values, step))
|
||||||
}
|
}
|
||||||
|
|
61
2020/day06.go
Normal file
61
2020/day06.go
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.annabunch.es/annabunches/adventofcode/2020/lib/fileutils"
|
||||||
|
"git.annabunch.es/annabunches/adventofcode/2020/lib/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func countAnswerUnion(input string) int {
|
||||||
|
charMap := make(map[rune]bool)
|
||||||
|
|
||||||
|
for _, char := range input {
|
||||||
|
if char == ' ' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := charMap[char]; !ok {
|
||||||
|
charMap[char] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len(charMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
func countAnswerIntersection(input string) int {
|
||||||
|
charMap := make(map[rune]int)
|
||||||
|
answers := strings.Split(strings.Trim(input, " "), " ")
|
||||||
|
|
||||||
|
for _, answer := range answers {
|
||||||
|
for _, char := range answer {
|
||||||
|
charMap[char]++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
total := 0
|
||||||
|
for _, count := range charMap {
|
||||||
|
if count == len(answers) {
|
||||||
|
total++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
step := os.Args[1]
|
||||||
|
values := fileutils.InputParserStrings(os.Args[2])
|
||||||
|
groups := util.SplitOnBlankLine(values)
|
||||||
|
|
||||||
|
total := 0
|
||||||
|
for _, line := range groups {
|
||||||
|
if step == "1" {
|
||||||
|
total += countAnswerUnion(line)
|
||||||
|
}
|
||||||
|
if step == "2" {
|
||||||
|
total += countAnswerIntersection(line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("Total:", total)
|
||||||
|
}
|
113
2020/day07.go
Normal file
113
2020/day07.go
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"git.annabunch.es/annabunches/adventofcode/2020/lib/fileutils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Node struct {
|
||||||
|
Color string
|
||||||
|
Children map[*Node]int
|
||||||
|
}
|
||||||
|
|
||||||
|
var nodeMap map[string]*Node
|
||||||
|
|
||||||
|
var colorRe = regexp.MustCompile("^(.*?) bags contain")
|
||||||
|
var childRe = regexp.MustCompile("(?:contain|,) (\\d+) (.*?) bag")
|
||||||
|
|
||||||
|
func findOrCreateNode(color string) *Node {
|
||||||
|
if node, ok := nodeMap[color]; ok {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
node := &Node{
|
||||||
|
Color: color,
|
||||||
|
}
|
||||||
|
nodeMap[color] = node
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseRule(line string) {
|
||||||
|
if line == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
color := colorRe.FindStringSubmatch(line)[1]
|
||||||
|
|
||||||
|
node := findOrCreateNode(color)
|
||||||
|
|
||||||
|
children := make(map[*Node]int)
|
||||||
|
childrenData := childRe.FindAllStringSubmatch(line, 128)
|
||||||
|
|
||||||
|
for _, childData := range childrenData {
|
||||||
|
child := findOrCreateNode(childData[2])
|
||||||
|
count, err := strconv.Atoi(childData[1])
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf(err.Error())
|
||||||
|
}
|
||||||
|
children[child] = count
|
||||||
|
}
|
||||||
|
|
||||||
|
node.Children = children
|
||||||
|
}
|
||||||
|
|
||||||
|
func findInDescendants(node *Node, color string) bool {
|
||||||
|
for child, _ := range node.Children {
|
||||||
|
if rFindInDescendants(child, color) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func rFindInDescendants(node *Node, color string) bool {
|
||||||
|
// found it
|
||||||
|
if node.Color == color {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for child, _ := range node.Children {
|
||||||
|
if rFindInDescendants(child, color) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func countChildren(node *Node) int {
|
||||||
|
total := 1 // count ourself
|
||||||
|
for child, count := range node.Children {
|
||||||
|
total += count * countChildren(child)
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
step := os.Args[1]
|
||||||
|
values := fileutils.InputParserStrings(os.Args[2])
|
||||||
|
|
||||||
|
nodeMap = make(map[string]*Node)
|
||||||
|
|
||||||
|
for _, line := range values {
|
||||||
|
parseRule(line)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch step {
|
||||||
|
case "1":
|
||||||
|
total := 0
|
||||||
|
for _, node := range nodeMap {
|
||||||
|
if findInDescendants(node, "shiny gold") {
|
||||||
|
total++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("Total:", total)
|
||||||
|
|
||||||
|
case "2":
|
||||||
|
fmt.Println("Total:", countChildren(nodeMap["shiny gold"])-1)
|
||||||
|
}
|
||||||
|
}
|
101
2020/day08.go
Normal file
101
2020/day08.go
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.annabunch.es/annabunches/adventofcode/2020/lib/fileutils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Instruction struct {
|
||||||
|
Operation string
|
||||||
|
Operand int
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseInstruction(input string) Instruction {
|
||||||
|
data := strings.Split(input, " ")
|
||||||
|
op := data[0]
|
||||||
|
operand, err := strconv.Atoi(strings.TrimPrefix(data[1], "+"))
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf(err.Error())
|
||||||
|
}
|
||||||
|
return Instruction{
|
||||||
|
Operation: op,
|
||||||
|
Operand: operand,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeInstruction(ins Instruction, ip, acc *int, history map[int]bool) {
|
||||||
|
history[*ip] = true
|
||||||
|
switch ins.Operation {
|
||||||
|
case "acc":
|
||||||
|
*acc += ins.Operand
|
||||||
|
*ip++
|
||||||
|
case "jmp":
|
||||||
|
*ip += ins.Operand
|
||||||
|
case "nop":
|
||||||
|
*ip++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeProgram(instructions []Instruction) (int, bool) {
|
||||||
|
ip := 0
|
||||||
|
acc := 0
|
||||||
|
history := make(map[int]bool)
|
||||||
|
|
||||||
|
for ip < len(instructions) {
|
||||||
|
if _, found := history[ip]; found {
|
||||||
|
// detect infinite loop and return
|
||||||
|
return acc, true
|
||||||
|
}
|
||||||
|
executeInstruction(instructions[ip], &ip, &acc, history)
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
step := os.Args[1]
|
||||||
|
values := fileutils.InputParserStrings(os.Args[2])
|
||||||
|
|
||||||
|
instructions := make([]Instruction, 0)
|
||||||
|
|
||||||
|
for _, line := range values {
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ins := parseInstruction(line)
|
||||||
|
instructions = append(instructions, ins)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch step {
|
||||||
|
case "1":
|
||||||
|
ret, loop := executeProgram(instructions)
|
||||||
|
if loop {
|
||||||
|
fmt.Println("Loop detected. Last ACC value:", ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
case "2":
|
||||||
|
for i, ins := range instructions {
|
||||||
|
if ins.Operation == "jmp" || ins.Operation == "nop" {
|
||||||
|
newInstructions := make([]Instruction, len(instructions))
|
||||||
|
copy(newInstructions, instructions)
|
||||||
|
switch ins.Operation {
|
||||||
|
case "jmp":
|
||||||
|
newInstructions[i].Operation = "nop"
|
||||||
|
case "nop":
|
||||||
|
newInstructions[i].Operation = "jmp"
|
||||||
|
}
|
||||||
|
ret, loop := executeProgram(newInstructions)
|
||||||
|
|
||||||
|
if !loop {
|
||||||
|
fmt.Println(ret)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
121
2020/day09.go
Normal file
121
2020/day09.go
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"git.annabunch.es/annabunches/adventofcode/2020/lib/fileutils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SumTracker map[int][]Tuple
|
||||||
|
|
||||||
|
type Tuple struct {
|
||||||
|
First, Second int
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkValue(sumMap SumTracker, value int) bool {
|
||||||
|
_, ok := sumMap[value]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func addSums(sumMap SumTracker, values []int, index int) {
|
||||||
|
for i := index - 25; i < index; i++ {
|
||||||
|
sum := values[i] + values[index]
|
||||||
|
sumMap[sum] = append(sumMap[sum], Tuple{First: i, Second: index})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeSums(sumMap SumTracker, index int) {
|
||||||
|
for sum, tupleList := range sumMap {
|
||||||
|
newList := make([]Tuple, 0)
|
||||||
|
|
||||||
|
for _, tuple := range tupleList {
|
||||||
|
if !(tuple.First == index || tuple.Second == index) {
|
||||||
|
newList = append(newList, tuple)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sumMap[sum] = newList
|
||||||
|
if len(sumMap[sum]) == 0 {
|
||||||
|
delete(sumMap, sum)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// find and return the slice of values that sums to sum
|
||||||
|
func findListSum(values []int, sum int) []int {
|
||||||
|
i := 0
|
||||||
|
j := 0
|
||||||
|
total := 0
|
||||||
|
for total != sum {
|
||||||
|
for total < sum {
|
||||||
|
if j >= len(values) {
|
||||||
|
log.Panicf("Couldn't find a match.")
|
||||||
|
}
|
||||||
|
|
||||||
|
total += values[j]
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
|
||||||
|
for total > sum {
|
||||||
|
total -= values[i]
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return values[i:j]
|
||||||
|
}
|
||||||
|
|
||||||
|
func sumMinMax(values []int) int {
|
||||||
|
min := values[0]
|
||||||
|
max := values[0]
|
||||||
|
|
||||||
|
for _, x := range values {
|
||||||
|
if x < min {
|
||||||
|
min = x
|
||||||
|
}
|
||||||
|
|
||||||
|
if x > max {
|
||||||
|
max = x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return min + max
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
step := os.Args[1]
|
||||||
|
values := fileutils.InputParserInts(os.Args[2])
|
||||||
|
|
||||||
|
var badValue int
|
||||||
|
sumMap := make(SumTracker)
|
||||||
|
|
||||||
|
// build up the preamble
|
||||||
|
for i := 0; i < 25; i++ {
|
||||||
|
for j := i + 1; j < 25; j++ {
|
||||||
|
sum := values[i] + values[j]
|
||||||
|
if _, ok := sumMap[sum]; !ok {
|
||||||
|
sumMap[sum] = make([]Tuple, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
sumMap[sum] = append(sumMap[sum], Tuple{First: i, Second: j})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 25; i < len(values); i++ {
|
||||||
|
if !checkValue(sumMap, values[i]) {
|
||||||
|
badValue = values[i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
addSums(sumMap, values, i)
|
||||||
|
removeSums(sumMap, i-25)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch step {
|
||||||
|
case "1":
|
||||||
|
fmt.Println(badValue)
|
||||||
|
case "2":
|
||||||
|
sumValues := findListSum(values, badValue)
|
||||||
|
fmt.Println(sumMinMax(sumValues))
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,27 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func InputParserInts(filename string) []int {
|
||||||
|
file, err := os.Open(filename)
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
values := make([]int, 0)
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
x, err := strconv.Atoi(scanner.Text())
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf(err.Error())
|
||||||
|
}
|
||||||
|
values = append(values, x)
|
||||||
|
}
|
||||||
|
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
|
||||||
func InputParserIntMap(filename string) map[int]bool {
|
func InputParserIntMap(filename string) map[int]bool {
|
||||||
file, err := os.Open(filename)
|
file, err := os.Open(filename)
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
21
2020/lib/util/strings.go
Normal file
21
2020/lib/util/strings.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
// Takes a slice of strings as from reading each line in a file.
|
||||||
|
// Concatenates strings, creating new ones when blank lines are encountered
|
||||||
|
// NB: adds a single space to the beginning of each concatenated line.
|
||||||
|
func SplitOnBlankLine(input []string) []string {
|
||||||
|
converted := []string{}
|
||||||
|
|
||||||
|
current := ""
|
||||||
|
for _, line := range input {
|
||||||
|
if line == "" {
|
||||||
|
converted = append(converted, current)
|
||||||
|
current = ""
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
current += " " + line
|
||||||
|
}
|
||||||
|
|
||||||
|
return converted
|
||||||
|
}
|
15
2020/template.go
Normal file
15
2020/template.go
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"git.annabunch.es/annabunches/adventofcode/2020/lib/fileutils"
|
||||||
|
"git.annabunch.es/annabunches/adventofcode/2020/lib/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
step := os.Args[1]
|
||||||
|
values := fileutils.InputParserStrings(os.Args[2])
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user