190 lines
3.8 KiB
Go

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
}