Compare commits

...

5 Commits

Author SHA1 Message Date
4e10039bfb Day 9 solution. 2020-12-11 10:00:29 +00:00
b0147157f1 Add day 8 solution. 2020-12-11 05:33:41 +00:00
1fd91cb343 Add day 7 solution. 2020-12-11 04:22:00 +00:00
dbfedc2c4d Add a template to start each day from. 2020-12-11 04:21:50 +00:00
c8cc6d34ae Add day 6 solution. 2020-12-11 03:32:15 +00:00
8 changed files with 455 additions and 18 deletions

View File

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

View File

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