181 lines
3.7 KiB
Go
181 lines
3.7 KiB
Go
package main
|
|
|
|
import (
|
|
"AoC2020/helper"
|
|
"fmt"
|
|
"os"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type Player struct {
|
|
deck []int
|
|
previousDecks [][]int
|
|
}
|
|
|
|
type Game struct {
|
|
players [2]Player
|
|
winner int
|
|
}
|
|
|
|
var lineBreak = "\n"
|
|
|
|
func main() {
|
|
game := Game{}
|
|
args := os.Args[1:]
|
|
input, err := helper.GetFile(args[0])
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
playerInput := strings.Split(input, lineBreak+lineBreak)
|
|
player1 := parsePlayer(playerInput[0])
|
|
player2 := parsePlayer(playerInput[1])
|
|
game.players[0] = player1
|
|
game.players[1] = player2
|
|
for game.winner == 0 {
|
|
game = game.runRoundRecursive()
|
|
fmt.Println(game.players[0])
|
|
fmt.Println(game.players[1])
|
|
}
|
|
fmt.Println(game.winner)
|
|
fmt.Println(game.players[game.winner-1].deck)
|
|
fmt.Println(game.caculateWinnerScore())
|
|
}
|
|
|
|
func parsePlayer(input string) Player {
|
|
var player = Player{}
|
|
playerInput := strings.Split(input, lineBreak)
|
|
for _, val := range playerInput[1:] {
|
|
number, _ := strconv.Atoi(val)
|
|
player.deck = append(player.deck, number)
|
|
}
|
|
return player
|
|
}
|
|
|
|
func (g Game) runRound() Game {
|
|
g = g.saveCurrentDeck()
|
|
var cardP0 int
|
|
var cardP1 int
|
|
g.players[0], cardP0 = g.players[0].drawCard()
|
|
g.players[1], cardP1 = g.players[1].drawCard()
|
|
winnerCards := []int{cardP0, cardP1}
|
|
sort.Sort(sort.Reverse(sort.IntSlice(winnerCards)))
|
|
if cardP0 > cardP1 {
|
|
g.players[0] = g.players[0].addToDeck(winnerCards)
|
|
}
|
|
if cardP1 > cardP0 {
|
|
g.players[1] = g.players[1].addToDeck(winnerCards)
|
|
}
|
|
if len(g.players[0].deck) == 0 {
|
|
g.winner = 2
|
|
}
|
|
if len(g.players[1].deck) == 0 {
|
|
g.winner = 1
|
|
}
|
|
return g
|
|
}
|
|
|
|
func (g Game) caculateWinnerScore() int {
|
|
winnerDeck := g.players[g.winner-1].deck
|
|
return calculateScoreForDeck(winnerDeck)
|
|
}
|
|
|
|
func calculateScoreForDeck(deck []int) int {
|
|
deckLen := len(deck)
|
|
sum := 0
|
|
for i := 0; i < deckLen; i++ {
|
|
sum += deck[i] * (deckLen - i)
|
|
}
|
|
return sum
|
|
}
|
|
|
|
func (g Game) saveCurrentDeck() Game {
|
|
for i, _ := range g.players {
|
|
g.players[i] = g.players[i].saveCurrentDeck()
|
|
}
|
|
return g
|
|
}
|
|
|
|
func (g Game) runRoundRecursive() Game {
|
|
p1 := g.players[0]
|
|
p2 := g.players[1]
|
|
for i, _ := range p1.previousDecks {
|
|
if helper.Equal(p1.previousDecks[i], p1.deck) && helper.Equal(p2.previousDecks[i], p2.deck) {
|
|
g.winner = 1
|
|
return g
|
|
}
|
|
}
|
|
var roundWinner int
|
|
p1 = p1.saveCurrentDeck()
|
|
p2 = p2.saveCurrentDeck()
|
|
var cardP1 int
|
|
var cardP2 int
|
|
p1, cardP1 = p1.drawCard()
|
|
p2, cardP2 = p2.drawCard()
|
|
if len(p1.deck) >= cardP1 && len(p2.deck) >= cardP2 {
|
|
var newGame Game
|
|
var newPlayer1 Player
|
|
var newPlayer2 Player
|
|
newPlayer1.deck = make([]int, cardP1)
|
|
newPlayer2.deck = make([]int, cardP2)
|
|
copy(newPlayer1.deck, p1.deck[:cardP1])
|
|
copy(newPlayer2.deck, p2.deck[:cardP2])
|
|
newGame.players = [2]Player{newPlayer1, newPlayer2}
|
|
roundWinner = newGame.runRecursive().winner
|
|
} else {
|
|
if cardP1 > cardP2 {
|
|
roundWinner = 1
|
|
}
|
|
if cardP2 > cardP1 {
|
|
roundWinner = 2
|
|
}
|
|
}
|
|
if roundWinner == 1 {
|
|
p1 = p1.addToDeck([]int{cardP1, cardP2})
|
|
}
|
|
if roundWinner == 2 {
|
|
p2 = p2.addToDeck([]int{cardP2, cardP1})
|
|
}
|
|
if len(p1.deck) == 0 {
|
|
g.winner = 2
|
|
}
|
|
if len(p2.deck) == 0 {
|
|
g.winner = 1
|
|
}
|
|
g.players = [2]Player{p1, p2}
|
|
return g
|
|
}
|
|
|
|
func (g Game) run() Game {
|
|
for g.winner == 0 {
|
|
g = g.runRound()
|
|
}
|
|
return g
|
|
}
|
|
|
|
func (g Game) runRecursive() Game {
|
|
for g.winner == 0 {
|
|
g = g.runRoundRecursive()
|
|
}
|
|
return g
|
|
}
|
|
|
|
func (p Player) drawCard() (Player, int) {
|
|
card := p.deck[0]
|
|
p.deck = helper.DeleteAt(p.deck, 0)
|
|
return p, card
|
|
}
|
|
|
|
func (p Player) saveCurrentDeck() Player {
|
|
copyOfDeck := make([]int, len(p.deck))
|
|
copy(copyOfDeck, p.deck)
|
|
p.previousDecks = append(p.previousDecks, copyOfDeck)
|
|
return p
|
|
}
|
|
|
|
func (p Player) addToDeck(cards []int) Player {
|
|
p.deck = append(p.deck, cards...)
|
|
return p
|
|
}
|