Pull out rating calculation to allow use outside of RatingDelegate.
git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@963 c613c5cb-e716-0410-b11b-feb51c14d237
This commit is contained in:
@@ -0,0 +1,165 @@
|
|||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
//
|
||||||
|
// Vilya library - tools for developing networked games
|
||||||
|
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||||
|
// http://www.threerings.net/code/vilya/
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
package com.threerings.parlor.rating.server;
|
||||||
|
|
||||||
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
|
import com.threerings.media.util.MathUtil;
|
||||||
|
|
||||||
|
import com.threerings.parlor.rating.data.RatingCodes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates the rating/experience tuple representing a player's rating for a game, and logic
|
||||||
|
* for calculating rating changes.
|
||||||
|
*/
|
||||||
|
public class Rating
|
||||||
|
implements RatingCodes
|
||||||
|
{
|
||||||
|
/** The player's rating for our game. */
|
||||||
|
public int rating;
|
||||||
|
|
||||||
|
/** The number of times the player's played our game. */
|
||||||
|
public int experience;
|
||||||
|
|
||||||
|
public Rating ()
|
||||||
|
{
|
||||||
|
this.rating = DEFAULT_RATING;
|
||||||
|
this.experience = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes a player's updated rating using a modified version of the
|
||||||
|
* FIDE/ELO system. The rating adjustment is computed for the player versus
|
||||||
|
* each opponent individually and these adjustments are summed and scaled
|
||||||
|
* by one over the number of opponents to create the final rating
|
||||||
|
* adjustment, which is then added to the player's previous rating and
|
||||||
|
* bounded to the rating range. <em>Note:</em> provisional players (those
|
||||||
|
* with experience of less than 20) will be treated as having, at most, the
|
||||||
|
* default rating when used as an opponent in calculatons for a
|
||||||
|
* non-provisional player.
|
||||||
|
*
|
||||||
|
* @param ratings the pre-match ratings of each of the opponents.
|
||||||
|
* @param pidx the index of the player whose rating is to be calculated.
|
||||||
|
* @param W the win value for the player whose rating is to be calculated,
|
||||||
|
* (1.0 means the player won, 0.5 means they drew, 0 means they lost).
|
||||||
|
*
|
||||||
|
* @return the player's updated rating or -1 if none of the opponents could
|
||||||
|
* be applicably rated against this player due to provisional/
|
||||||
|
* non-provisional mismatch or lack of participation.
|
||||||
|
*/
|
||||||
|
public static int computeRating (Rating[] ratings, int pidx, float W)
|
||||||
|
{
|
||||||
|
float dR = 0; // the total delta rating
|
||||||
|
int opponents = 0;
|
||||||
|
|
||||||
|
for (int ii = 0; ii < ratings.length; ii++) {
|
||||||
|
Rating orating = ratings[ii];
|
||||||
|
// we don't care how we did against ourselves, or against guests...
|
||||||
|
if (pidx == ii || orating == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we are non-provisional, and the opponent is provisional, we
|
||||||
|
// max the opponent out at the default rating to avoid potentially
|
||||||
|
// inflating a real rating with one that has a lot of uncertainty
|
||||||
|
int opprat = ratings[ii].rating;
|
||||||
|
if (!ratings[pidx].isProvisional() && ratings[ii].isProvisional()) {
|
||||||
|
opprat = Math.min(opprat, DEFAULT_RATING);
|
||||||
|
}
|
||||||
|
dR += computeAdjustment(W, opprat, ratings[pidx]);
|
||||||
|
opponents++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we have no valid opponents, we cannot compute a rating
|
||||||
|
if (opponents == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nrat = Math.round(ratings[pidx].rating + dR/opponents);
|
||||||
|
return MathUtil.bound(MINIMUM_RATING, nrat, MAXIMUM_RATING);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes a ratings adjustment for the given player, using a modified
|
||||||
|
* version of the FIDE Chess rating system as:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* adjustment = K(W - We)
|
||||||
|
*
|
||||||
|
* where:
|
||||||
|
*
|
||||||
|
* K = if (experience < 20) then 64
|
||||||
|
* else if (rating < 2100 and experience >= 20) then 32
|
||||||
|
* else if (rating >= 2100 and rating < 2400 and experience >= 20)
|
||||||
|
* then 24
|
||||||
|
* else 16
|
||||||
|
* W = score for the game just completed, as 1.0, 0.5, and 0.0 for a
|
||||||
|
* win, draw, or loss, respectively.
|
||||||
|
* dR = opponent's rating minus player's rating.
|
||||||
|
* We = expected score (win expectancy) as determined by:
|
||||||
|
*
|
||||||
|
* We = 1 / (10^(dR/400) + 1)
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param W the win value the game in question (1.0 means the player won,
|
||||||
|
* 0.5 means they drew, 0 means they lost).
|
||||||
|
* @param opprat the opponent's current rating.
|
||||||
|
* @param rating the player's current rating.
|
||||||
|
*
|
||||||
|
* @return the adjustment to the player's rating.
|
||||||
|
*/
|
||||||
|
public static float computeAdjustment (float W, int opprat, Rating rating)
|
||||||
|
{
|
||||||
|
// calculate We, the win expectancy
|
||||||
|
float dR = opprat - rating.rating;
|
||||||
|
float We = 1.0f / (float)(Math.pow(10.0f, (dR / 400.0f)) + 1);
|
||||||
|
|
||||||
|
// calculate K, the score multiplier constant
|
||||||
|
int K;
|
||||||
|
if (rating.experience < 20) {
|
||||||
|
K = 64;
|
||||||
|
} else if (rating.rating < 2100) {
|
||||||
|
K = 32; // experience >= 20
|
||||||
|
} else if (rating.rating < 2400) {
|
||||||
|
K = 24; // experience >= 20 && rating >= 2100
|
||||||
|
} else {
|
||||||
|
K = 16; // experience >= 20 && rating >= 2400
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute and return the ratings adjustment
|
||||||
|
return K * (W - We);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this rating is provisional (experience < 20).
|
||||||
|
*/
|
||||||
|
public boolean isProvisional ()
|
||||||
|
{
|
||||||
|
return (experience < 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
return StringUtil.fieldsToString(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -83,7 +83,7 @@ public abstract class RatingDelegate extends GameManagerDelegate
|
|||||||
// if the game is in play and this is a player, load their ratings
|
// if the game is in play and this is a player, load their ratings
|
||||||
BodyObject occupant = (BodyObject)_omgr.getObject(bodyOid);
|
BodyObject occupant = (BodyObject)_omgr.getObject(bodyOid);
|
||||||
if (shouldRateGame() && _gobj.isInPlay() && isPlayer(occupant)) {
|
if (shouldRateGame() && _gobj.isInPlay() && isPlayer(occupant)) {
|
||||||
Rating rating = maybeCreateRating(occupant);
|
PlayerRating rating = maybeCreateRating(occupant);
|
||||||
if (rating != null) {
|
if (rating != null) {
|
||||||
loadRatings(Collections.singleton(rating));
|
loadRatings(Collections.singleton(rating));
|
||||||
}
|
}
|
||||||
@@ -96,7 +96,7 @@ public abstract class RatingDelegate extends GameManagerDelegate
|
|||||||
super.bodyLeft(bodyOid);
|
super.bodyLeft(bodyOid);
|
||||||
|
|
||||||
// flush this player's rating if its modified
|
// flush this player's rating if its modified
|
||||||
for (Rating rating : _ratings.values()) {
|
for (PlayerRating rating : _ratings.values()) {
|
||||||
if (rating.playerOid == bodyOid && rating.modified) {
|
if (rating.playerOid == bodyOid && rating.modified) {
|
||||||
saveRatings(Collections.singleton(rating.cloneForSave()));
|
saveRatings(Collections.singleton(rating.cloneForSave()));
|
||||||
break;
|
break;
|
||||||
@@ -122,14 +122,14 @@ public abstract class RatingDelegate extends GameManagerDelegate
|
|||||||
|
|
||||||
// load up the ratings for all players in this game; also make a note of the persistent
|
// load up the ratings for all players in this game; also make a note of the persistent
|
||||||
// player id of each player position for seated table games
|
// player id of each player position for seated table games
|
||||||
List<Rating> toLoad = Lists.newArrayList();
|
List<PlayerRating> toLoad = Lists.newArrayList();
|
||||||
for (int ii = 0, ll = _gobj.occupants.size(); ii < ll; ii++) {
|
for (int ii = 0, ll = _gobj.occupants.size(); ii < ll; ii++) {
|
||||||
BodyObject bobj = (BodyObject)_omgr.getObject(_gobj.occupants.get(ii));
|
BodyObject bobj = (BodyObject)_omgr.getObject(_gobj.occupants.get(ii));
|
||||||
int pidx = _gmgr.getPlayerIndex(bobj.getVisibleName());
|
int pidx = _gmgr.getPlayerIndex(bobj.getVisibleName());
|
||||||
if (pidx != -1) {
|
if (pidx != -1) {
|
||||||
_playerIds[pidx] = _gmgr.getPlayerPersistentId(bobj);
|
_playerIds[pidx] = _gmgr.getPlayerPersistentId(bobj);
|
||||||
}
|
}
|
||||||
Rating rating = maybeCreateRating(bobj);
|
PlayerRating rating = maybeCreateRating(bobj);
|
||||||
if (rating != null) {
|
if (rating != null) {
|
||||||
toLoad.add(rating);
|
toLoad.add(rating);
|
||||||
}
|
}
|
||||||
@@ -157,8 +157,8 @@ public abstract class RatingDelegate extends GameManagerDelegate
|
|||||||
updateRatings();
|
updateRatings();
|
||||||
|
|
||||||
// any players who are no longer in the room need their ratings flushed immediately
|
// any players who are no longer in the room need their ratings flushed immediately
|
||||||
List<Rating> flushes = Lists.newArrayList();
|
List<PlayerRating> flushes = Lists.newArrayList();
|
||||||
for (Rating rating : _ratings.values()) {
|
for (PlayerRating rating : _ratings.values()) {
|
||||||
if (rating.modified && !_gobj.occupants.contains(rating.playerOid)) {
|
if (rating.modified && !_gobj.occupants.contains(rating.playerOid)) {
|
||||||
flushes.add(rating.cloneForSave());
|
flushes.add(rating.cloneForSave());
|
||||||
}
|
}
|
||||||
@@ -166,7 +166,7 @@ public abstract class RatingDelegate extends GameManagerDelegate
|
|||||||
saveRatings(flushes);
|
saveRatings(flushes);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Rating maybeCreateRating (BodyObject bobj)
|
protected PlayerRating maybeCreateRating (BodyObject bobj)
|
||||||
{
|
{
|
||||||
// if this occupant is not a player (or not ratable), skip 'em
|
// if this occupant is not a player (or not ratable), skip 'em
|
||||||
int playerId = _gmgr.getPlayerPersistentId(bobj);
|
int playerId = _gmgr.getPlayerPersistentId(bobj);
|
||||||
@@ -174,18 +174,18 @@ public abstract class RatingDelegate extends GameManagerDelegate
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// if this player's ratings are already loaded and their oids match, no need to reload
|
// if this player's ratings are already loaded and their oids match, no need to reload
|
||||||
Rating orating = _ratings.get(playerId);
|
PlayerRating orating = _ratings.get(playerId);
|
||||||
if (orating != null && orating.playerOid == bobj.getOid()) {
|
if (orating != null && orating.playerOid == bobj.getOid()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new Rating(bobj, playerId);
|
return new PlayerRating(bobj, playerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads up rating information for the specified set of player ids and stores them in the
|
* Loads up rating information for the specified set of player ids and stores them in the
|
||||||
* {@link #_ratings} table.
|
* {@link #_ratings} table.
|
||||||
*/
|
*/
|
||||||
protected void loadRatings (final Collection<Rating> ratings)
|
protected void loadRatings (final Collection<PlayerRating> ratings)
|
||||||
{
|
{
|
||||||
if (ratings.size() == 0) {
|
if (ratings.size() == 0) {
|
||||||
return;
|
return;
|
||||||
@@ -195,15 +195,15 @@ public abstract class RatingDelegate extends GameManagerDelegate
|
|||||||
_invoker.postUnit(new RepositoryUnit("loadRatings(" + gameId + ")") {
|
_invoker.postUnit(new RepositoryUnit("loadRatings(" + gameId + ")") {
|
||||||
@Override public void invokePersist () throws Exception {
|
@Override public void invokePersist () throws Exception {
|
||||||
// map the records by player id so that we can correlate with the db results
|
// map the records by player id so that we can correlate with the db results
|
||||||
IntMap<Rating> map = IntMaps.newHashIntMap();
|
IntMap<PlayerRating> map = IntMaps.newHashIntMap();
|
||||||
for (Rating rating : ratings) {
|
for (PlayerRating rating : ratings) {
|
||||||
map.put(rating.playerId, rating);
|
map.put(rating.playerId, rating);
|
||||||
}
|
}
|
||||||
|
|
||||||
// load up the ratings data from the database, update the records
|
// load up the ratings data from the database, update the records
|
||||||
Integer[] playerIds = map.keySet().toArray(new Integer[map.size()]);
|
Integer[] playerIds = map.keySet().toArray(new Integer[map.size()]);
|
||||||
for (RatingRecord record : _repo.getRatings(gameId, playerIds)) {
|
for (RatingRecord record : _repo.getRatings(gameId, playerIds)) {
|
||||||
Rating rating = map.get(record.playerId);
|
PlayerRating rating = map.get(record.playerId);
|
||||||
if (rating != null) {
|
if (rating != null) {
|
||||||
rating.rating = record.rating;
|
rating.rating = record.rating;
|
||||||
rating.experience = record.experience;
|
rating.experience = record.experience;
|
||||||
@@ -213,14 +213,14 @@ public abstract class RatingDelegate extends GameManagerDelegate
|
|||||||
|
|
||||||
@Override public void handleSuccess () {
|
@Override public void handleSuccess () {
|
||||||
// stuff our populated records into the _ratings mapping
|
// stuff our populated records into the _ratings mapping
|
||||||
for (Rating rating : ratings) {
|
for (PlayerRating rating : ratings) {
|
||||||
_ratings.put(rating.playerId, rating);
|
_ratings.put(rating.playerId, rating);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void saveRatings (final Collection<Rating> ratings)
|
protected void saveRatings (final Collection<PlayerRating> ratings)
|
||||||
{
|
{
|
||||||
if (ratings.size() == 0) {
|
if (ratings.size() == 0) {
|
||||||
return;
|
return;
|
||||||
@@ -229,14 +229,14 @@ public abstract class RatingDelegate extends GameManagerDelegate
|
|||||||
final int gameId = getGameId();
|
final int gameId = getGameId();
|
||||||
_invoker.postUnit(new RepositoryUnit("saveRatings(" + gameId + ")") {
|
_invoker.postUnit(new RepositoryUnit("saveRatings(" + gameId + ")") {
|
||||||
@Override public void invokePersist () throws Exception {
|
@Override public void invokePersist () throws Exception {
|
||||||
for (Rating rating : ratings) {
|
for (PlayerRating rating : ratings) {
|
||||||
_repo.setRating(gameId, rating.playerId, rating.rating, rating.experience);
|
_repo.setRating(gameId, rating.playerId, rating.rating, rating.experience);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void handleSuccess () {
|
@Override public void handleSuccess () {
|
||||||
// let subclasses publish the new ratings if they so desire
|
// let subclasses publish the new ratings if they so desire
|
||||||
for (Rating rating : ratings) {
|
for (PlayerRating rating : ratings) {
|
||||||
updateRatingInMemory(gameId, rating);
|
updateRatingInMemory(gameId, rating);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -255,15 +255,21 @@ public abstract class RatingDelegate extends GameManagerDelegate
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PlayerRating[] ratings = new PlayerRating[_ratings.size()];
|
||||||
|
for (int ii = 0; ii < ratings.length; ii++) {
|
||||||
|
ratings[ii] = _ratings.get(_playerIds[ii]);
|
||||||
|
}
|
||||||
|
|
||||||
// compute the update ratings for all players
|
// compute the update ratings for all players
|
||||||
int[] nratings = new int[_playerIds.length];
|
int[] nratings = new int[_playerIds.length];
|
||||||
for (int ii = 0; ii < nratings.length; ii ++) {
|
for (int ii = 0; ii < nratings.length; ii++) {
|
||||||
nratings[ii] = computeRating(ii);
|
float W = _gobj.isDraw() ? 0.5f : _gobj.isWinner(ii) ? 1f : 0f;
|
||||||
|
nratings[ii] = Rating.computeRating(ratings, ii, W);
|
||||||
}
|
}
|
||||||
|
|
||||||
// and write them back to their rating records
|
// and write them back to their rating records
|
||||||
for (int ii = 0; ii < nratings.length; ii++) {
|
for (int ii = 0; ii < nratings.length; ii++) {
|
||||||
Rating rating = _ratings.get(_playerIds[ii]);
|
PlayerRating rating = ratings[ii];
|
||||||
if (rating != null && nratings[ii] > 0) {
|
if (rating != null && nratings[ii] > 0) {
|
||||||
rating.rating = nratings[ii];
|
rating.rating = nratings[ii];
|
||||||
rating.experience++;
|
rating.experience++;
|
||||||
@@ -272,80 +278,6 @@ public abstract class RatingDelegate extends GameManagerDelegate
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes a player's updated rating using a modified version of the FIDE/ELO system.
|
|
||||||
*
|
|
||||||
* <p> The rating adjustment is computed for the player versus each opponent individually and
|
|
||||||
* these adjustments are summed and scaled by one over the number of opponents to create the
|
|
||||||
* final rating adjustment, which is then added to the player's previous rating and bounded to
|
|
||||||
* the rating range. <em>Note:</em> provisional players (those with experience of less than 20)
|
|
||||||
* will be treated as having, at most, the default rating when used as an opponent in
|
|
||||||
* calculations for a non-provisional player.
|
|
||||||
*
|
|
||||||
* @return the player's updated rating or -1 if none of the opponents could be applicably rated
|
|
||||||
* against this player.
|
|
||||||
*/
|
|
||||||
protected int computeRating (int pidx)
|
|
||||||
{
|
|
||||||
float totDeltaR = 0; // the total delta rating
|
|
||||||
int opponents = 0;
|
|
||||||
|
|
||||||
Rating prating = _ratings.get(_playerIds[pidx]);
|
|
||||||
if (prating == null) {
|
|
||||||
// be robust
|
|
||||||
log.warning("Computing ratings for unknown player [where=" + where() +
|
|
||||||
", pidx=" + pidx + "].");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int ii = 0; ii < _playerIds.length; ii++) {
|
|
||||||
Rating orating = _ratings.get(_playerIds[ii]);
|
|
||||||
// we don't care how we did against ourselves, or against guests...
|
|
||||||
if (pidx == ii || orating == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we are non-provisional, and the opponent is provisional, we max the opponent out
|
|
||||||
// at the default rating to avoid potentially inflating a real rating with one that has
|
|
||||||
// a lot of uncertainty
|
|
||||||
int opprat = orating.rating;
|
|
||||||
if (prating.experience >= 20 && orating.experience < 20) {
|
|
||||||
opprat = Math.min(opprat, DEFAULT_RATING);
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate K, the score multiplier constant
|
|
||||||
int K;
|
|
||||||
if (prating.experience < 20) {
|
|
||||||
K = 64;
|
|
||||||
} else if (prating.rating < 2100) {
|
|
||||||
K = 32; // experience >= 20
|
|
||||||
} else if (prating.rating < 2400) {
|
|
||||||
K = 24; // experience >= 20 && rating >= 2100
|
|
||||||
} else {
|
|
||||||
K = 16; // experience >= 20 && rating >= 2400
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate W, the win value representing the actual result of the game
|
|
||||||
float W = _gobj.isDraw() ? 0.5f : _gobj.isWinner(pidx) ? 1f : 0f;
|
|
||||||
// calculate We, the expected win value given the players' respective ratings
|
|
||||||
float dR = opprat - prating.rating;
|
|
||||||
float We = 1.0f / (float)(Math.pow(10.0f, (dR / 400.0f)) + 1);
|
|
||||||
|
|
||||||
// update the total rating adjustment with the value for this opponent
|
|
||||||
totDeltaR += K * (W - We);
|
|
||||||
opponents++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we have no valid opponents, we cannot compute a rating;
|
|
||||||
if (opponents == 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return the updated and clamped rating
|
|
||||||
int nrat = Math.round(prating.rating + totDeltaR/opponents);
|
|
||||||
return MathUtil.bound(MINIMUM_RATING, nrat, MAXIMUM_RATING);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the game id to use when reading and writing ratings.
|
* Returns the game id to use when reading and writing ratings.
|
||||||
*/
|
*/
|
||||||
@@ -372,12 +304,12 @@ public abstract class RatingDelegate extends GameManagerDelegate
|
|||||||
*
|
*
|
||||||
* This method is called on the dobj thread.
|
* This method is called on the dobj thread.
|
||||||
*/
|
*/
|
||||||
protected abstract void updateRatingInMemory (int gameId, Rating rating);
|
protected abstract void updateRatingInMemory (int gameId, PlayerRating rating);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates the rating/experience tuple representing a player's rating for a game.
|
* Encapsulates the rating/experience tuple representing a player's rating for a game.
|
||||||
*/
|
*/
|
||||||
protected static class Rating
|
protected static class PlayerRating extends Rating
|
||||||
implements Cloneable
|
implements Cloneable
|
||||||
{
|
{
|
||||||
/** The oid of the rated player. */
|
/** The oid of the rated player. */
|
||||||
@@ -389,19 +321,13 @@ public abstract class RatingDelegate extends GameManagerDelegate
|
|||||||
/** The id of the rated player. */
|
/** The id of the rated player. */
|
||||||
public int playerId;
|
public int playerId;
|
||||||
|
|
||||||
/** The player's rating for our game. */
|
|
||||||
public int rating;
|
|
||||||
|
|
||||||
/** The number of times the player's played our game. */
|
|
||||||
public int experience;
|
|
||||||
|
|
||||||
/** Whether or not this rating needs to be written back to the database. */
|
/** Whether or not this rating needs to be written back to the database. */
|
||||||
public boolean modified;
|
public boolean modified;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up a new {@link Rating} object with default values.
|
* Sets up a new {@link PlayerRating} object with default values.
|
||||||
*/
|
*/
|
||||||
public Rating (BodyObject player, int playerId)
|
public PlayerRating (BodyObject player, int playerId)
|
||||||
{
|
{
|
||||||
this.playerOid = player.getOid();
|
this.playerOid = player.getOid();
|
||||||
this.playerName = player.getVisibleName();
|
this.playerName = player.getVisibleName();
|
||||||
@@ -413,22 +339,16 @@ public abstract class RatingDelegate extends GameManagerDelegate
|
|||||||
/**
|
/**
|
||||||
* Duplicates this rating and clears its modified status.
|
* Duplicates this rating and clears its modified status.
|
||||||
*/
|
*/
|
||||||
public Rating cloneForSave ()
|
public PlayerRating cloneForSave ()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Rating rating = (Rating)this.clone();
|
PlayerRating rating = (PlayerRating)this.clone();
|
||||||
modified = false;
|
modified = false;
|
||||||
return rating;
|
return rating;
|
||||||
} catch (CloneNotSupportedException cnse) {
|
} catch (CloneNotSupportedException cnse) {
|
||||||
throw new AssertionError(cnse);
|
throw new AssertionError(cnse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString ()
|
|
||||||
{
|
|
||||||
return StringUtil.fieldsToString(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An appropriately casted reference to our GameManager. */
|
/** An appropriately casted reference to our GameManager. */
|
||||||
@@ -441,7 +361,7 @@ public abstract class RatingDelegate extends GameManagerDelegate
|
|||||||
protected int[] _playerIds;
|
protected int[] _playerIds;
|
||||||
|
|
||||||
/** The ratings for each player as they were at the beginning of the game. */
|
/** The ratings for each player as they were at the beginning of the game. */
|
||||||
protected IntMap<Rating> _ratings = IntMaps.newHashIntMap();
|
protected IntMap<PlayerRating> _ratings = IntMaps.newHashIntMap();
|
||||||
|
|
||||||
/** A timestamp set at the beginning of the game, used to calculate its duration. */
|
/** A timestamp set at the beginning of the game, used to calculate its duration. */
|
||||||
protected long _startStamp;
|
protected long _startStamp;
|
||||||
|
|||||||
Reference in New Issue
Block a user