From 98351bcade005b453ecc749651e53d058244cd84 Mon Sep 17 00:00:00 2001 From: Yannik Schmidt Date: Sun, 27 Jan 2019 17:43:37 +0100 Subject: [PATCH] Add general classes --- Player.py | 74 ++++++++++++++++++++++++++++++++++++++ Round.py | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 Player.py create mode 100644 Round.py diff --git a/Player.py b/Player.py new file mode 100644 index 0000000..74b5ab7 --- /dev/null +++ b/Player.py @@ -0,0 +1,74 @@ +import datetime + +class Player: + def __init__(self, steamid, name, rating=None): + if rating: + self.rating = rating + else: + self.rating = TS.new_rating() + self.steamid = steamid + self.cur_name = name + def __hash__(self): + return hash(self.steamid) + def __eq__(self, other): + if not other: + return False + if isinstance(other,str): + return self.steamid == other + elif isinstance(other,Player): + return self.steamid == other.steamid + else: + raise TypeError("Unsupported Equals with types {} and {}".format(type(other),type(self))) + def __str__(self): + return "Player: {}, ID: {}".format(self.name, self.steamid) + +class DummyPlayer(Player): + def __init__(self, steamid, name="PLACEHOLDER", rating=None): + self.rating = TS.new_rating() + if rating: + self.rating = rating + self.name = name + self.cur_name = name + super().__init__(steamid, name) + +class PlayerInRound(Player): + def __init__(self, steamid, name, team, timestamp): + self.name = name + self.cur_name = name + self.steamid = steamid + self.rating = TS.new_rating() + self.active_time = datetime.timedelta(0) + if type(team) != int or team > 3 or team < 0: + raise Exception("Invalid TeamID '{}', must be 0-3 (inkl.)".format(team)) + self.team = int(team) + self.active = True # unset when player has disconnected or changed team + if not timestamp: + self.is_fake = True + else: + self.is_fake = False + self.timestamp = timestamp + def __str__(self): + return "TMP-Player: {}, ID: {}, active: {}".format(self.cur_name,self.steamid,self.active_time) + +class PlayerForDatabase(Player): + def __init__(self,steamid,name,rating,player=None): + if player: + self.steamid = player.steamid + self.name = player.name + self.rating = player.rating + else: + self.steamid = steamid + self.name = name + self.rating = rating + self.games = 0 + self.wins = 0 + def winratio(self): + if self.games == 0: + return "---" + return str(int(self.wins*100/self.games)) + def get_name(self): + return self.name.encode('utf-8')[:25].decode('utf-8','ignore').rstrip(" ") + +class PlayerFromDatabase(PlayerForDatabase): + def __init__(line): + super().__init__(None,None,None) diff --git a/Round.py b/Round.py new file mode 100644 index 0000000..f03c639 --- /dev/null +++ b/Round.py @@ -0,0 +1,104 @@ +from datetime import timedelta + +## A comment on why the login-offset is nessesary ## +## - losing teams tend to have players leaving and joining more rapidly +## - every time a new player joins he has to setup +## - new players are unfamiliar with postions of enemy team +## - new players have to run from spawn +## --> their impact factor must account for that +loginoffset = timedelta(seconds=60) + +class Round: + def __init__(self,winner_team,loser_team,_map,duration,starttime,winner_side=None): + self.winners = winner_team + self.losers = loser_team + self.winner_side = winner_side + self.map = _map + self.duration = duration + self.start = starttime + self.add_fake_players() + + def normalized_playtimes(self): + '''returns a dict-Object with {key=(teamid,player):value=player_time_played/total_time_of_round}''' + np = dict() + + for p in self.winners: + if self.duration == None: + d = 1.0 + else: + d = (p.active_time-loginoffset)/self.duration + if d < -1: + print("lol") + if d < 0: + d = 0.0 + elif d > 1: + d = 1.0 + np.update({(0,p):d}) + for p in self.losers: + if self.duration == None: + d = 1.0 + else: + d = (p.active_time-loginoffset)/self.duration + if d < 0: + d = 0.0 + elif d > 1: + d = 1.0 + np.update({(1,p):d}) + + return np + + def add_fake_players(self): + ''' adds map/side specific player to account for asynchronous gameplay ''' + if not self.map: + #print("Warning: No map info, cannot add fake players.") + return + ins = self.map+str(2) + sec = self.map+str(3) + + p_ins = PlayerInRound(ins,2,None) + p_sec = PlayerInRound(sec,3,None) + + if p_ins in Storrage.known_players: + p_ins = Storrage.known_players[p_ins] + if p_sec in Storrage.known_players: + p_sec = Storrage.known_players[p_sec] + + if self.winner_side == 2: + self.winners += [p_ins] + self.losers += [p_sec] + else: + self.winners += [p_sec] + self.losers += [p_ins] + + def pt_difference(self): + '''Used to check difference in playtimes per team''' + if self.duration == None: + return 1 + w1 = w2 = 0 + for p in self.winners: + if p.is_fake: + w1 += 1.0 + continue + d = (p.active_time-loginoffset)/self.duration + if d < 0: + d = 0.0 + elif d > 1: + d = 1.0 + w1 += d + for p in self.losers: + d = (p.active_time-loginoffset)/self.duration + if p.is_fake: + w2 += 1.0 + continue + if d < 0: + d = 0.0 + elif d > 1: + d = 1.0 + w2 += d + + # no div0 plox + if min(w1,w2) <= 0: + return 0 + + return max(w1,w2)/min(w1,w2) +