package main import ( "fmt" "os" "slices" "strconv" "strings" ) type Queue struct { arr []int head uint tail uint } func (s *Queue) Dequeue() int { s.head++ return s.arr[s.head - 1] } func (s *Queue) Enqueue(num int) { if len(s.arr) <= int(s.tail) { s.arr = append(s.arr, num) } else { s.arr[s.tail] = num } s.tail++ } func (s *Queue) Print() string { str := "" for i := s.head; i < s.tail; i++ { str += strconv.Itoa(s.arr[i]) + "," } return str } func main() { content, err := os.ReadFile("./input.txt") if err != nil { panic(err) } players := strings.Split(string(content), "\n\n") player1 := strings.Split(players[0], "\n")[1:] player2 := strings.Split(players[1], "\n")[1:] player1Cards := Queue{ arr: make([]int, 0), head: 0, tail: 0, } player2Cards := Queue{ arr: make([]int, 0), head: 0, tail: 0, } for _, v := range player1 { n, err := strconv.Atoi(v) if err != nil { panic(err) } player1Cards.Enqueue(n) } for _, v := range player2 { if len(v) == 0 { continue } n, err := strconv.Atoi(v) if err != nil { panic(err) } player2Cards.Enqueue(n) } /* rounds := 0 for { if player1Cards.head == player1Cards.tail || player2Cards.head == player2Cards.tail { break } player1Card := player1Cards.Dequeue() player2Card := player2Cards.Dequeue() if player1Card > player2Card { player1Cards.Enqueue(player1Card) player1Cards.Enqueue(player2Card) } else { player2Cards.Enqueue(player2Card) player2Cards.Enqueue(player1Card) } rounds++ } */ _, p1, p2 := PlayGame(player1Cards, player2Cards) var winningScore uint = 0 if p1.tail - p1.head < p2.tail - p2.head { for i := p2.head; i < p2.tail; i++ { winningScore += (p2.tail - i) * uint(p2.arr[i]) } } else { for i := p1.head; i < p1.tail; i++ { winningScore += (p1.tail - i) * uint(p1.arr[i]) } } fmt.Println(winningScore) } // true = player1, false = player2 func PlayGame(player1 Queue, player2 Queue) (bool, *Queue, *Queue) { cache1 := make(map[string]bool) cache2 := make(map[string]bool) for { if player1.head == player1.tail || player2.head == player2.tail { return player2.head == player2.tail, &player1, &player2 } // Before drawing, check. player1string := player1.Print() player2string := player2.Print() _, exists := cache1[player1string] if exists { return true, &player1, &player2 } _, exists = cache2[player2string] if exists { return true, &player1, &player2 } cache1[player1string] = true cache2[player2string] = true player1Card := player1.Dequeue() player2Card := player2.Dequeue() if int(player1.tail) - int(player1.head) >= player1Card && int(player2.tail) - int(player2.head) >= player2Card { // Recursive case! player1Copy := Queue{ arr: slices.Clone(player1.arr), head: player1.head, tail: player1.head + uint(player1Card), } player2Copy := Queue{ arr: slices.Clone(player2.arr), head: player2.head, tail: player2.head + uint(player2Card), } winner, _, _ := PlayGame(player1Copy, player2Copy) if winner { player1.Enqueue(player1Card) player1.Enqueue(player2Card) } else { player2.Enqueue(player2Card) player2.Enqueue(player1Card) } } else { if player1Card > player2Card { player1.Enqueue(player1Card) player1.Enqueue(player2Card) } else { player2.Enqueue(player2Card) player2.Enqueue(player1Card) } } } } func GetString(arr []int) string { s := "" for _, v := range arr { s += "," + strconv.Itoa(v) } return s }