adventofcode/2020/day23.go

126 lines
3.0 KiB
Go
Raw Normal View History

2020-12-25 09:58:23 +00:00
package main
import (
"fmt"
"log"
"os"
"strconv"
"git.annabunch.es/annabunches/adventofcode/2020/lib/util"
)
type Cup struct {
label int
next *Cup
}
func parseInput(input string, step string) (*Cup, map[int]*Cup) {
labelMap := make(map[int]*Cup)
var firstCup *Cup
var prev *Cup
first := true
for _, char := range input {
label := util.MustAtoi(string(char))
newCup := &Cup{
label: label,
}
labelMap[label] = newCup
if first {
first = false
firstCup = newCup
} else {
prev.next = newCup
}
prev = newCup
}
if step == "2" {
for i := 10; i <= 1000000; i++ {
newCup := &Cup{
label: i,
}
prev.next = newCup
prev = newCup
labelMap[i] = newCup
}
}
prev.next = firstCup
return firstCup, labelMap
}
func move(current *Cup, labels map[int]*Cup, step string) *Cup {
// The crab picks up the three cups that are immediately clockwise of the current cup. They are removed from the circle; cup spacing is adjusted as necessary to maintain the circle.
pickedUp := current.next
current.next = current.next.next.next.next
cursor := pickedUp
holding := make(map[int]struct{})
for i := 0; i < 3; i++ {
holding[cursor.label] = struct{}{}
cursor = cursor.next
}
// The crab selects a destination cup: the cup with a label equal to the current cup's label minus one. If this would select one of the cups that was just picked up, the crab will keep subtracting one until it finds a cup that wasn't just picked up. If at any point in this process the value goes below the lowest value on any cup's label, it wraps around to the highest value on any cup's label instead.
dest := current.label - 1
_, nope := holding[dest]
for nope || dest == 0 {
dest--
if dest <= 0 {
switch step {
case "1":
dest = 9
case "2":
dest = 1000000
}
}
_, nope = holding[dest]
}
// The crab places the cups it just picked up so that they are immediately clockwise of the destination cup. They keep the same order as when they were picked up.
destCup, ok := labels[dest]
if !ok {
log.Panicf("No such cup %d", dest)
}
oldNext := destCup.next
destCup.next = pickedUp
pickedUp.next.next.next = oldNext
// The crab selects a new current cup: the cup which is immediately clockwise of the current cup.
return current.next
}
func formatCups(start *Cup) string {
answer := ""
startLabel := start.label
for cursor := start.next; cursor.label != startLabel; cursor = cursor.next {
answer = answer + strconv.Itoa(cursor.label)
}
return answer
}
// too high: 540428194020
func main() {
step := os.Args[1]
values := os.Args[2]
current, labels := parseInput(values, step)
switch step {
case "1":
for i := 0; i < 100; i++ {
current = move(current, labels, step)
}
fmt.Println(formatCups(labels[1]))
case "2":
for i := 0; i < 10000000; i++ {
current = move(current, labels, step)
}
cursor := labels[1]
fmt.Println(cursor.next.label)
fmt.Println(cursor.next.next.label)
fmt.Println(cursor.next.label * cursor.next.next.label)
}
}