package main

import "fmt"

type player struct {
	position     int
	score        int
	roundsPlayed int
}

type game struct {
	players       [2]player
	currentPlayer int
	winner        int
	winscore      int
}

func main() {
	n := 6
	player1 := player{8, 0, 0}
	player2 := player{7, 0, 0}

	part1(player1, player2, n)
	part2(player1, player2)
}

func part2(player1 player, player2 player) {
	diceResultMap := generateDiceResultMap()
	gameMap := make(map[game]int64)
	startGame := game{[2]player{player1, player2}, 0, -1, 21}
	gameMap[startGame] = 1
	for i := 0; i < 20; i++ {
		tmpGameMap := make(map[game]int64)
		for game, gameAmount := range gameMap {
			if game.winner == -1 {
				for diceResult1, diceResultAmount1 := range diceResultMap {
					tmpGame := game
					tmpGame.playOneRoung(diceResult1)
					tmpGameMap[tmpGame] += gameAmount * diceResultAmount1
				}
			} else {
				tmpGameMap[game] += gameAmount
			}
		}
		gameMap = tmpGameMap
		printGameMapInfos(gameMap)
		fmt.Println()
	}

}

func printGameMapInfos(gameMap map[game]int64) {
	fmt.Println(len(gameMap))
	var amountGames int64
	var winnersPlayer1 int64
	var winnersPlayer2 int64
	var winSum int64
	var bothWinners int64
	var noWin int64
	for key, val := range gameMap {
		if key.winner == 0 {
			winnersPlayer1 += val
			winSum += val
		}
		if key.winner == 1 {
			winnersPlayer2 += val
			winSum += val
		}
		if key.winner == -1 {
			noWin += val
		}
		amountGames += val
	}
	fmt.Printf("Amount Games: %d \n", amountGames)
	fmt.Printf("Winners: %d \n", winSum)
	fmt.Printf("Games Winner 1: %d \n", winnersPlayer1)
	fmt.Printf("Games Winner 2: %d \n", winnersPlayer2)
	fmt.Printf("Games No Win: %d \n", noWin)
	fmt.Printf("Games Both Win: %d \n", bothWinners)
}

func (game *game) playOneRoung(increase int) {
	if increasePlayer(&game.players[game.currentPlayer], increase, game.winscore) {
		game.winner = game.currentPlayer
	}
	if game.currentPlayer == 1 {
		game.currentPlayer = 0
	} else {
		game.currentPlayer = 1
	}
}

func generateDiceResultMap() map[int]int64 {
	tmpDiceResultMap := make(map[int]int64)
	for a := 1; a < 4; a++ {
		for b := 1; b < 4; b++ {
			for c := 1; c < 4; c++ {
				tmpDiceResultMap[a+b+c] += 1
			}
		}
	}
	return tmpDiceResultMap
}

func part1(player1 player, player2 player, n int) (diceRolls int) {
	game := game{[2]player{player1, player2}, 0, -1, 1000}
	for {
		game.playOneRoung(n)
		reduceN(&n, &diceRolls)
		if game.winner != -1 {
			fmt.Println(min(game.players[0].score, game.players[1].score) * diceRolls)
			return
		}
	}

}

func reduceN(n *int, counter *int) {
	*n--
	if *n < 0 {
		*n = 9
	}
	*counter += 3
}

func increasePlayer(player *player, n int, winscore int) bool {
	(*player).position += n
	if (*player).position > 10 {
		(*player).position -= 10
	}
	(*player).score += (*player).position
	(*player).roundsPlayed++
	return (*player).score >= winscore
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}
