AoC2020/day22/day22.go
Karl Spickermann 5dd123ea97 Day22
2020-12-22 18:37:58 +01:00

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
}