package main import ( "bufio" "flag" "fmt" "io" "os" "strconv" ) // Deck ... type Deck []int func sameDeck(a, b Deck) bool { if len(a) != len(b) { return false } for i := range a { if a[i] != b[i] { return false } } return true } // Task1 ... func Task1(input []Deck, debug bool) int { p1, p2 := input[0], input[1] round := 1 for len(p1) > 0 && len(p2) > 0 { if debug { fmt.Printf("\n-- Round %d --\n", round) fmt.Printf("Player 1's deck: %+v\n", p1) fmt.Printf("Player 2's deck: %+v\n", p2) } a, b := p1[0], p2[0] if debug { fmt.Printf("Player 1 plays: %d\n", a) fmt.Printf("Player 2 plays: %d\n", b) } if a > b { if debug { fmt.Printf("Player 1 wins the round!\n") } p1 = append(p1[1:], a, b) p2 = p2[1:] } else { if debug { fmt.Printf("Player 2 wins the round!\n") } p1 = p1[1:] p2 = append(p2[1:], b, a) } round++ } if debug { fmt.Println("\n== Post-game results ==") fmt.Printf("Player 1's deck: %+v\n", p1) fmt.Printf("Player 2's deck: %+v\n", p2) fmt.Println() } var deck Deck if len(p1) > 0 { deck = p1 } else { deck = p2 } var result int for i := 0; i < len(deck); i++ { if debug { fmt.Printf("+ %2d * %2d\n", deck[i], len(deck)-i) } result += deck[i] * (len(deck) - i) } return result } func playRecursiveCombat(game int, p1, p2 Deck, debug bool) (int, Deck, Deck) { if debug { fmt.Printf("\n=== Game %d ===\n", game) } round := 1 memory := make(map[int][]Deck) for len(p1) > 0 && len(p2) > 0 { if debug { fmt.Printf("\n-- Round %d (Game %d) --\n", round, game) fmt.Printf("Player 1's deck: %+v\n", p1) fmt.Printf("Player 2's deck: %+v\n", p2) } a, b := p1[0], p2[0] p1 = p1[1:] p2 = p2[1:] if debug { fmt.Printf("Player 1 plays: %d\n", a) fmt.Printf("Player 2 plays: %d\n", b) } var playerWon int if len(p1) >= a && len(p2) >= b { if debug { fmt.Println("Playing a sub-game to determine the winner...") } p1C := make([]int, a) p2C := make([]int, b) copy(p1C, p1[:a]) copy(p2C, p2[:b]) playerWon, _, _ = playRecursiveCombat(game+1, p1C, p2C, debug) if debug { fmt.Printf("The winner of game %d is player %d\n", game+1, playerWon) } } else { if a > b { playerWon = 1 } else { playerWon = 2 } if debug { fmt.Printf( "Player %d wins round %d of game %d!\n", playerWon, round, game, ) } } if playerWon == 1 { p1 = append(p1, a, b) } else { p2 = append(p2, b, a) } for _, m := range memory { if sameDeck(m[0], p1) && sameDeck(m[1], p2) { if debug { fmt.Println("infinite loop, p1 won") } return 1, p1, p2 } } memory[round] = []Deck{p1, p2} round++ } if len(p1) > len(p2) { return 1, p1, p2 } return 2, p1, p2 } // Task2 ... func Task2(input []Deck, debug bool) int { p1, p2 := input[0], input[1] game := 1 player, p1, p2 := playRecursiveCombat(game, p1, p2, debug) if debug { fmt.Println("\n== Post-game results ==") fmt.Printf("Player 1's deck: %+v\n", p1) fmt.Printf("Player 2's deck: %+v\n", p2) fmt.Println() } var deck Deck if player == 1 { deck = p1 } else { deck = p2 } var result int for i := 0; i < len(deck); i++ { if debug { fmt.Printf("+ %2d * %2d\n", deck[i], len(deck)-i) } result += deck[i] * (len(deck) - i) } return result } func readInput(reader io.Reader) []Deck { input := make([]Deck, 2) input[0] = make([]int, 0, 10) input[1] = make([]int, 0, 10) var current int scanner := bufio.NewScanner(reader) scanner.Scan() for scanner.Scan() { line := scanner.Text() if line == "" { scanner.Scan() current++ continue } val, _ := strconv.Atoi(line) input[current] = append(input[current], val) } return input } func main() { var debug bool flag.BoolVar(&debug, "debug", false, "debug") flag.Parse() var input []Deck file, _ := os.Open("input.txt") input = readInput(file) file.Close() result := Task1(input, debug) fmt.Printf("Task 1: %d\n", result) result = Task2(input, debug) fmt.Printf("Task 2: %d\n", result) }