Files
advent-of-code-go/2020/day23/main.go
T

118 lines
2.6 KiB
Go

package main
import (
"flag"
"fmt"
"strings"
"github.com/alexchao26/advent-of-code-go/cast"
"github.com/alexchao26/advent-of-code-go/util"
)
func main() {
var part int
flag.IntVar(&part, "part", 1, "part 1 or 2")
flag.Parse()
fmt.Println("Running part", part)
ans := crabCups(util.ReadFile("./input.txt"), part)
fmt.Println("Output:", ans)
}
// LLNode is a doubly linked list node
type LLNode struct {
val int
left, right *LLNode
}
// ~1250/ 199
func crabCups(input string, part int) int {
cups := strings.Split(input, "")
currentCup := &LLNode{val: cast.ToInt(cups[0])}
// LRU caches are a hashmap of integers pointing to a pointer of a (doubly) LL node
// so finding a given node is constant time through the hash map
lruCacheMap := map[int]*LLNode{currentCup.val: currentCup}
// setup initial cups
iter := currentCup
for _, v := range cups[1:] {
iter.right = &LLNode{
val: cast.ToInt(v),
left: iter,
}
iter = iter.right
lruCacheMap[iter.val] = iter
}
rounds := 100 // part 1 default
// for part 2 make rounds higher and add a bunch of extra nodes
if part == 2 {
rounds = 10000000
for i := 10; i <= 1000000; i++ {
iter.right = &LLNode{
val: i,
left: iter,
}
iter = iter.right
lruCacheMap[iter.val] = iter
}
}
iter.right = currentCup
currentCup.left = iter
for i := 0; i < rounds; i++ {
valToFind := currentCup.val - 1
ignoreVals := map[int]bool{}
for it := currentCup.right; len(ignoreVals) < 3; it = it.right {
ignoreVals[it.val] = true
}
// if the val to find is in ignore vals or is less than smallest possible
// value, then loop and decrement until a valid value is found
for ignoreVals[valToFind] || valToFind <= 0 {
valToFind--
// loop back to highest numbered cup if value goes below zero
if valToFind <= 0 {
valToFind = len(lruCacheMap)
}
}
// next 3
startOfThree := currentCup.right
endOfThree := currentCup.right.right.right
// remove the three off the end of the current cup
currentCup.right = endOfThree.right
currentCup.right.left = currentCup
// find the LL node to attach the 3 cups to (directly from LRU cache)
attachAfterMe := lruCacheMap[valToFind]
// mash the 3 cups into the doubly LL
endOfThree.right = attachAfterMe.right
attachAfterMe.right.left = endOfThree
attachAfterMe.right = startOfThree
startOfThree.left = attachAfterMe
// move currentCup pointer
currentCup = currentCup.right
}
oneCup := lruCacheMap[1]
if part == 2 {
return oneCup.right.val * oneCup.right.right.val
}
var ans int
for i := 0; i < 8; i++ {
oneCup = oneCup.right
ans *= 10
ans += oneCup.val
}
return ans
}