private async Task RunOneGame(OneRoundTempData round) { await round.Semaphore.WaitAsync(); int[] teams; int gameId = -1; try { teams = round.SelectPlayers(simulator.NumPlayers); { await using var cmd = new NpgsqlCommand("insert into Game (round, teams, start_time) VALUES (@round, @teams, @starttime) RETURNING id", conn); cmd.Parameters.AddWithValue("round", round.Round); cmd.Parameters.AddWithValue("teams", NpgsqlTypes.NpgsqlDbType.Array | NpgsqlTypes.NpgsqlDbType.Integer, teams); Int64 unixTimestamp = (Int64)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalMilliseconds; cmd.Parameters.AddWithValue("starttime", unixTimestamp); gameId = (int)await cmd.ExecuteScalarAsync(); } } finally { round.Semaphore.Release(); } Console.WriteLine("Simulating game between " + String.Join(", ", teams)); GameLaunchParams launch = new GameLaunchParams(); launch.Practice = false; foreach (int team in teams) { launch.Teams.Add(new TeamData { Id = team, BinaryPath = round.Teams[team].BinaryPath }); } var result = await simulator.Launch(launch); double[] eloDeltas = Elo.ComputeEloDelta(teams.Select(t => round.Teams[t].StartingElo).ToArray(), result.Points.ToArray(), round.EloKFactor); await round.Semaphore.WaitAsync(); try { round.UpdateRatings(teams, eloDeltas, gameId, false); { await using var cmd = new NpgsqlCommand( "update Game set end_time = @endtime, scores = @scores, result_path = @resultpath, " + "elo_deltas = @elodeltas where id = @id", conn); Int64 unixTimestamp = (Int64)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalMilliseconds; cmd.Parameters.AddWithValue("endtime", unixTimestamp); cmd.Parameters.AddWithValue("scores", NpgsqlTypes.NpgsqlDbType.Array | NpgsqlTypes.NpgsqlDbType.Double, result.Points.ToArray()); cmd.Parameters.AddWithValue("elodeltas", NpgsqlTypes.NpgsqlDbType.Array | NpgsqlTypes.NpgsqlDbType.Double, eloDeltas); cmd.Parameters.AddWithValue("id", gameId); cmd.Parameters.AddWithValue("resultpath", result.ResultPath); await cmd.ExecuteNonQueryAsync(); } } finally { round.Semaphore.Release(); } }
private async Task RunRoundLoop(OneRoundTempData round) { Console.WriteLine($"Simulating tournament round with {round.Teams.Count} teams with {numThreads} threads."); Task[] tasks = new Task[numThreads]; for (int i = 0; i < tasks.Length; i++) { tasks[i] = Task.CompletedTask; } // Parallelization. while (round.NumGames < round.Teams.Count * round.DesiredNumGamesPerTeam / 2) { var completed = await Task.WhenAny(tasks); tasks[Array.IndexOf(tasks, completed)] = RunOneGame(round); round.NumGames++; } await Task.WhenAll(tasks); await FinishRound(); }
private async Task <OneRoundTempData> RecoverRoundData() { var result = new OneRoundTempData(); var activeRound = await GetCurrentActiveRound(); if (!activeRound.HasValue) { throw new Exception("Attempting to simulate non-active round."); } var(round, numGamesPerTeam, maxTeams, eloKFactor) = activeRound.Value; result.Round = round; result.DesiredNumGamesPerTeam = numGamesPerTeam; result.MaxTeams = maxTeams; result.EloKFactor = eloKFactor; // Read the snapshot binary path and teams of the current round. { await using var cmd = new NpgsqlCommand("select team, binary_path from Round where round = @round", conn); cmd.Parameters.AddWithValue("round", result.Round); await using var reader = await cmd.ExecuteReaderAsync(); while (await reader.ReadAsync()) { int team = reader.GetInt32(0); string binaryPath = reader.GetString(1); result.Teams[team] = new OneTeamTempData { Id = team, BinaryPath = binaryPath, StartingElo = 1500, PendingElo = 1500, }; } } // Read elo from previous round. { await using var cmd = new NpgsqlCommand("select team, elo from Round where round = @round", conn); cmd.Parameters.AddWithValue("round", result.Round - 1); await using var reader = await cmd.ExecuteReaderAsync(); while (await reader.ReadAsync()) { int team = reader.GetInt32(0); double elo = reader.GetDouble(1); if (result.Teams.ContainsKey(team)) { result.Teams[team].StartingElo = elo; result.Teams[team].PendingElo = elo; } } } // Recover previous games { await using var cmd = new NpgsqlCommand("select teams, id, elo_deltas from Game where round = @round and end_time != 0 ORDER BY id ASC", conn); cmd.Parameters.AddWithValue("round", result.Round); await using var reader = await cmd.ExecuteReaderAsync(); while (await reader.ReadAsync()) { var teams = (int[])reader.GetValue(0); var gameId = reader.GetInt32(1); var eloDeltas = (double[])reader.GetValue(2); result.UpdateRatings(teams, eloDeltas, gameId, true); result.NumGames++; } } return(result); }