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