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
* //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()
{
//TODO : this is overall a rather naive implementation
// several possibilities to speed up the computation exist,
// though this is minor in importance as it's not done
// during racing.
auto players = m_game_setup->getConnectedPlayers(true/*same_index_for_disconnected*/);
//TODO : make some numerical parts of the formulas
// depend of a single constant value
assert (m_rankings.size() == players.size() &&
m_num_ranked_races.size() == players.size() &&
m_max_ranking.size() == players.size() );
// No ranking yet for battle mode
// TODO : separate rankings for time-trial and normal and FTL ??
if (!race_manager->modeHasLaps())
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;
for (unsigned i = 0; i < players.size(); i++)
{
m_rankings[i] += distributeBasePoints(i);
}
for (unsigned i = 0; i < players.size(); i++)
{
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
int player1_ranking = players[i]->getRankingPoints();
// If the player has quitted before the race end,
// the value will be incorrect, but it will not be used
float player1_time = race_manager->getKartRaceTime(i);
float player1_factor = computeRankingFactor(i);
@ -817,13 +826,13 @@ void ServerLobby::computeNewRankings()
double ranking_importance = 0.0f;
// No change between two quitting players
if (!players[i].lock() && !players[j].lock())
if (!players[i] && !players[j])
continue;
int player2_ranking = players[i]->getRankingPoints();
int player2_ranking = m_rankings[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;
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,
computeRankingFactor(j) );
if (!players[i].lock())
if (!players[i])
{
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;
ranking_importance = (MAX_SCALING_TIME/20.0f)*player_factors;
ranking_importance =
MAX_SCALING_TIME*MAX_POINTS_PER_SECOND*player_factors;
}
else
{
@ -856,21 +867,22 @@ void ServerLobby::computeNewRankings()
result = std::max( (double) 0.0f, 0.5f - result);
}
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
ranking_change[i] += ranking_importance * (result - expected_result);
}
}
// Don't merge it in the main loop as long as getRankingPoints
// is called in it
// Don't merge it in the main loop as m_rankings value are used there
for (unsigned i = 0; i < players.size(); i++)
{
// Add or substract 0.5f so that the cast to int acts like rounding
ranking_change[i] += (ranking_change[i] > 0 ) ? 0.5f : -0.5f;
int old_ranking_points = players[i]->getRankingPoints();
players[i]->setRankingPoints(old_ranking_points + ((int) ranking_change[i]));
m_rankings[i] += ranking_change[i];
// This isn't entirely correct when rankings are negatives, but
// the max will always be positive
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
@ -880,30 +892,42 @@ void ServerLobby::computeNewRankings()
*/
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());
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;
if ( max_points >= (int) (BASE_RANKING_POINTS * 2.0f))
return 0.4f;
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)
return 1.5f;
return 0.6f;
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
// So it's not guaranteed a player reach them
else if (max_points >= (int) (BASE_RANKING_POINTS ) || num_races > 50)
return 2.0f;
else if (max_points >= (int) (BASE_RANKING_POINTS ) || num_races > 50)
return 0.8f;
else
return 2.5f;
return 1.0f;
} //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.
*/

View File

@ -80,8 +80,13 @@ private:
/* Ranking related variables */
const float BASE_RANKING_POINTS = 4000.0f;
const float MAX_SCALING_TIME = 600.0f;
const float BASE_RANKING_POINTS = 4000.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
void clientDisconnected(Event* event);
@ -133,6 +138,7 @@ private:
void stopCurrentRace();
void computeNewRankings();
float computeRankingFactor(unsigned int player_id);
float distributeBasePoints(unsigned int player_id);
public:
ServerLobby();