adventofcode/2020/day22.go
2020-12-25 05:49:31 +00:00

123 lines
2.4 KiB
Go

package main
import (
"fmt"
"os"
"strings"
"git.annabunch.es/annabunches/adventofcode/2020/lib/util"
)
func parseInput(input []string) [][]int {
decks := make([][]int, 2)
decks[0] = make([]int, 0)
decks[1] = make([]int, 0)
player := 0
for _, line := range input {
if strings.HasPrefix(line, "Player") {
continue
}
if line == "" {
player++
continue
}
decks[player] = append(decks[player], util.MustAtoi(line))
}
return decks
}
func playGame(decks [][]int, step string) (int, [][]int) {
gameStates := make(map[string]struct{})
found := struct{}{}
for len(decks[0]) > 0 && len(decks[1]) > 0 {
state := serializeGame(decks)
if _, ok := gameStates[state]; ok && step == "2" {
return 0, decks
}
gameStates[state] = found
var winner int
// take the top cards
card0 := decks[0][0]
card1 := decks[1][0]
decks[0] = decks[0][1:]
decks[1] = decks[1][1:]
// determine the winner, put the cards in order
if card0 > card1 {
winner = 0
} else {
winner = 1
}
// if each card is >= the number of cards in that deck
if step == "2" && card0 <= len(decks[0]) && card1 <= len(decks[1]) {
newDecks := make([][]int, 2)
newDecks[0] = make([]int, card0)
newDecks[1] = make([]int, card1)
copy(newDecks[0], decks[0][:card0])
copy(newDecks[1], decks[1][:card1])
// Recursive Combat throws out the "normal" winner above
winner, _ = playGame(newDecks, step)
}
// stack the cards for adding to the winner's bottom
cards := make([]int, 2)
if winner == 0 {
cards[0] = card0
cards[1] = card1
} else {
cards[0] = card1
cards[1] = card0
}
// and add them to the winner's bottom
decks[winner] = append(decks[winner], cards...)
}
if len(decks[0]) > 0 {
return 0, decks
}
return 1, decks
}
func serializeGame(decks [][]int) string {
out := ""
for _, deck := range decks {
for _, card := range deck {
out = out + string(card) + ","
}
out = out + "|"
}
return out
}
func calculateScore(decks [][]int) int {
score := 0
var index int
if len(decks[0]) > 0 {
index = 0
} else {
index = 1
}
deckSize := len(decks[index])
for i := deckSize - 1; i >= 0; i-- {
score += decks[index][i] * (deckSize - i)
}
return score
}
func main() {
step := os.Args[1]
values := util.InputParserStrings(os.Args[2])
input := parseInput(values)
_, decks := playGame(input, step)
fmt.Println(calculateScore(decks))
}