Skip to content

Commit 019d49b

Browse files
committed
Added rating change from day before.
1 parent 1935c1f commit 019d49b

File tree

13 files changed

+310
-65
lines changed

13 files changed

+310
-65
lines changed

game.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,16 @@ std::chrono::year_month_day Game::date() const
198198
return std::chrono::year_month_day{days};
199199
}
200200

201+
/*!
202+
*/
203+
std::chrono::sys_days Game::sysDate() const
204+
{
205+
using namespace std::chrono;
206+
auto date = this->date();
207+
208+
return sys_days{ year{ date.year() } / month{ date.month() } / day{ date.day() } };
209+
}
210+
201211
/*!
202212
*/
203213
/*

game.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ class Game
145145
//! Get the date from the game.
146146
std::chrono::year_month_day date() const;
147147

148+
//! Get the system date from the game.
149+
std::chrono::sys_days sysDate() const;
150+
148151
//! Get the exact timestamp of the game.
149152
//std::tuple<std::chrono::year_month_day, std::chrono::hh_mm_ss<std::chrono::seconds>> dateTime() const;
150153

logging.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ class Log
155155
return *this;
156156
}
157157

158+
//! Output formatted date.
158159
Log& operator<<(const std::chrono::year_month_day &date)
159160
{
160161
if (Log::_enabled)
@@ -174,6 +175,18 @@ class Log
174175
return *this;
175176
}
176177

178+
//! Output formatted date.
179+
Log& operator<<(const std::chrono::time_point<std::chrono::system_clock, std::chrono::days> &tp)
180+
{
181+
if (Log::_enabled)
182+
{
183+
std::chrono::sys_days sd = tp;
184+
std::chrono::year_month_day ymd{sd};
185+
*this << ymd;
186+
}
187+
return *this;
188+
}
189+
177190
//! The global log level.
178191
static Level _globalLogLevel;
179192

main.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -282,10 +282,10 @@ int main(int argc, char* argv[])
282282
std::chrono::milliseconds timestamp = std::chrono::milliseconds(static_cast<uint64_t>(game->timestamp() + game->duration()) * 1000);
283283
std::chrono::system_clock::time_point currentTimePoint = std::chrono::system_clock::time_point(timestamp);
284284

285-
// Days will be switches at UTC+5. So EST is the time zone for flipping days. The game time will still stay
285+
// Days will be switches at UTC+9. So AKST is the time zone for flipping days. The game time will still stay
286286
// UTC, but for historical ELO, peak rating, etc... the ELO is taken at this specific time. For the locally
287287
// generated ELO list it was supposed to be UTC+1, but was UTC-1 by accident.
288-
std::chrono::system_clock::time_point shiftedTime = currentTimePoint - std::chrono::hours(5);
288+
std::chrono::system_clock::time_point shiftedTime = currentTimePoint - std::chrono::hours(9);
289289
std::chrono::time_point<std::chrono::system_clock, std::chrono::days> date = floor<std::chrono::days>(shiftedTime);
290290

291291
Log::verbose() << "Shifted time of game " << game->id() << " from "
@@ -325,10 +325,17 @@ int main(int argc, char* argv[])
325325
} // for (Game *game : validGames)
326326

327327
// Process the last day.
328-
players.update();
329-
players.apply(lastDate, true, options.gameMode);
328+
if (options.allGames)
329+
{
330+
players.update();
331+
players.apply(lastDate, true, options.gameMode);
332+
currentDate = lastDate;
333+
}
334+
330335
players.finalize();
331336

337+
Log::info() << "Last day taken into account: " << currentDate;
338+
332339
if (!options.dryRun)
333340
{
334341
players.exportActivePlayers(options.outputDirectory, options.gameMode);
@@ -353,7 +360,7 @@ int main(int argc, char* argv[])
353360

354361
Log::info() << "Processed " << validGames.size() << " games. About to finalize stats.";
355362

356-
stats.finalize(options.outputDirectory, players);
363+
stats.finalize(options.outputDirectory, players, floor<std::chrono::days>(std::chrono::system_clock::now()) - std::chrono::days{1});
357364
stats.exportUpsets(options.outputDirectory, players);
358365
stats.exportLongestGames(options.outputDirectory, players);
359366
stats.exportBestTeams(options.outputDirectory, players);

mapstats.cpp

Lines changed: 108 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,12 @@ void MapStats::processGame(const Game &game, const Players &players)
6767
}
6868
}
6969

70-
std::chrono::year_month_day date{game.date().year(), game.date().month(), std::chrono::day{1}};
70+
std::chrono::year_month_day keyDate{game.date().year(), game.date().month(), std::chrono::day{1}};
71+
std::chrono::sys_days gameDate = game.sysDate();
7172

72-
_gameCountsPerMonthAndPlayer[date][mapName].count++;
73-
_gameCountsPerMonthAndPlayer[date][mapName].differentPlayers.insert(game.userId(0));
74-
_gameCountsPerMonthAndPlayer[date][mapName].differentPlayers.insert(game.userId(1));
73+
_gameCountsPerMonthAndPlayer[keyDate][mapName].count++;
74+
_gameCountsPerMonthAndPlayer[keyDate][mapName].differentPlayers.insert(game.userId(0));
75+
_gameCountsPerMonthAndPlayer[keyDate][mapName].differentPlayers.insert(game.userId(1));
7576

7677
// Ignore games with duration 0. These are probably manually added game, e.g. tournament games.
7778
if (game.duration() > 0)
@@ -136,14 +137,19 @@ void MapStats::processGame(const Game &game, const Players &players)
136137
std::vector<int> loserELOs = losersELOs(game);
137138

138139
Upset upset{ game.date(), winnerIds, loserIds, mapName, winnerFactions, loserFactions, winnerELOs, loserELOs, diff };
139-
_upsetsMonthly[date].insert(upset);
140-
if (_upsetsMonthly[date].size() > 20)
140+
_upsetsMonthly[keyDate].insert(upset);
141+
if (_upsetsMonthly[keyDate].size() > 20)
141142
{
142-
_upsetsMonthly[date].erase(std::prev(_upsetsMonthly[date].end()));
143+
_upsetsMonthly[keyDate].erase(std::prev(_upsetsMonthly[keyDate].end()));
143144
}
144145

145-
auto yearBoundary = floor<std::chrono::days>(std::chrono::system_clock::now()) - std::chrono::days(365);
146-
if (date >= yearBoundary)
146+
std::chrono::time_point<std::chrono::system_clock, std::chrono::days> today
147+
= std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now());
148+
149+
std::chrono::time_point<std::chrono::system_clock, std::chrono::days> yearBoundary
150+
= today - std::chrono::days(365);
151+
152+
if (gameDate >= yearBoundary)
147153
{
148154
_upsetsLast12Month.insert(upset);
149155
}
@@ -152,8 +158,11 @@ void MapStats::processGame(const Game &game, const Players &players)
152158
_upsetsLast12Month.erase(std::prev(_upsetsLast12Month.end()));
153159
}
154160

155-
auto monthBoundary = floor<std::chrono::days>(std::chrono::system_clock::now()) - std::chrono::days(31);
156-
if (date >= monthBoundary)
161+
std::chrono::time_point<std::chrono::system_clock, std::chrono::days> monthBoundary
162+
= today - std::chrono::days(31);
163+
164+
165+
if (gameDate >= monthBoundary)
157166
{
158167
_upsetsLast30Days.insert(upset);
159168
}
@@ -195,18 +204,21 @@ void MapStats::processGame(const Game &game, const Players &players)
195204
Probabilities &probsWinners = _teamStats[winnerTeamId];
196205
Probabilities &probsLosers = _teamStats[loserTeamId];
197206

198-
_lastTeamELOs[winnerTeamId].first = (winners[0].userId < winners[1].userId) ? winners[1].elo : winners[0].elo;
199-
_lastTeamELOs[winnerTeamId].second = (winners[1].userId > winners[0].userId) ? winners[0].elo : winners[1].elo;
200-
_lastTeamELOs[loserTeamId].first = (losers[0].userId < losers[1].userId) ? losers[1].elo : losers[0].elo;
201-
_lastTeamELOs[loserTeamId].second = (losers[1].userId > losers[0].userId) ? losers[0].elo : losers[1].elo;
207+
double winnerFirstElo = (winners[0].userId < winners[1].userId) ? winners[1].elo : winners[0].elo;
208+
double winnerSecondElo = (winners[1].userId > winners[0].userId) ? winners[0].elo : winners[1].elo;
209+
_lastTeamELOs[winnerTeamId].push_back({winnerFirstElo, winnerSecondElo});
210+
211+
double loserFirstElo = (losers[0].userId < losers[1].userId) ? losers[1].elo : losers[0].elo;
212+
double loserSecondElo = (losers[1].userId > losers[0].userId) ? losers[0].elo : losers[1].elo;
213+
_lastTeamELOs[loserTeamId].push_back({loserFirstElo, loserSecondElo});
202214

203215
Rating winnerRating(winners[0].elo + winners[1].elo, winners[0].deviation + winners[1].deviation, glicko::initialVolatility);
204216
Rating losersRating(losers[0].elo + losers[1].elo, losers[0].deviation + losers[1].deviation, glicko::initialVolatility);
205217

206218
double expectedWinRate = winnerRating.e_star(losersRating.toArray(), 0.0);
207219

208-
probsWinners.addGame(expectedWinRate, 1);
209-
probsLosers.addGame(1.0 - expectedWinRate, 0);
220+
probsWinners.addGame(expectedWinRate, game.sysDate(), 1);
221+
probsLosers.addGame(1.0 - expectedWinRate, game.sysDate(), 0);
210222
}
211223

212224
// Process longest games.
@@ -270,7 +282,7 @@ void MapStats::processGame(const Game &game, const Players &players)
270282
return;
271283
}
272284

273-
_mapStats[factionSetup][mapName].addGame(expectedWinRate, (game.winnerIndex() == static_cast<int>(alliedPlayerIndex)));
285+
_mapStats[factionSetup][mapName].addGame(expectedWinRate, game.sysDate(), (game.winnerIndex() == static_cast<int>(alliedPlayerIndex)));
274286
}
275287
else if (factionSetup == factions::AvY)
276288
{
@@ -291,7 +303,7 @@ void MapStats::processGame(const Game &game, const Players &players)
291303
return;
292304
}
293305

294-
_mapStats[factionSetup][mapName].addGame(expectedWinRate, (game.winnerIndex() == static_cast<int>(alliedPlayerIndex)));
306+
_mapStats[factionSetup][mapName].addGame(expectedWinRate, game.sysDate(), (game.winnerIndex() == static_cast<int>(alliedPlayerIndex)));
295307
}
296308
else if (factionSetup == factions::YvS)
297309
{
@@ -312,34 +324,51 @@ void MapStats::processGame(const Game &game, const Players &players)
312324
return;
313325
}
314326

315-
_mapStats[factionSetup][mapName].addGame(expectedWinRate, (game.winnerIndex() == static_cast<int>(yuriPlayerIndex)));
327+
_mapStats[factionSetup][mapName].addGame(expectedWinRate, game.sysDate(), (game.winnerIndex() == static_cast<int>(yuriPlayerIndex)));
316328
}
317-
}
329+
330+
} // void MapStats::processGame(const Game &game, const Players &players)
318331

319332
/*!
320333
*/
321-
void MapStats::finalize(const std::filesystem::path &directory, const Players &players)
334+
void MapStats::finalize(const std::filesystem::path &directory, const Players &players, std::chrono::sys_days date)
322335
{
323336
Log::info() << "Finalizing map statistics.";
324337

325338
using json = nlohmann::json;
326339

327340
static std::vector<factions::Setup> factionSetups = { factions::AvS, factions::AvY, factions::YvS };
328341

342+
Log::info() << "Creating team stats.";
343+
329344
for (std::map<uint64_t, Probabilities>::iterator it = _teamStats.begin(); it != _teamStats.end(); ++it)
330345
{
331346
uint64_t key = it->first;
332347
Probabilities &value = it->second;
333348
value.finalize();
349+
ProbResult probToday = value.result(date);
350+
ProbResult probYesterday = value.result(date - std::chrono::days{3});
334351
uint32_t player1 = static_cast<uint32_t>(key & 0xFFFFFFFF);
335352
uint32_t player2 = static_cast<uint32_t>(key >> 32);
336353

337-
// Exclude teams where no player has ELO > 1400.
338-
if (value.count() > 20 && players[player1].isActive() && players[player2].isActive() && value.wins() > 1 &&
339-
value.count() != value.wins() &&
340-
(players[player1].elo(factions::Combined) > 1400 || players[player2].elo(factions::Combined) > 1400))
354+
auto eloDiff = [](const ProbResult &result) -> double {
355+
return -400.0 * std::log10((1.0 / result.normalized) - 1.0);
356+
};
357+
// Exclude teams where no player has ELO > 1300.
358+
if (probToday.games >= 20 && players[player1].isActive() && players[player2].isActive() && probToday.wins > 1 &&
359+
probToday.games != probToday.wins &&
360+
(players[player1].elo(factions::Combined) > 1300 || players[player2].elo(factions::Combined) > 1300))
361+
{
362+
Log::info() << players[player1].alias() << " + " << players[player2].alias() << " " << probToday.games << "/" << probToday.wins << " " << probToday.actual << "/" << probToday.expected;
363+
_teams.insert({key, probToday.games, probToday.wins, players[player1].elo(factions::Combined) + players[player2].elo(factions::Combined), eloDiff(probToday), probToday.lastGame });
364+
}
365+
366+
if (probYesterday.games >= 20 && players[player1].isActive() && players[player2].isActive() && probYesterday.wins > 1 &&
367+
probYesterday.games != probYesterday.wins &&
368+
(players[player1].elo(factions::Combined) > 1300 || players[player2].elo(factions::Combined) > 1300))
341369
{
342-
_teams.insert({key, value.count(), value.wins(), players[player1].elo(factions::Combined) + players[player2].elo(factions::Combined), value.eloDifference() });
370+
Log::info() << players[player1].alias() << " + " << players[player2].alias() << " " << probYesterday.games << "/" << probYesterday.wins << " " << probYesterday.actual << "/" << probYesterday.expected;
371+
_yesterdaysTeams.insert({key, probYesterday.games, probYesterday.wins, players[player1].elo(factions::Combined) + players[player2].elo(factions::Combined), eloDiff(probYesterday), probYesterday.lastGame });
343372
}
344373
}
345374

@@ -655,6 +684,12 @@ void MapStats::exportLongestGames(const std::filesystem::path &directory, const
655684

656685
for (auto it = _longestGames.begin(); it != _longestGames.end(); ++it)
657686
{
687+
if (it->winners.empty() || it->losers.empty())
688+
{
689+
Log::error() << "No winners or losers while exporting longest game.";
690+
continue;
691+
}
692+
658693
json jLongestGame = json::object();
659694
jLongestGame["rank"] = rank++;
660695
jLongestGame["date"] = stringtools::fromDate(it->date);
@@ -673,6 +708,8 @@ void MapStats::exportLongestGames(const std::filesystem::path &directory, const
673708
std::ofstream streamLongest(directory / (gamemodes::shortName(_gameMode) + "_longest_games.json"));
674709
streamLongest << std::setw(4) << jLongestGames << std::endl;
675710
streamLongest.close();
711+
712+
Log::verbose() << "Exported longest games.";
676713
}
677714

678715
/*!
@@ -683,14 +720,18 @@ void MapStats::exportBestTeams(const std::filesystem::path &directory, const Pla
683720

684721
json data = json::object();
685722

686-
data["description"] = "Top 20 teams with the highest performance above predicted ELO";
723+
data["description"] = "Top 40 teams with the highest performance above predicted ELO";
687724
data["columns"] = json::array({
688725
{ { "index", 0 }, { "header", "#" } , { "name", "rank" } },
689-
{ { "index", 1 }, { "header", "Names" } , { "name", "names" } },
690-
{ { "index", 2 }, { "header", "Games" } , { "name", "games" } },
691-
{ { "index", 3 }, { "header", "Team ELO" } , { "name", "elo_team" } },
692-
{ { "index", 4 }, { "header", "Performance" } , { "name", "performance" } },
693-
{ { "index", 5 }, { "header", "Difference" } , { "name", "diff" }, { "info", "Performance above team ELO."} }
726+
{ { "index", 1 }, { "header", "∆ #" } , { "name", "delta_rank" } },
727+
{ { "index", 2 }, { "header", "Names" } , { "name", "names" } },
728+
{ { "index", 3 }, { "header", "Games" } , { "name", "games" } },
729+
{ { "index", 4 }, { "header", "∆ Games" } , { "name", "delta_gamesplayed" } },
730+
{ { "index", 5 }, { "header", "Last game" } , { "name", "last_game" } },
731+
{ { "index", 6 }, { "header", "Team ELO" } , { "name", "elo_team" } },
732+
{ { "index", 7 }, { "header", "Performance" } , { "name", "performance" } },
733+
{ { "index", 8 }, { "header", "Difference" } , { "name", "diff" }, { "info", "Performance above team ELO."} },
734+
{ { "index", 9 }, { "header", "" } , { "name", "delta_diff" }, { "info", "Performance above team ELO change since the day before."} }
694735
});
695736

696737
int rank = 1;
@@ -701,8 +742,10 @@ void MapStats::exportBestTeams(const std::filesystem::path &directory, const Pla
701742
{
702743
json jTeam = json::object();
703744
jTeam["rank"] = rank++;
704-
uint32_t elo1 = static_cast<uint32_t>(std::round(_lastTeamELOs[team.teamId].first));
705-
uint32_t elo2 = static_cast<uint32_t>(std::round(_lastTeamELOs[team.teamId].second));
745+
jTeam["last_game"] = stringtools::fromDate(team.lastGame);
746+
747+
uint32_t elo1 = static_cast<uint32_t>(std::round(_lastTeamELOs[team.teamId][team.games - 1].first));
748+
uint32_t elo2 = static_cast<uint32_t>(std::round(_lastTeamELOs[team.teamId][team.games - 1].second));
706749

707750
std::string player1 = players[team.player1()].alias() + " (" + std::to_string(elo1) + ")";
708751
std::string player2 = players[team.player2()].alias() + " (" + std::to_string(elo2) + ")";
@@ -711,9 +754,31 @@ void MapStats::exportBestTeams(const std::filesystem::path &directory, const Pla
711754
jTeam["games"] = std::to_string(team.games);
712755
jTeam["performance"] = std::to_string(elo1 + elo2 + static_cast<uint32_t>(std::round(team.eloDifference)));
713756
jTeam["diff"] = std::to_string(static_cast<uint32_t>(std::round(team.eloDifference)));
757+
758+
int deltaRank = 0;
759+
int deltaGames = 0;
760+
int deltaDiff = 0;
761+
int currentRank = 0;
762+
for (const Team &yesterdayTeam : _yesterdaysTeams)
763+
{
764+
currentRank++;
765+
if (yesterdayTeam.teamId == team.teamId)
766+
{
767+
deltaRank = currentRank - (rank - 1);
768+
deltaGames = team.games - yesterdayTeam.games;
769+
deltaDiff = team.eloDifference - yesterdayTeam.eloDifference;
770+
break;
771+
}
772+
}
773+
774+
775+
jTeam["delta_rank"] = deltaRank;
776+
jTeam["delta_gamesplayed"] = deltaGames;
777+
jTeam["delta_diff"] = deltaDiff;
778+
714779
jTeams.push_back(jTeam);
715780

716-
if (rank == 21)
781+
if (rank == 31)
717782
break;
718783
}
719784

@@ -726,6 +791,8 @@ void MapStats::exportBestTeams(const std::filesystem::path &directory, const Pla
726791
stream << std::setw(4) << data << std::endl;
727792
stream.close();
728793
}
794+
795+
Log::verbose() << "Exported best teams.";
729796
}
730797

731798

@@ -746,8 +813,13 @@ void MapStats::exportUpsets(const std::filesystem::path &directory, const Player
746813
}
747814

748815
exportUpsets(directory, _upsetsLast12Month, gamemodes::shortName(_gameMode) + "_upsets_last12month.json", "Upsets within the last 12 month", players);
816+
Log::verbose() << "Exported biggest upsets of the last 12 month.";
817+
749818
exportUpsets(directory, _upsetsLast30Days, gamemodes::shortName(_gameMode) + "_upsets_last30days.json", "Upsets within the last 30 days", players);
819+
Log::verbose() << "Exported biggest upsets of the last 30 days.";
820+
750821
exportUpsets(directory, _upsetsAllTime, gamemodes::shortName(_gameMode) + "_upsets_alltime.json", "Biggest upsets of all time", players);
822+
Log::verbose() << "Exported biggest upsets of all time..";
751823
}
752824

753825
/*!

0 commit comments

Comments
 (0)