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 }