Fix/update ranking computation
This commit is contained in:
parent
8da8390773
commit
b026b24e4a
@ -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.
|
||||||
*/
|
*/
|
||||||
|
@ -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();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user