Several improvements to the ranking formula

This commit is contained in:
Alayan 2019-01-06 02:35:01 +01:00
parent e2d5e350cf
commit aeeb4afd63
2 changed files with 67 additions and 28 deletions

View File

@ -1651,6 +1651,7 @@ void ServerLobby::computeNewRankings()
double result = 0.0; double result = 0.0;
double expected_result = 0.0; double expected_result = 0.0;
double ranking_importance = 0.0; double ranking_importance = 0.0;
double max_time = 0.0;
// No change between two quitting players // No change between two quitting players
if (w->getKart(i)->isEliminated() && if (w->getKart(i)->isEliminated() &&
@ -1660,13 +1661,8 @@ void ServerLobby::computeNewRankings()
double player2_scores = new_scores[j]; double player2_scores = new_scores[j];
double player2_time = race_manager->getKartRaceTime(j); double player2_time = race_manager->getKartRaceTime(j);
// Compute the expected result using an ELO-like function
double diff = player2_scores - player1_scores;
expected_result = 1.0/ (1.0 + std::pow(10.0,
diff / (BASE_RANKING_POINTS * getModeSpread() / 2.0)));
// Compute the result and race ranking importance // Compute the result and race ranking importance
double player_factors = std::max(player1_factor, double player_factors = std::min(player1_factor,
computeRankingFactor( computeRankingFactor(
race_manager->getKartInfo(j).getOnlineId())); race_manager->getKartInfo(j).getOnlineId()));
@ -1675,14 +1671,14 @@ void ServerLobby::computeNewRankings()
if (w->getKart(i)->isEliminated()) if (w->getKart(i)->isEliminated())
{ {
result = 0.0; result = 0.0;
ranking_importance = mode_factor * player1_time = player2_time; // for getTimeSpread
scalingValueForTime(MAX_SCALING_TIME) * player_factors; max_time = MAX_SCALING_TIME;
} }
else if (w->getKart(j)->isEliminated()) else if (w->getKart(j)->isEliminated())
{ {
result = 1.0; result = 1.0;
ranking_importance = mode_factor * player2_time = player1_time;
scalingValueForTime(MAX_SCALING_TIME) * player_factors; max_time = MAX_SCALING_TIME;
} }
else else
{ {
@ -1701,11 +1697,25 @@ void ServerLobby::computeNewRankings()
result = std::max(0.0, 0.5 - result); result = std::max(0.0, 0.5 - result);
} }
double max_time = std::min(std::max(player1_time, player2_time), max_time = std::min(std::max(player1_time, player2_time),
MAX_SCALING_TIME); MAX_SCALING_TIME);
ranking_importance = mode_factor *
scalingValueForTime(max_time) * player_factors;
} }
ranking_importance = mode_factor *
scalingValueForTime(max_time) * player_factors;
// Compute the expected result using an ELO-like function
double diff = player2_scores - player1_scores;
double uncertainty = std::max(getUncertaintySpread(race_manager->getKartInfo(i).getOnlineId()),
getUncertaintySpread(race_manager->getKartInfo(j).getOnlineId()) );
expected_result = 1.0/ (1.0 + std::pow(10.0,
diff / ( BASE_RANKING_POINTS / 2.0
* getModeSpread()
* getTimeSpread(std::min(player1_time, player2_time))
* uncertainty )));
// Compute the ranking change // Compute the ranking change
scores_change[i] += scores_change[i] +=
ranking_importance * (result - expected_result); ranking_importance * (result - expected_result);
@ -1733,19 +1743,19 @@ double ServerLobby::computeRankingFactor(uint32_t online_id)
unsigned num_races = m_num_ranked_races.at(online_id); unsigned num_races = m_num_ranked_races.at(online_id);
if (max_points >= (BASE_RANKING_POINTS * 2.0)) if (max_points >= (BASE_RANKING_POINTS * 2.0))
return 0.4;
else if (max_points >= (BASE_RANKING_POINTS * 1.75) || num_races > 500)
return 0.5;
else if (max_points >= (BASE_RANKING_POINTS * 1.5) || num_races > 250)
return 0.6; return 0.6;
else if (max_points >= (BASE_RANKING_POINTS * 1.25) || num_races > 100) else if (max_points >= (BASE_RANKING_POINTS * 1.75) || num_races > 500)
return 0.7; return 0.7;
else if (max_points >= (BASE_RANKING_POINTS * 1.5) || num_races > 250)
return 0.8;
else if (max_points >= (BASE_RANKING_POINTS * 1.25) || num_races > 100)
return 1.0;
// 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 >= (BASE_RANKING_POINTS) || num_races > 50) else if (max_points >= (BASE_RANKING_POINTS) || num_races > 50)
return 0.8; return 1.2;
else else
return 1.0; return 1.5;
} // computeRankingFactor } // computeRankingFactor
@ -1757,7 +1767,7 @@ double ServerLobby::getModeFactor()
{ {
if (race_manager->isTimeTrialMode()) if (race_manager->isTimeTrialMode())
return 1.0; return 1.0;
return 0.4; return 0.7;
} // getModeFactor } // getModeFactor
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -1773,31 +1783,58 @@ double ServerLobby::getModeSpread()
// When hard data to the spread tendencies of time-trial // When hard data to the spread tendencies of time-trial
// and normal mode becomes available, update this to make // and normal mode becomes available, update this to make
// the spreads more comparable // the spreads more comparable
return 1.4; return 1.5;
} // getModeSpread } // getModeSpread
//-----------------------------------------------------------------------------
/** Returns the time spread factor.
* Short races are more random, so the expected result changes depending
* on race duration.
*/
double ServerLobby::getTimeSpread(double time)
{
return sqrt(120.0 / time);
} // getTimeSpread
//-----------------------------------------------------------------------------
/** Returns the uncertainty spread factor.
* The ranking of new players is not yet reliable,
* so weight the expected results twoards 0.5 by using a > 1 spread
*/
double ServerLobby::getUncertaintySpread(uint32_t online_id)
{
unsigned num_races = m_num_ranked_races.at(online_id);
if (num_races <= 60)
return 0.5 + (4.0/sqrt(num_races+3));
else
return 1.0;
} // getUncertaintySpread
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Compute the scaling value of a given time /** Compute the scaling value of a given time
* Short races are more random, so we don't use strict proportionality * This is linear to race duration, getTimeSpread takes care
* of expecting a more random result in shorter races.
*/ */
double ServerLobby::scalingValueForTime(double time) double ServerLobby::scalingValueForTime(double time)
{ {
return time * sqrt(time / 120.0) * MAX_POINTS_PER_SECOND; return time * MAX_POINTS_PER_SECOND;
} // scalingValueForTime } // scalingValueForTime
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Manages the distribution of the base points. /** Manages the distribution of the base points.
* Gives half of the points progressively * Gives half of the points progressively
* by smaller and smaller chuncks from race 1 to 45. * by smaller and smaller chuncks from race 1 to 60.
* The race count is incremented after this is called, so num_races
* is between 0 and 59.
* The first half is distributed when the player enters * The first half is distributed when the player enters
* for the first time in the ranked server. * for the first time in a ranked server.
*/ */
double ServerLobby::distributeBasePoints(uint32_t online_id) double ServerLobby::distributeBasePoints(uint32_t online_id)
{ {
unsigned num_races = m_num_ranked_races.at(online_id); unsigned num_races = m_num_ranked_races.at(online_id);
if (num_races <= 45) if (num_races < 60)
{ {
return BASE_RANKING_POINTS / 2000.0 * std::max((45u - num_races), 4u); return BASE_RANKING_POINTS / 8000.0 * std::max((96u - num_races), 41u);
} }
else else
return 0.0; return 0.0;

View File

@ -263,6 +263,8 @@ private:
double distributeBasePoints(uint32_t online_id); double distributeBasePoints(uint32_t online_id);
double getModeFactor(); double getModeFactor();
double getModeSpread(); double getModeSpread();
double getTimeSpread(double time);
double getUncertaintySpread(uint32_t online_id);
double scalingValueForTime(double time); double scalingValueForTime(double time);
void checkRaceFinished(); void checkRaceFinished();
void getHitCaptureLimit(float num_karts); void getHitCaptureLimit(float num_karts);