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