Files
skillbird/Round.py
2019-02-06 20:57:04 +01:00

151 lines
4.9 KiB
Python

from datetime import timedelta, datetime
import threading
from Player import PlayerInRound
import TrueSkillWrapper as TS
## 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:
writeLock = threading.RLock()
def __init__(self, winner_team, loser_team, _map, duration,\
starttime, winner_side=None, cache=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()
if cache:
Round.writeLock.acquire()
with open(cache, "a") as f:
f.write(self.serialize())
f.write("\n")
f.flush()
Round.writeLock.release()
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)
def serialize(self):
# full = winners|losers|winner_side|map|duration|start
# winners/losers = p1,p2,p3 ...
winners = ""
losers = ""
for p in self.winners:
winners += "," + p.serialize()
for p in self.losers:
losers += "," + p.serialize()
teams = "{}|{}".format(winners, losers)
startTimeStr = self.start.strftime("%b %d %H:%M:%S")
ret = "{}|{}|{}|{}|{}".format(teams, self.winner_side, \
self.map, self.duration.seconds, startTimeStr)
return ret
def deserialize(string):
string = string.strip("\n")
winnersStr, losersStr, winner_side, _map, duration, startTimeStr = string.split("|")
winners = dict()
losers = dict()
for pStr in winnersStr.split(","):
if pStr == "":
continue
winners.update({PlayerInRound.deserialize(pStr):TS.new_rating()})
for pStr in losersStr.split(","):
if pStr == "":
continue
losers.update({PlayerInRound.deserialize(pStr):TS.new_rating()})
startTime = datetime.strptime(startTimeStr, "%b %d %H:%M:%S")
duration = timedelta(seconds=int(duration))
return Round(winners, losers, _map, duration, startTime, winner_side)