diff --git a/2020/day22.go b/2020/day22.go new file mode 100644 index 0000000..e238a22 --- /dev/null +++ b/2020/day22.go @@ -0,0 +1,122 @@ +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)) +}