コード例 #1
0
        public static List <Player> RunDayOne(List <Player> players, int numReentries)
        {
            var dayOnePlayers = new List <Player>(players);
            var dayTwoPlayers = new List <Player>();
            var roundNumber   = 0;

            // need to avoid getting stuck with an odd player out
            // probably just fail them out
            while (dayOnePlayers.Count > 1)
            {
                // random match making until we know better
                Shuffle(dayOnePlayers);

                for (var index = 0; index < dayOnePlayers.Count - 1; index += 2)
                {
                    var playerOne = dayOnePlayers[index];
                    var playerTwo = dayOnePlayers[index + 1];
                    // yeah yeah yeah decimals aren't doubles blah blah blah
                    bool playerOneWins = EloCalculator.PredictResult(playerOne.Elo, playerTwo.Elo)[0] >= (decimal)rng.NextDouble();
                    if (playerOneWins)
                    {
                        playerOne.CurrentWins++;
                        playerOne.DayOneWins++;
                        playerTwo.CurrentLosses++;
                        playerTwo.DayOneLosses++;
                    }
                    else
                    {
                        playerTwo.CurrentWins++;
                        playerTwo.DayOneWins++;
                        playerOne.CurrentLosses++;
                        playerOne.DayOneLosses++;
                    }
                }

                for (var index = dayOnePlayers.Count - 1; index >= 0; index--)
                {
                    var player = dayOnePlayers[index];
                    if (player.CurrentLosses == 3)
                    {
                        player.GemsWon += Math.Max(0, 400 * (player.CurrentWins - 2));
                        if (player.Run <= numReentries)
                        {
                            // Re-enter the tournament
                            player.Run++;
                            player.CurrentWins   = 0;
                            player.CurrentLosses = 0;
                            player.GemsSpent    += 4000;
                        }
                        else
                        {
                            // you're out!
                            dayOnePlayers.RemoveAt(index);
                        }
                    }
                    else if (player.CurrentWins == 7) // shouldn't really need the else but if there's a bug it's less bad this way
                    {
                        dayTwoPlayers.Add(player);
                        dayOnePlayers.RemoveAt(index);
                    }
                }
                roundNumber++;
                Console.WriteLine("After round " + roundNumber + " of Day 1 - " + dayOnePlayers.Count +
                                  " remaining players, and " + dayTwoPlayers.Count + " day two players.");
            }
            return(dayTwoPlayers);
        }
コード例 #2
0
        static void Run(int numPlayers, int numReentries, double eloDistribution)
        {
            // This doesn't really matter but I picked from the same source as my default distribution
            // https://www.mtgcommunityreview.com/single-post/2018/06/12/Luck-Skill-and-Magic
            double eloMean = 1678.632;
            // I'm not actually going to adjust anyone's elo as they go - I'm using it as a representation of "true" skill
            var playerDistribution = new NormalDistribution(eloMean, eloDistribution);
            var players            = new List <Player>();

            for (var index = 0; index < numPlayers; index++)
            {
                var player = new Player();
                player.Elo       = (decimal)playerDistribution.Generate();
                player.GemsSpent = 4000;
                players.Add(player);
            }

            var dayTwoPlayers = RunDayOne(players, numReentries);

            foreach (var player in dayTwoPlayers)
            {
                player.CurrentWins   = 0;
                player.CurrentLosses = 0;
            }
            RunDayTwo(dayTwoPlayers);

            var dayOneAvgElo     = players.Average(p => p.Elo);
            var dayTwoAvgElo     = dayTwoPlayers.Average(p => p.Elo);
            var dayTwoWinPercent = EloCalculator.PredictResult(dayTwoAvgElo, (decimal)eloMean)[0] * 100;

            Console.WriteLine($"Day one average Elo: {dayOneAvgElo}.");
            Console.WriteLine($"Day two average Elo: {dayTwoAvgElo} ({dayTwoWinPercent,3:0.0}% win percent).");

            var numBuckets = 100;
            var bucketSize = numPlayers / numBuckets;

            if (numPlayers % numBuckets != 0)
            {
                Console.WriteLine("Warning - please use a multiple of " + numBuckets + " for more accurate top end performance");
            }

            var eloSorted = players.OrderBy(p => p.Elo).ToList();
            var skip      = 0;

            while (skip + bucketSize <= eloSorted.Count)
            {
                var nextBucket      = eloSorted.Skip(skip).Take(bucketSize).ToList();
                var minElo          = (int)nextBucket.Min(p => p.Elo);
                var maxElo          = (int)nextBucket.Max(p => p.Elo);
                var avgElo          = (int)nextBucket.Average(p => p.Elo);
                var avgGems         = nextBucket.Average(p => p.GemsWon - p.GemsSpent);
                var avgDayOneWins   = nextBucket.Average(p => p.DayOneWins);
                var avgDayOneLosses = nextBucket.Average(p => p.DayOneLosses);
                var avgDayTwoWins   = nextBucket.Average(p => p.DayTwoWins);
                var avgDayTwoLosses = nextBucket.Average(p => p.DayTwoLosses);
                var winPercentage   = EloCalculator.PredictResult(avgElo, (decimal)eloMean)[0] * 100;
                var bucketNumber    = skip / bucketSize + 1;

                Console.WriteLine($"{avgElo} ({minElo}-{maxElo}) ({winPercentage,3:0.0}% game win%, bucket #{bucketNumber}): {avgGems} gems, " +
                                  $"{avgDayOneWins,3:0.0}-{avgDayOneLosses,3:0.0} on day one, " +
                                  $"{avgDayTwoWins,3:0.0}-{avgDayTwoLosses,3:0.0} on day two.");
                skip += bucketSize;
            }
        }
コード例 #3
0
        public static void RunDayTwo(List <Player> players)
        {
            var dayTwoPlayers = new List <Player>(players);
            var roundNumber   = 0;

            while (dayTwoPlayers.Count > 1)
            {
                Shuffle(dayTwoPlayers);
                for (var index = 0; index < dayTwoPlayers.Count - 1; index += 2)
                {
                    var playerOne = dayTwoPlayers[index];
                    var playerTwo = dayTwoPlayers[index + 1];

                    var  playerOneGameWinChance  = EloCalculator.PredictResult(playerOne.Elo, playerTwo.Elo)[0];
                    var  playerOneMatchWinChance = playerOneGameWinChance * playerOneGameWinChance * (3 - 2 * playerOneGameWinChance);
                    bool playerOneWins           = playerOneMatchWinChance >= (decimal)rng.NextDouble();
                    if (playerOneWins)
                    {
                        playerOne.DayTwoWins++;
                        playerTwo.DayTwoLosses++;
                    }
                    else
                    {
                        playerTwo.DayTwoWins++;
                        playerOne.DayTwoLosses++;
                    }
                }

                for (var index = dayTwoPlayers.Count - 1; index >= 0; index--)
                {
                    var player = dayTwoPlayers[index];
                    if (player.DayTwoLosses == 2)
                    {
                        var gemsWon = 0;
                        switch (player.DayTwoWins)
                        {
                        case 1:
                        case 2:
                        case 3:
                            gemsWon = player.DayTwoWins * 2000;
                            break;

                        case 4:
                        case 5:
                            gemsWon = (player.DayTwoWins - 3) * 10000;
                            break;

                        case 6:
                            gemsWon = 200000;
                            break;
                        }
                        player.GemsWon += gemsWon;
                        dayTwoPlayers.RemoveAt(index);
                    }
                    else if (player.DayTwoWins == 7) // shouldn't really need the else but if there's a bug it's less bad this way
                    {
                        player.GemsWon += 400000;
                        dayTwoPlayers.RemoveAt(index);
                    }
                }
                roundNumber++;
                Console.WriteLine("After round " + roundNumber + " of Day 2 - " + dayTwoPlayers.Count +
                                  " remaining players.");
            }
        }