예제 #1
0
        private void Worker_DoWork(object sender, DoWorkEventArgs e)
        {
            List <Action>           games   = new List <Action>();
            List <TournamentResult> results = new List <TournamentResult>();

            int completedGames = 0;

            foreach (var engine1 in _players)
            {
                foreach (var engine2 in _players)
                {
                    if (engine1 != engine2 || _allowSelfPlay)
                    {
                        games.Add(() =>
                        {
                            Stopwatch killswitch = Stopwatch.StartNew();
                            VolcanoGame game     = new VolcanoGame();

                            VictoryType victory = VictoryType.None;
                            game.OnGameOver    += (p, v) => victory = v;

                            try
                            {
                                game.RegisterEngine(Player.One, _engines.GetEngine(engine1));
                                game.RegisterEngine(Player.Two, _engines.GetEngine(engine2));
                                game.SecondsPerEngineMove = _secondsPerMove;
                                game.StartNewGame();
                                game.ComputerPlay();

                                while (victory == VictoryType.None && game.CurrentState.Winner == Player.Empty && game.CurrentState.Turn < VolcanoGame.Settings.TournamentAdjudicateMaxTurns && killswitch.ElapsedMilliseconds < VolcanoGame.Settings.TournamentAdjudicateMaxSeconds * 1000)
                                {
                                    System.Threading.Thread.Sleep(100);
                                }

                                var termination = TournamentTerminationType.Normal;
                                if (game.CurrentState.Winner == Player.Empty)
                                {
                                    if (game.CurrentState.Turn >= VolcanoGame.Settings.TournamentAdjudicateMaxTurns)
                                    {
                                        termination = TournamentTerminationType.AdjudicateMoves;
                                    }
                                    else if (killswitch.ElapsedMilliseconds >= VolcanoGame.Settings.TournamentAdjudicateMaxSeconds * 1000)
                                    {
                                        termination = TournamentTerminationType.AdjudicateTime;
                                    }
                                }
                                if (victory == VictoryType.ArenaAdjudication)
                                {
                                    if (game.BackgroundError != null)
                                    {
                                        if (game.CurrentState.Winner == Player.One)
                                        {
                                            termination = TournamentTerminationType.PlayerTwoError;
                                        }
                                        else if (game.CurrentState.Winner == Player.Two)
                                        {
                                            termination = TournamentTerminationType.PlayerOneError;
                                        }
                                        else
                                        {
                                            termination = TournamentTerminationType.Error;
                                        }
                                    }
                                    else
                                    {
                                        termination = TournamentTerminationType.IllegalMove;
                                    }
                                }

                                lock (results)
                                {
                                    results.Add(new TournamentResult(game, engine1, engine2, termination, killswitch.ElapsedMilliseconds));
                                }
                            }
                            catch (Exception ex)
                            {
                                using (StreamWriter w = new StreamWriter("errors.txt", true))
                                {
                                    w.WriteLine("Failed to play \"" + engine1 + "\" and \"" + engine2 + "\"! :: " + ex.Message);
                                }

                                try
                                {
                                    var termination = game?.CurrentState?.Player == Player.One ? TournamentTerminationType.PlayerOneError : TournamentTerminationType.PlayerTwoError;

                                    lock (results)
                                    {
                                        results.Add(new TournamentResult(game, engine1, engine2, termination, killswitch.ElapsedMilliseconds));
                                    }
                                }
                                catch (Exception eotw)
                                {
                                    using (StreamWriter w2 = new StreamWriter("errors.txt", true))
                                    {
                                        w2.WriteLine("Failed to log result! :: " + eotw.Message);
                                    }
                                }
                            }

                            completedGames++;
                            worker.ReportProgress(0, new TournamentStatus(completedGames, totalGames));
                        });
                    }
                }
            }

            for (int r = 0; r < _rounds; r++)
            {
                Parallel.ForEach(games, x => x());
            }

            using (StreamWriter w = new StreamWriter(_gameDataFile))
            {
                w.WriteLine("Player_One,Player_Two,Winner,Termination,Total_Moves,Total_Milliseconds,Starting_Tile_Index,Transcript,Winning_Path,Win_Condition,Seconds_Per_Move");
                foreach (var result in results)
                {
                    string gameResult = "Draw";
                    if (result.PlayerOneScore > result.PlayerTwoScore)
                    {
                        gameResult = "One";
                    }
                    if (result.PlayerTwoScore > result.PlayerOneScore)
                    {
                        gameResult = "Two";
                    }

                    string transcript = "";
                    if (result.Moves.Count > 0)
                    {
                        try
                        {
                            transcript = result.Moves.Select(x => x.Tile + (VolcanoGame.Settings.IndicateTranscriptMoveType && x.Addition ? "+" : "")).Aggregate((c, n) => c + " " + n);
                        }
                        catch (Exception ex)
                        {
                            transcript = ex.Message;
                        }
                    }

                    string winningPath = "";
                    if (result.WinningPath != null && result.WinningPath.Count > 0)
                    {
                        try
                        {
                            winningPath = result.WinningPath.Select(x => Constants.TileNames[x]).Aggregate((c, n) => c + " " + n);
                        }
                        catch (Exception ex)
                        {
                            winningPath = ex.Message;
                        }
                    }

                    string winCondition = "";
                    if (result.WinCondition == 1)
                    {
                        winCondition = "Tie-breaker";
                    }
                    else
                    {
                        winCondition = "Normal Win (no tie-breaker)";
                    }

                    w.WriteLine(result.PlayerOne + "," + result.PlayerTwo + "," + gameResult + "," + result.Termination.ToString() + "," + result.TotalMoves + "," + result.ElapsedMilliseconds + "," + result.FirstTile + "," + transcript + "," + winningPath + "," + winCondition + "," + _secondsPerMove);
                }
            }

            List <TournamentResultLine> lines = new List <TournamentResultLine>();

            foreach (var engine1 in _players)
            {
                decimal score             = 0m;
                TournamentResultLine line = new TournamentResultLine();
                line.Name = engine1;
                foreach (var engine2 in _players)
                {
                    if (engine1 != engine2 || _allowSelfPlay)
                    {
                        decimal wins = results.Where(x => x.PlayerOne == engine1 && x.PlayerTwo == engine2).Sum(x => x.PlayerOneScore) + results.Where(x => x.PlayerOne == engine2 && x.PlayerTwo == engine1).Sum(x => x.PlayerTwoScore);
                        score += wins;
                        line.Data.Add(engine2, wins);
                    }
                    else
                    {
                        line.Data.Add(engine2, -1);
                    }
                }
                decimal total = results.Where(x => x.PlayerOne == engine1 || x.PlayerTwo == engine1).Count();
                line.TotalScore      = score;
                line.TotalPercentage = score * 100m / total;
                line.Score           = score;
                lines.Add(line);
            }

            lines.Sort((c, n) => n.Sort.CompareTo(c.Sort));

            List <string> names = new List <string>();

            for (int i = 0; i < lines.Count; i++)
            {
                lines[i].CrossTableName = (i + 1) + ". " + lines[i].Name;
                names.Add((i + 1).ToString());

                lines[i].NeustadtlScore = 0m;
                foreach (var opponent in lines)
                {
                    if (opponent.Name != lines[i].Name)
                    {
                        lines[i].NeustadtlScore += opponent.TotalScore * lines[i].Data[opponent.Name];
                    }
                }
            }

            // It doesn't make sense to save a cross table when there's only one person competing
            if (!string.IsNullOrEmpty(_crossTableFile) && lines.Count > 1)
            {
                using (StreamWriter w = new StreamWriter(_crossTableFile))
                {
                    // cs = common score
                    // ns = neustadtl score (figures in strength of opposition)
                    w.WriteLine("," + names.Aggregate((c, n) => c + "," + n) + ",cs,ns");
                    foreach (var player in lines)
                    {
                        w.Write(player.CrossTableName);
                        foreach (var opponent in lines)
                        {
                            string val = player.Data[opponent.Name] >= 0 ? player.Data[opponent.Name].ToString() : "";
                            w.Write("," + val);
                        }
                        w.Write(", " + player.TotalScore);
                        w.Write(", " + player.NeustadtlScore.ToString("0.00"));
                        w.WriteLine();
                    }
                }
            }
        }
예제 #2
0
        private void Worker_DoWork(object sender, DoWorkEventArgs e)
        {
            results = new List <TournamentResult>();

            completedGames = 0;
            timeouts       = 0;

            if (_tournamentType == TournamentType.RoundRobin)
            {
                games = new List <Action>();

                foreach (var engine1 in _players)
                {
                    foreach (var engine2 in _players)
                    {
                        if (engine1 != engine2 || _allowSelfPlay)
                        {
                            QueueGame(engine1, engine2);
                        }
                    }
                }

                for (int r = 0; r < _rounds; r++)
                {
                    Parallel.ForEach(games, x => x());
                }
            }
            else if (_tournamentType == TournamentType.Swiss)
            {
                var rand = new Random();

                var swissPlayers = _players.Select(x => new SwissPlayer
                {
                    Engine = x,
                    Score  = 0
                }).ToList();

                for (int r = 0; r < _rounds; r++)
                {
                    swissPlayers = swissPlayers.OrderByDescending(x => x.Score).ThenBy(x => rand.Next()).ToList();

                    games = new List <Action>();

                    // If there's an odd number of players, the last player doesn't play
                    for (int i = 0; i < ((swissPlayers.Count % 2 == 1) ? swissPlayers.Count - 1 : swissPlayers.Count); i += 2)
                    {
                        // Play both colors
                        QueueGame(swissPlayers[i].Engine, swissPlayers[i + 1].Engine);
                        QueueGame(swissPlayers[i + 1].Engine, swissPlayers[i].Engine);
                    }

                    Parallel.ForEach(games, x => x());

                    // Update scores for next round
                    for (int i = 0; i < ((swissPlayers.Count % 2 == 1) ? swissPlayers.Count - 1 : swissPlayers.Count); i++)
                    {
                        swissPlayers[i].Score  = results.Where(x => x.PlayerOne == swissPlayers[i].Engine).Sum(x => x.PlayerOneScore);
                        swissPlayers[i].Score += results.Where(x => x.PlayerTwo == swissPlayers[i].Engine).Sum(x => x.PlayerTwoScore);
                    }

                    // If someone didn't play, they get a half point bye (per game) for the sake of pairings
                    if (swissPlayers.Count % 2 == 1)
                    {
                        swissPlayers[swissPlayers.Count - 1].Score++;
                    }
                }
            }

            using (StreamWriter w = new StreamWriter(_gameDataFile))
            {
                w.WriteLine("Player One,Player Two,Winner,Termination,Total Moves,Total Milliseconds,Starting Tile Index,Transcript,Winning Path One,Winning Path Two");
                foreach (var result in results)
                {
                    string gameResult = "Draw";
                    if (result.PlayerOneScore > result.PlayerTwoScore)
                    {
                        gameResult = "One";
                    }
                    if (result.PlayerTwoScore > result.PlayerOneScore)
                    {
                        gameResult = "Two";
                    }

                    string transcript = "";
                    if (result.Moves.Count > 0)
                    {
                        try
                        {
                            transcript = result.Moves.Select(x => x.Tile + (VolcanoGame.Settings.IndicateTranscriptMoveType && x.Addition ? "+" : "")).Aggregate((c, n) => c + " " + n);
                        }
                        catch (Exception ex)
                        {
                            transcript = ex.Message;
                        }
                    }

                    string winningPathOne = GetWinningPath(result.WinningPathOne);
                    string winningPathTwo = GetWinningPath(result.WinningPathTwo);

                    w.WriteLine(result.PlayerOne + "," + result.PlayerTwo + "," + gameResult + "," + result.Termination.ToString() + "," + result.TotalMoves + "," + result.ElapsedMilliseconds + "," + result.FirstTile + "," + transcript + "," + winningPathOne + "," + winningPathTwo);
                }
            }

            List <TournamentResultLine> lines = new List <TournamentResultLine>();

            foreach (var engine1 in _players)
            {
                decimal score             = 0m;
                TournamentResultLine line = new TournamentResultLine();
                line.Name = engine1;
                foreach (var engine2 in _players)
                {
                    if (engine1 != engine2 || _allowSelfPlay)
                    {
                        decimal wins = results.Where(x => x.PlayerOne == engine1 && x.PlayerTwo == engine2).Sum(x => x.PlayerOneScore) + results.Where(x => x.PlayerOne == engine2 && x.PlayerTwo == engine1).Sum(x => x.PlayerTwoScore);
                        score += wins;
                        line.Data.Add(engine2, wins);
                    }
                    else
                    {
                        line.Data.Add(engine2, -1);
                    }
                }
                decimal total = results.Where(x => x.PlayerOne == engine1 || x.PlayerTwo == engine1).Count();
                line.TotalScore      = score;
                line.TotalPercentage = score * 100m / total;
                line.Score           = score;
                lines.Add(line);
            }

            lines.Sort((c, n) => n.Sort.CompareTo(c.Sort));

            List <string> names = new List <string>();

            for (int i = 0; i < lines.Count; i++)
            {
                lines[i].CrossTableName = (i + 1) + ". " + lines[i].Name;
                names.Add((i + 1).ToString());

                lines[i].NeustadtlScore = 0m;
                foreach (var opponent in lines)
                {
                    if (opponent.Name != lines[i].Name)
                    {
                        lines[i].NeustadtlScore += opponent.TotalScore * lines[i].Data[opponent.Name];
                    }
                }
            }

            // It doesn't make sense to save a cross table when there's only one person competing
            if (!string.IsNullOrEmpty(_crossTableFile) && lines.Count > 1)
            {
                using (StreamWriter w = new StreamWriter(_crossTableFile))
                {
                    // cs = common score
                    // ns = neustadtl score (figures in strength of opposition)
                    w.WriteLine("," + names.Aggregate((c, n) => c + "," + n) + ",cs,ns");
                    foreach (var player in lines)
                    {
                        w.Write(player.CrossTableName);
                        foreach (var opponent in lines)
                        {
                            string val = player.Data[opponent.Name] >= 0 ? player.Data[opponent.Name].ToString() : "";
                            w.Write("," + val);
                        }
                        w.Write(", " + player.TotalScore);
                        w.Write(", " + player.NeustadtlScore.ToString("0.00"));
                        w.WriteLine();
                    }
                }
            }
        }