Fix/update ranking computation

This commit is contained in:
Alayan-stk-2 2018-05-15 18:47:59 +02:00 committed by GitHub
parent 8da8390773
commit b026b24e4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 71 additions and 41 deletions

View File

@ -775,34 +775,43 @@ void ServerLobby::checkRaceFinished()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Compute the new player's rankings in ranked servers /** Compute the new player's rankings in ranked servers
* //FIXME : this function assumes that m_rankings,
* m_num_ranked_races and m_max_ranking
* are correctly filled before
* It also assumes that the data stored by them
* is written back to the main list after the GP
*/ */
void ServerLobby::computeNewRankings() void ServerLobby::computeNewRankings()
{ {
//TODO : this is overall a rather naive implementation auto players = m_game_setup->getConnectedPlayers(true/*same_index_for_disconnected*/);
// several possibilities to speed up the computation exist,
// though this is minor in importance as it's not done
// during racing.
//TODO : make some numerical parts of the formulas assert (m_rankings.size() == players.size() &&
// depend of a single constant value m_num_ranked_races.size() == players.size() &&
m_max_ranking.size() == players.size() );
// No ranking yet for battle mode // No ranking yet for battle mode
// TODO : separate rankings for time-trial and normal and FTL ?? // TODO : separate rankings for time-trial and normal and FTL ??
if (!race_manager->modeHasLaps()) if (!race_manager->modeHasLaps())
return; return;
auto& players = m_game_setup->getPlayers(); // Using a vector of vector, it would be possible to fill
// all j < i v[i][j] with -v[j][i]
// Would this be worth it ?
std::vector<double> ranking_change; std::vector<double> ranking_change;
for (unsigned i = 0; i < players.size(); i++)
{
m_rankings[i] += distributeBasePoints(i);
}
for (unsigned i = 0; i < players.size(); i++) for (unsigned i = 0; i < players.size(); i++)
{ {
ranking_change.push_back(0); ranking_change.push_back(0);
//FIXME : if the players have been kicked out, there is no way to retrieve the data ! int player1_ranking = m_rankings[i];
//FIXME : can't use a weak_ptr like that // If the player has quitted before the race end,
int player1_ranking = players[i]->getRankingPoints(); // the value will be incorrect, but it will not be used
float player1_time = race_manager->getKartRaceTime(i); float player1_time = race_manager->getKartRaceTime(i);
float player1_factor = computeRankingFactor(i); float player1_factor = computeRankingFactor(i);
@ -817,13 +826,13 @@ void ServerLobby::computeNewRankings()
double ranking_importance = 0.0f; double ranking_importance = 0.0f;
// No change between two quitting players // No change between two quitting players
if (!players[i].lock() && !players[j].lock()) if (!players[i] && !players[j])
continue; continue;
int player2_ranking = players[i]->getRankingPoints(); int player2_ranking = m_rankings[j];
float player2_time = race_manager->getKartRaceTime(j); float player2_time = race_manager->getKartRaceTime(j);
// Compute the expected result // Compute the expected result using an ELO-like function
double diff = (double) player2_ranking - player1_ranking; double diff = (double) player2_ranking - player1_ranking;
expected_result = 1.0f/(1.0f+std::pow(10.0f, diff/(BASE_RANKING_POINTS/2.0f))); expected_result = 1.0f/(1.0f+std::pow(10.0f, diff/(BASE_RANKING_POINTS/2.0f)));
@ -831,15 +840,17 @@ void ServerLobby::computeNewRankings()
float player_factors = std::max(player1_factor, float player_factors = std::max(player1_factor,
computeRankingFactor(j) ); computeRankingFactor(j) );
if (!players[i].lock()) if (!players[i])
{ {
result = 0.0f; result = 0.0f;
ranking_importance = (MAX_SCALING_TIME/20.0f)*player_factors; ranking_importance =
MAX_SCALING_TIME*MAX_POINTS_PER_SECOND*player_factors;
} }
else if (!players[j].lock()) else if (!players[j])
{ {
result = 1.0f; result = 1.0f;
ranking_importance = (MAX_SCALING_TIME/20.0f)*player_factors; ranking_importance =
MAX_SCALING_TIME*MAX_POINTS_PER_SECOND*player_factors;
} }
else else
{ {
@ -856,21 +867,22 @@ void ServerLobby::computeNewRankings()
result = std::max( (double) 0.0f, 0.5f - result); result = std::max( (double) 0.0f, 0.5f - result);
} }
ranking_importance = std::min ( std::max (player1_time, player2_time), ranking_importance = std::min ( std::max (player1_time, player2_time),
MAX_SCALING_TIME ) * player_factors/20.0f; MAX_SCALING_TIME ) * MAX_POINTS_PER_SECOND * player_factors;
} }
// Compute the ranking change // Compute the ranking change
ranking_change[i] += ranking_importance * (result - expected_result); ranking_change[i] += ranking_importance * (result - expected_result);
} }
} }
// Don't merge it in the main loop as long as getRankingPoints // Don't merge it in the main loop as m_rankings value are used there
// is called in it
for (unsigned i = 0; i < players.size(); i++) for (unsigned i = 0; i < players.size(); i++)
{ {
// Add or substract 0.5f so that the cast to int acts like rounding m_rankings[i] += ranking_change[i];
ranking_change[i] += (ranking_change[i] > 0 ) ? 0.5f : -0.5f; // This isn't entirely correct when rankings are negatives, but
int old_ranking_points = players[i]->getRankingPoints(); // the max will always be positive
players[i]->setRankingPoints(old_ranking_points + ((int) ranking_change[i])); if ((int) (m_rankings[i]+0.5f) > m_max_ranking[i])
m_max_ranking[i] = (int) (m_rankings[i]+0.5f);
m_num_ranked_races[i]++;
} }
} //computeNewRankings } //computeNewRankings
@ -880,30 +892,42 @@ void ServerLobby::computeNewRankings()
*/ */
float ServerLobby::computeRankingFactor(unsigned int player_id) float ServerLobby::computeRankingFactor(unsigned int player_id)
{ {
auto& players = m_game_setup->getPlayers(); int max_points = m_max_ranking[player_id];
int num_races = m_num_ranked_races[player_id];
assert(player_id < players.size()); if ( max_points >= (int) (BASE_RANKING_POINTS * 2.0f))
return 0.4f;
int max_points = players[player_id].getMaxRankingPoints();
int num_races = players[player_id].getNumRankedRaces();
if (max_points >= (int) (BASE_RANKING_POINTS * 2.0f))
return 1.0f;
else if (max_points >= (int) (BASE_RANKING_POINTS * 1.75f) || num_races > 500) else if (max_points >= (int) (BASE_RANKING_POINTS * 1.75f) || num_races > 500)
return 1.25f; return 0.5f;
else if (max_points >= (int) (BASE_RANKING_POINTS * 1.5f) || num_races > 250) else if (max_points >= (int) (BASE_RANKING_POINTS * 1.5f) || num_races > 250)
return 1.5f; return 0.6f;
else if (max_points >= (int) (BASE_RANKING_POINTS * 1.25f) || num_races > 100) else if (max_points >= (int) (BASE_RANKING_POINTS * 1.25f) || num_races > 100)
return 1.75f; return 0.7f;
// The base ranking points are not distributed all at once // The base ranking points are not distributed all at once
// So it's not guaranteed a player reach them // So it's not guaranteed a player reach them
else if (max_points >= (int) (BASE_RANKING_POINTS ) || num_races > 50) else if (max_points >= (int) (BASE_RANKING_POINTS ) || num_races > 50)
return 2.0f; return 0.8f;
else else
return 2.5f; return 1.0f;
} //computeRankingFactor } //computeRankingFactor
//-----------------------------------------------------------------------------
/** Manages the distribution of the base points.
* Gives half of the points immediately and the other half progressively
* by smaller and smaller chuncks from race 1 to 46.
*/
float ServerLobby::distributeBasePoints(unsigned int player_id)
{
int num_races = m_num_ranked_races[player_id];
if (num_races == 0)
return BASE_RANKING_POINTS/2.0f;
else if (num_races <= 45)
return (BASE_RANKING_POINTS/2000.0f * std::max((45-num_races),4)*2.0f);
else
return 0.0f;
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Stop any race currently in server, should only be called in main thread. /** Stop any race currently in server, should only be called in main thread.
*/ */

View File

@ -82,6 +82,11 @@ private:
const float BASE_RANKING_POINTS = 4000.0f; const float BASE_RANKING_POINTS = 4000.0f;
const float MAX_SCALING_TIME = 600.0f; const float MAX_SCALING_TIME = 600.0f;
const float MAX_POINTS_PER_SECOND = 0.125f;
std::vector<double> m_rankings; // TODO : convert from and to int when communicating with the server. Think to round it correctly
std::vector<unsigned int> m_num_ranked_races;
std::vector<int> m_max_ranking;
// connection management // connection management
void clientDisconnected(Event* event); void clientDisconnected(Event* event);
@ -133,6 +138,7 @@ private:
void stopCurrentRace(); void stopCurrentRace();
void computeNewRankings(); void computeNewRankings();
float computeRankingFactor(unsigned int player_id); float computeRankingFactor(unsigned int player_id);
float distributeBasePoints(unsigned int player_id);
public: public:
ServerLobby(); ServerLobby();