2 Models related to players.
5 from calendar import timegm
7 from xonstat.models.mixins import FuzzyDateMixin, EpochMixin, NickColorsMixin
8 from xonstat.util import strip_colors, pretty_date, qfont_decode
12 # the default initial rating value
15 # the default ratings deviation value
18 # the default volatility value
21 # the ratio to convert from/to glicko2
22 GLICKO2_SCALE = 173.7178
25 class Player(EpochMixin, NickColorsMixin, FuzzyDateMixin):
27 A player, which can represent either a human or a bot.
30 def nick_strip_colors(self):
32 return "Anonymous Player"
34 return strip_colors(self.nick)
37 return "<Player({}, {})>".format(self.player_id, self.nick.encode('utf-8'))
41 'player_id': self.player_id,
43 'joined': self.create_dt.strftime('%Y-%m-%dT%H:%M:%SZ'),
44 'active_ind': self.active_ind,
45 'location': self.location,
46 'stripped_nick': qfont_decode(self.stripped_nick),
50 class Achievement(object):
52 A type of achievement. Referenced implicitly in PlayerAchievement.
56 return "<Achievement({0.achievement_cd}, {0.descr}, {0.limit})>".format(self)
60 'achievement_cd': self.achievement_cd,
66 class PlayerAchievement(object):
68 Achievements a player has earned.
72 return "<PlayerAchievement({0.player_id}, {0.achievement_cd})>".format(self)
76 'player_id': self.player_id,
77 'achievement_cd': self.achievement_cd,
81 class Hashkey(object):
83 A player's identifying key from the d0_blind_id library.
86 def __init__(self, player_id=None, hashkey=None):
87 self.player_id = player_id
88 self.hashkey = hashkey
91 return "<Hashkey({0.player_id}, {0.hashkey})>".format(self)
95 'player_id': self.player_id,
96 'hashkey': self.hashkey
100 class PlayerNick(object):
102 A single nickname a player has used in a game.
106 return "<PlayerNick({0.player_id}, {0.stripped_nick})>".format(self)
110 'player_id': self.player_id,
111 'name': qfont_decode(self.stripped_nick),
115 class PlayerElo(object):
117 A player's skill for a particular game type, as determined by a modified Elo algorithm.
120 def __init__(self, player_id=None, game_type_cd=None, elo=None):
121 self.player_id = player_id
122 self.game_type_cd = game_type_cd
128 return ("<PlayerElo(pid={0.player_id}, gametype={0.game_type_cd}, elo={0.elo}, "
129 "games={0.games})>".format(self))
133 'player_id': self.player_id,
134 'game_type_cd': self.game_type_cd,
140 class PlayerRank(NickColorsMixin):
142 A player's rank for a given game type.
146 return ("<PlayerRank(pid={0.player_id}, gametype={0.game_type_cd}, rank={0.rank})>"
151 'player_id': self.player_id,
152 'game_type_cd': self.game_type_cd,
157 class PlayerCaptime(FuzzyDateMixin, EpochMixin):
159 A flag capture time for a player on a given map.
162 def __init__(self, player_id=None, game_id=None, map_id=None, fastest_cap=None, mod=None):
163 self.player_id = player_id
164 self.game_id = game_id
166 self.fastest_cap = fastest_cap
170 return "<PlayerCaptime(pid={0.player_id}, map_id={0.map_id}, mod={0.mod})>".format(self)
173 class PlayerGroups(object):
175 An authorization group a player belongs to. Used to control access.
178 def __init__(self, player_id=None, group_name=None):
179 self.player_id = player_id
180 self.group_name = group_name
183 return "<PlayerGroups({0.player_id}, {0.group_name})>".format(self)
186 # TODO: determine if this is a real model (it is very similar to PlayerCaptime from above)
187 class PlayerCapTime(object):
189 Fastest flag capture times per player.
192 def __init__(self, row):
193 self.fastest_cap = row.fastest_cap
194 self.create_dt = row.create_dt
195 self.create_dt_epoch = timegm(row.create_dt.timetuple())
196 self.create_dt_fuzzy = pretty_date(row.create_dt)
197 self.player_id = row.player_id
198 self.game_id = row.game_id
199 self.map_id = row.map_id
200 self.map_name = row.map_name
201 self.server_id = row.server_id
202 self.server_name = row.server_name
206 "fastest_cap" : self.fastest_cap.total_seconds(),
207 "create_dt_epoch": self.create_dt_epoch,
208 "create_dt_fuzzy": self.create_dt_fuzzy,
209 "game_id":self.game_id,
210 "map_id": self.map_id,
211 "map_name": self.map_name,
212 "server_id": self.server_id,
213 "server_name": self.server_name,
217 class PlayerMedal(object):
219 A medal a player has earned in a large tournament.
223 return "<PlayerMedal(pid={0.player_id}, place={0.place}, alt={0.alt})>".format(self)
226 class PlayerGlicko(object):
228 A player's skill for a particular game type, as determined by the Glicko2 algorithm.
230 def __init__(self, player_id, game_type_cd, category="general", mu=MU, phi=PHI, sigma=SIGMA):
231 self.player_id = player_id
232 self.game_type_cd = game_type_cd
233 self.category = category
238 def to_glicko2(self):
239 """ Convert a rating to the Glicko2 scale. """
241 player_id=self.player_id,
242 game_type_cd=self.game_type_cd,
243 category=self.category,
244 mu=(float(self.mu) - MU)/GLICKO2_SCALE,
245 phi=self.phi/GLICKO2_SCALE,
249 def from_glicko2(self):
250 """ Convert a rating to the original Glicko scale. """
252 player_id=self.player_id,
253 game_type_cd=self.game_type_cd,
254 category=self.category,
255 mu=self.mu * GLICKO2_SCALE + MU,
256 phi=self.phi * GLICKO2_SCALE,
261 return ("<PlayerGlicko({0.player_id}, {0.game_type_cd}, {0.category}, "
262 "{0.mu}, {0.phi}, {0.sigma})>".format(self))
265 class PlayerGlickoBase(PlayerGlicko):
267 A clone of the above PlayerGlicko class, but created separately in order to avoid
268 dealing with primary and non-primary SQLAlchemy mappers.