def __init__(self, is_adm, request=None): if request is not None: super(AddMatchesForm, self).__init__(request.POST) self.close_after = 'commit_close' in request.POST self.eobj = etn(lambda: request.POST['eventobj']) else: super(AddMatchesForm, self).__init__(initial={'date': date.today()}) self.close_after = False self.requested_close_after = self.close_after self.label_suffix = '' self.is_adm = is_adm self.fields['eventobj'] = forms.ChoiceField( choices=[ (e['id'], e['fullname']) for e in Event.objects.filter( closed=False, type__in=(TYPE_ROUND, TYPE_EVENT) ) .annotate(num_downlinks=Count('downlink')) .filter(num_downlinks=1) .order_by('idx') .values('id', 'fullname') ], required=False, label=_('Event'), )
def make_player(player): if player is None: pl = Player('BYE', 'T', -10000, 0, 0, 0) pl.dbpl = None return pl try: rating = player.current_rating pl = Player( player.tag, player.race, rating.rating, rating.rating_vp, rating.rating_vt, rating.rating_vz, rating.dev, rating.dev_vp, rating.dev_vt, rating.dev_vz, ) except: pl = Player( player.tag, player.race, start_rating(player.country, etn(lambda: get_latest_period().id) or 1), 0.0, 0.0, 0.0, INIT_DEV, INIT_DEV, INIT_DEV, INIT_DEV, ) pl.dbpl = player return pl
def __init__(self, is_adm, request=None): if request is not None: super(AddMatchesForm, self).__init__(request.POST) self.close_after = 'commit_close' in request.POST self.eobj = etn(lambda: request.POST['eventobj']) else: super(AddMatchesForm, self).__init__(initial={'date': date.today()}) self.close_after = False self.requested_close_after = self.close_after self.label_suffix = '' self.is_adm = is_adm self.fields['eventobj'] = forms.ChoiceField( choices=[(e['id'], e['fullname']) for e in Event.objects.filter( closed=False, type__in=(TYPE_ROUND, TYPE_EVENT)).annotate( num_downlinks=Count('downlink')).filter( num_downlinks=1).order_by('idx').values( 'id', 'fullname')], required=False, label=_('Event'), )
def adjustment(request, player_id, period_id): # {{{ Get objects period = get_object_or_404(Period, id=period_id, computed=True) player = get_object_or_404(Player, id=player_id) rating = get_object_or_404(Rating, player=player, period=period) base = base_ctx('Ranking', 'Adjustments', request, context=player) base.update({ 'period': period, 'player': player, 'rating': rating, 'prevlink': etn(lambda: player.rating_set.filter(period__lt=period, decay=0).latest('period')), 'nextlink': etn(lambda: player.rating_set.filter(period__gt=period, decay=0).earliest('period')), }) # }}} # {{{ Matches matches = player.get_matchset(related=['rta','rtb','pla','plb','eventobj']).filter(period=period) base.update({"title": player.tag}) # If there are no matches, we don't need to continue if not matches.exists(): return render_to_response('ratingdetails.html', base) base.update({ 'matches': display_matches(matches, fix_left=player, ratings=True), 'has_treated': False, 'has_nontreated': False, }) # }}} # {{{ Perform calculations tot_rating = {'M': 0.0, 'P': 0.0, 'T': 0.0, 'Z': 0.0} ngames = {'M': 0.0, 'P': 0.0, 'T': 0.0, 'Z': 0.0} expwins = {'M': 0.0, 'P': 0.0, 'T': 0.0, 'Z': 0.0} nwins = {'M': 0.0, 'P': 0.0, 'T': 0.0, 'Z': 0.0} for m in base['matches']: if not m['match'].treated: base['has_nontreated'] = True continue base['has_treated'] = True total_score = m['pla']['score'] + m['plb']['score'] scale = sqrt(1 + m['pla']['dev']**2 + m['plb']['dev']**2) expected = total_score * cdf(m['pla']['rating'] - m['plb']['rating'], scale=scale) ngames['M'] += total_score tot_rating['M'] += m['plb']['rating'] * total_score expwins['M'] += expected nwins['M'] += m['pla']['score'] vs_races = [m['plb']['race']] if m['plb']['race'] in 'PTZ' else 'PTZ' weight = 1/len(vs_races) for r in vs_races: ngames[r] += weight * total_score tot_rating[r] += weight * m['plb']['rating'] * total_score expwins[r] += weight * expected nwins[r] += weight * m['pla']['score'] for r in 'MPTZ': if ngames[r] > 0: tot_rating[r] /= ngames[r] base.update({ 'ngames': ngames, 'tot_rating': tot_rating, 'expwins': expwins, 'nwins': nwins, }) # }}} return render_to_response('ratingdetails.html', base)
def player(request, player_id): # {{{ Get player object and base context, generate messages and make changes if needed player = get_object_or_404(Player, id=player_id) base = base_ctx('Ranking', 'Summary', request, context=player) if request.method == 'POST' and base['adm']: form = PlayerModForm(request) base['messages'] += form.update_player(player) else: form = PlayerModForm(player=player) base['messages'] += generate_messages(player) # }}} # {{{ Various easy data matches = player.get_matchset() recent = matches.filter(date__gte=(date.today() - relativedelta(months=2))) base.update({ 'player': player, 'form': form, 'first': etn(lambda: matches.earliest('date')), 'last': etn(lambda: matches.latest('date')), 'totalmatches': matches.count(), 'offlinematches': matches.filter(offline=True).count(), 'aliases': player.alias_set.all(), 'earnings': ntz(player.earnings_set.aggregate(Sum('earnings'))['earnings__sum']), 'team': player.get_current_team(), 'total': count_winloss_player(matches, player), 'vp': count_matchup_player(matches, player, P), 'vt': count_matchup_player(matches, player, T), 'vz': count_matchup_player(matches, player, Z), 'totalf': count_winloss_player(recent, player), 'vpf': count_matchup_player(recent, player, P), 'vtf': count_matchup_player(recent, player, T), 'vzf': count_matchup_player(recent, player, Z), }) if player.country is not None: base['countryfull'] = transformations.cc_to_cn(player.country) # }}} # {{{ Recent matches matches = player.get_matchset(related=['rta','rtb','pla','plb','eventobj'])[0:10] if matches.exists(): base['matches'] = display_matches(matches, fix_left=player, ratings=True) # }}} # {{{ Team memberships team_memberships = list(player.groupmembership_set.filter(group__is_team=True).select_related('group')) team_memberships.sort(key=lambda t: t.id, reverse=True) team_memberships.sort(key=meandate, reverse=True) team_memberships.sort(key=lambda t: t.current, reverse=True) base['teammems'] = team_memberships # }}} # {{{ If the player has at least one rating if player.current_rating: ratings = total_ratings(player.rating_set.filter(period__computed=True)).select_related('period') base.update({ 'highs': ( ratings.latest('rating'), ratings.latest('tot_vp'), ratings.latest('tot_vt'), ratings.latest('tot_vz'), ), 'recentchange': player.get_latest_rating_update(), 'firstrating': ratings.earliest('period'), 'rating': player.current_rating, }) if player.current_rating.decay >= INACTIVE_THRESHOLD: base['messages'].append(Message(msg_inactive % player.tag, 'Inactive', type=Message.INFO)) base['charts'] = base['recentchange'].period_id > base['firstrating'].period_id else: base['messages'].append(Message('%s has no rating yet.' % player.tag, type=Message.INFO)) base['charts'] = False # }}} # {{{ If the player has enough games to make a chart if base['charts']: ratings = ( total_ratings(player.rating_set.filter(period_id__lte=base['recentchange'].period_id)) .select_related('period__end') .prefetch_related('prev__rta', 'prev__rtb') .order_by('period') ) # {{{ Add stories and other extra information earliest = base['firstrating'] latest = base['recentchange'] # Look through team changes teampoints = [] for mem in base['teammems']: if mem.start and earliest.period.end < mem.start < latest.period.end: teampoints.append({ 'date': mem.start, 'rating': interp_rating(mem.start, ratings), 'data': [{'date': mem.start, 'team': mem.group, 'jol': 'joins'}], }) if mem.end and earliest.period.end < mem.end < latest.period.end: teampoints.append({ 'date': mem.end, 'rating': interp_rating(mem.end, ratings), 'data': [{'date': mem.end, 'team': mem.group, 'jol': 'leaves'}], }) teampoints.sort(key=lambda p: p['date']) # Condense if team changes happened within 14 days cur = 0 while cur < len(teampoints) - 1: if (teampoints[cur+1]['date'] - teampoints[cur]['date']).days <= 14: teampoints[cur]['data'].append(teampoints[cur+1]['data'][0]) del teampoints[cur+1] else: cur += 1 # Sort first by date, then by joined/left for point in teampoints: point['data'].sort(key=lambda a: a['jol'], reverse=True) point['data'].sort(key=lambda a: a['date']) # Look through stories stories = player.story_set.all().select_related('event__fullname') for s in stories: if earliest.period.start < s.date < latest.period.start: s.rating = interp_rating(s.date, ratings) else: s.skip = True # }}} base.update({ 'ratings': add_counts(ratings), 'patches': PATCHES, 'stories': stories, 'teampoints': teampoints, }) else: base['messages'].append(Message(msg_nochart % player.tag, type=Message.INFO)) # }}} base.update({"title": player.tag}) return render_to_response('player.html', base)
def events(request, event_id=None): # {{{ Get base context, redirect if necessary if 'goto' in request.GET: return redirect('/results/events/' + request.GET['goto']) base = base_ctx('Results', 'By Event', request) # }}} # {{{ Display the main table if event ID is not given if event_id is None: root_events = ( Event.objects .annotate(num_uplinks=Count("uplink")) .filter(num_uplinks=1) .order_by('name') .only('id', 'name', 'big', 'category', 'fullname') ) base.update({ 'bigs': ( list(root_events.filter(big=True, category=CAT_INDIVIDUAL)) + list(root_events.filter(big=True, category=CAT_TEAM)) + list(root_events.filter(big=True, category=CAT_FREQUENT)) ), 'smalls': ( list(root_events.filter(big=False, category=CAT_INDIVIDUAL).order_by('name')) + list(root_events.filter(big=False, category=CAT_TEAM).order_by('name')) + list(root_events.filter(big=False, category=CAT_FREQUENT).order_by('name')) ) }) base['messages'].append(Message( _('The events are organized in a hierarchical fashion. Thus, all GSL tournaments ' 'are filed under GSL, all Code S under their respective seasons, all groups under ' 'their respective Code S event, and so on.'), type=Message.INFO )) return render_to_response('events.djhtml', base) # }}} # {{{ Get object, generate messages, and ensure big is set. Find familial relationships. event = get_object_or_404(Event, id=event_id) base['messages'] += generate_messages(event) matches = event.get_matchset() if matches.count() > 200 and not event.big: event.set_big(True) base.update({ 'event': event, 'siblings': event.get_parent().get_immediate_children().exclude(id=event.id) if event.get_parent() else None, 'path': event.get_ancestors(id=True), 'children': event.get_immediate_children(), }) # }}} # {{{ Make forms if base['adm']: def check_form(formname, cl, check): if request.method == 'POST' and check in request.POST: f = cl(request=request, event=event) base['messages'] += f.update_event(event) else: f = cl(event=event) base[formname] = f check_form('form', EventModForm, 'modevent') check_form('addform', AddForm, 'addevent') if event.has_children(): check_form('reorderform', ReorderForm, 'reorder') if event.type == TYPE_EVENT: check_form('ppform', PrizepoolModForm, 'modpp') check_form('wcsform', WCSModForm, 'modwcs') if not event.has_children() and event.get_immediate_matchset().exists(): check_form('stform', StoriesForm, 'modstory') if 'close' in request.GET and request.GET['close'] == '1': event.close() base['messages'].append(Message(_('Sucessfully closed event.'), type=Message.SUCCESS)) # }}} # {{{ Prizepool information for the public total_earnings = Earnings.objects.filter(event__uplink__parent=event) local_earnings = Earnings.objects.filter(event=event) ranked_prize = local_earnings.exclude(placement=0)\ .order_by('-earnings', 'placement') unranked_prize = list( local_earnings.filter(placement=0).order_by('-earnings') ) placements = get_placements(event) prize_pool_table = list() for k, g in groupby(ranked_prize, key=lambda x: x.earnings): gl = list(g) prize_pool_table.append((k, placements[k], gl, len(gl))) if len(prize_pool_table) > 0: base['ranked_prize'] = prize_pool_table if len(unranked_prize) > 0: base['unranked_prize'] = unranked_prize currencies = list({r['currency'] for r in total_earnings.values('currency').distinct()}) base.update({ 'prizepool': total_earnings.aggregate(Sum('earnings'))['earnings__sum'], 'nousdpp': len(currencies) > 1 or len(currencies) == 1 and currencies[0] != 'USD', 'prizepoolorig': [{ 'pp': total_earnings.filter(currency=k).aggregate(Sum('origearnings'))['origearnings__sum'], 'cur': k, } for k in currencies], }) # }}} # {{{ Other easy statistics add_links = request.user.is_authenticated() and request.user.is_staff base.update({ 'game': etn(lambda: dict(GAMES)[matches.values('game').distinct()[0]['game']]), 'nmatches': matches.count(), 'ngames': sum(count_winloss_games(matches)), 'pvp_games': count_mirror_games(matches, 'P'), 'tvt_games': count_mirror_games(matches, 'T'), 'zvz_games': count_mirror_games(matches, 'Z'), 'matches': display_matches( matches.prefetch_related('message_set') .prefetch_related('pla', 'plb', 'eventobj') .annotate(Count('eventobj__match')) .order_by('-eventobj__latest', '-eventobj__idx', '-date', '-id')[0:200], eventcount=True, add_links=add_links ), 'nplayers': Player.objects.filter( Q(id__in=matches.values('pla')) | Q(id__in=matches.values('plb')) ).count(), }) offlines = list(matches.values('offline').distinct()) if len(offlines) > 1: base['offline'] = _('Both') elif len(offlines) == 1: base['offline'] = _('Offline') if offlines[0]['offline'] else _('Online') base['pvt_wins'], base['pvt_loss'] = count_matchup_games(matches, 'P', 'T') base['pvz_wins'], base['pvz_loss'] = count_matchup_games(matches, 'P', 'Z') base['tvz_wins'], base['tvz_loss'] = count_matchup_games(matches, 'T', 'Z') base['tot_mirror'] = base['pvp_games'] + base['tvt_games'] + base['zvz_games'] # }}} return render_to_response('eventres.djhtml', base)
# {{{ Initialize periods try: period = Period.objects.get(id=sys.argv[1]) except: print('[%s] No such period' % str(datetime.now()), flush=True) sys.exit(1) print('[{0}] Recomputing #{1} ({2} -> {3})'.format(str(datetime.now()), period.id, period.start, period.end), flush=True) if Period.objects.filter(id__lt=period.id).filter(Q(computed=False) | Q(needs_recompute=True)).exists(): print('[%s] Earlier period not refreshed. Aborting.' % str(datetime.now()), flush=True) sys.exit(1) prev = etn(lambda: Period.objects.get(id=period.id-1)) # }}} # {{{ Get players players = {} if prev: for r in Rating.objects.filter(period=prev).select_related('player').prefetch_related('prevrating'): players[r.player_id] = { 'player': r.player, 'rating': r, 'prev_ratings': { 'M': r.rating, 'P': r.rating_vp, 'T': r.rating_vt, 'Z': r.rating_vz }, 'prev_devs': { 'M': r.dev, 'P': r.dev_vp, 'T': r.dev_vt, 'Z': r.dev_vz }, 'opp_c': [], 'opp_r': [], 'opp_d': [], 'wins': [], 'losses': [], }
def events(request, event_id=None): # {{{ Get base context, redirect if necessary if 'goto' in request.GET: return redirect('/results/events/' + request.GET['goto']) base = base_ctx('Results', 'By Event', request) # }}} # {{{ Display the main table if event ID is not given if event_id is None: root_events = ( Event.objects .annotate(num_uplinks=Count("uplink")) .filter(num_uplinks=1) .order_by('name') .only('id', 'name', 'big', 'category', 'fullname') ) base.update({ 'ind_bigs': collect(root_events.filter(big=True, category=CAT_INDIVIDUAL), 2), 'ind_smalls': root_events.filter(big=False, category=CAT_INDIVIDUAL).order_by('name'), 'team_bigs': collect(root_events.filter(big=True, category=CAT_TEAM), 2), 'team_smalls': root_events.filter(big=False, category=CAT_TEAM).order_by('name'), 'freq_bigs': collect(root_events.filter(big=True, category=CAT_FREQUENT), 2), 'freq_smalls': root_events.filter(big=False, category=CAT_FREQUENT).order_by('name'), }) return render_to_response('events.html', base) # }}} # {{{ Get object, generate messages, and ensure big is set. Find familial relationships. event = get_object_or_404(Event, id=event_id) base['messages'] += generate_messages(event) matches = event.get_matchset() if matches.count() > 200 and not event.big: event.set_big(True) base.update({ 'event': event, 'siblings': event.get_parent().get_immediate_children().exclude(id=event.id) if event.get_parent() else None, 'path': event.get_ancestors(id=True), 'children': event.get_immediate_children(), }) # }}} # {{{ Make forms if base['adm']: def check_form(formname, cl, check): if request.method == 'POST' and check in request.POST: f = cl(request=request, event=event) base['messages'] += f.update_event(event) else: f = cl(event=event) base[formname] = f check_form('form', EventModForm, 'modevent') check_form('addform', AddForm, 'addevent') if event.has_children(): check_form('reorderform', ReorderForm, 'reorder') if event.type == TYPE_EVENT: check_form('ppform', PrizepoolModForm, 'modpp') if not event.has_children() and event.get_immediate_matchset().exists(): check_form('stform', StoryModForm, 'modstories') # }}} # {{{ Prizepool information for the public total_earnings = Earnings.objects.filter(event__uplink__parent=event) currencies = list({r['currency'] for r in total_earnings.values('currency').distinct()}) base.update({ 'prizepool': total_earnings.aggregate(Sum('earnings'))['earnings__sum'], 'nousdpp': len(currencies) > 1 or len(currencies) == 1 and currencies[0] != 'USD', 'prizepoolorig': [{ 'pp': total_earnings.filter(currency=k).aggregate(Sum('origearnings'))['origearnings__sum'], 'cur': k, } for k in currencies], }) # }}} # {{{ Other easy statistics base.update({ 'game': etn(lambda: dict(Match.GAMES)[matches.values('game').distinct()[0]['game']]), 'offline': etn(lambda: matches.values('offline').distinct()[0]['offline']), 'nmatches': matches.count(), 'ngames': sum(count_winloss_games(matches)), 'pvp_games': count_mirror_games(matches, 'P'), 'tvt_games': count_mirror_games(matches, 'T'), 'zvz_games': count_mirror_games(matches, 'Z'), 'matches': display_matches( matches.prefetch_related('message_set') .prefetch_related('pla', 'plb', 'eventobj') .annotate(Count('eventobj__match')) .order_by('-eventobj__latest', '-eventobj__idx', '-date', '-id')[0:200], eventcount=True, ), 'nplayers': Player.objects.filter( Q(id__in=matches.values('pla')) | Q(id__in=matches.values('plb')) ).count(), }) base['pvt_wins'], base['pvt_loss'] = count_matchup_games(matches, 'P', 'T') base['pvz_wins'], base['pvz_loss'] = count_matchup_games(matches, 'P', 'Z') base['tvz_wins'], base['tvz_loss'] = count_matchup_games(matches, 'T', 'Z') base['tot_mirror'] = base['pvp_games'] + base['tvt_games'] + base['zvz_games'] # }}} base.update({"title": event}) return render_to_response('eventres.html', base)
def adjustment(request, player_id, period_id): # {{{ Get objects period = get_object_or_404(Period, id=period_id, computed=True) player = get_object_or_404(Player, id=player_id) rating = get_object_or_404(Rating, player=player, period=period) base = base_ctx('Ranking', 'Adjustments', request, context=player) base.update({ 'period': period, 'player': player, 'rating': rating, 'prevlink': etn(lambda: player.rating_set.filter(period__lt=period, decay=0). latest('period')), 'nextlink': etn(lambda: player.rating_set.filter(period__gt=period, decay=0). earliest('period')), }) # }}} # {{{ Matches matches = player.get_matchset( related=['rta', 'rtb', 'pla', 'plb', 'eventobj']).filter(period=period) # If there are no matches, we don't need to continue if not matches.exists(): return render_to_response('ratingdetails.djhtml', base) base.update({ 'matches': display_matches(matches, fix_left=player, ratings=True), 'has_treated': False, 'has_nontreated': False, }) # }}} # {{{ Perform calculations tot_rating = {'M': 0.0, 'P': 0.0, 'T': 0.0, 'Z': 0.0} ngames = {'M': 0.0, 'P': 0.0, 'T': 0.0, 'Z': 0.0} expwins = {'M': 0.0, 'P': 0.0, 'T': 0.0, 'Z': 0.0} nwins = {'M': 0.0, 'P': 0.0, 'T': 0.0, 'Z': 0.0} for m in base['matches']: if not m['match'].treated: base['has_nontreated'] = True continue base['has_treated'] = True total_score = m['pla']['score'] + m['plb']['score'] scale = sqrt(1 + m['pla']['dev']**2 + m['plb']['dev']**2) expected = total_score * cdf(m['pla']['rating'] - m['plb']['rating'], scale=scale) ngames['M'] += total_score tot_rating['M'] += m['plb']['rating'] * total_score expwins['M'] += expected nwins['M'] += m['pla']['score'] vs_races = [m['plb']['race']] if m['plb']['race'] in 'PTZ' else 'PTZ' weight = 1 / len(vs_races) for r in vs_races: ngames[r] += weight * total_score tot_rating[r] += weight * m['plb']['rating'] * total_score expwins[r] += weight * expected nwins[r] += weight * m['pla']['score'] for r in 'MPTZ': if ngames[r] > 0: tot_rating[r] /= ngames[r] base.update({ 'ngames': ngames, 'tot_rating': tot_rating, 'expwins': expwins, 'nwins': nwins, }) # }}} return render_to_response('ratingdetails.djhtml', base)
def player(request, player_id): # {{{ Get player object and base context, generate messages and make changes if needed player = get_object_or_404(Player, id=player_id) base = base_ctx('Ranking', 'Summary', request, context=player) if request.method == 'POST' and 'modplayer' in request.POST and base['adm']: modform = PlayerModForm(request) base['messages'] += modform.update_player(player) else: modform = PlayerModForm(player=player) base['messages'] += generate_messages(player) # }}} # {{{ Various easy data matches = player.get_matchset() recent = matches.filter(date__gte=(date.today() - relativedelta(months=2))) base.update({ 'player': player, 'modform': modform, 'first': etn(lambda: matches.earliest('date')), 'last': etn(lambda: matches.latest('date')), 'totalmatches': matches.count(), 'offlinematches': matches.filter(offline=True).count(), 'aliases': player.alias_set.all(), 'earnings': ntz(player.earnings_set.aggregate(Sum('earnings'))['earnings__sum']), 'team': player.get_current_team(), 'total': count_winloss_player(matches, player), 'vp': count_matchup_player(matches, player, P), 'vt': count_matchup_player(matches, player, T), 'vz': count_matchup_player(matches, player, Z), 'totalf': count_winloss_player(recent, player), 'vpf': count_matchup_player(recent, player, P), 'vtf': count_matchup_player(recent, player, T), 'vzf': count_matchup_player(recent, player, Z), }) base['riv_nem_vic'] = zip_longest(player.rivals, player.nemesis, player.victim) if player.country is not None: base['countryfull'] = transformations.cc_to_cn(player.country) # }}} # {{{ Recent matches matches = player.get_matchset( related=['rta', 'rtb', 'pla', 'plb', 'eventobj'])[0:10] if matches.exists(): base['matches'] = display_matches(matches, fix_left=player, ratings=True) # }}} # {{{ Team memberships team_memberships = list( player.groupmembership_set.filter( group__is_team=True).select_related('group')) team_memberships.sort(key=lambda t: t.id, reverse=True) team_memberships.sort(key=meandate, reverse=True) team_memberships.sort(key=lambda t: t.current, reverse=True) base['teammems'] = team_memberships # }}} # {{{ If the player has at least one rating if player.current_rating: ratings = total_ratings(player.rating_set.filter( period__computed=True)).select_related('period') base.update({ 'highs': ( ratings.latest('rating'), ratings.latest('tot_vp'), ratings.latest('tot_vt'), ratings.latest('tot_vz'), ), 'recentchange': player.get_latest_rating_update(), 'firstrating': ratings.earliest('period'), 'rating': player.current_rating, }) if player.current_rating.decay >= INACTIVE_THRESHOLD: base['messages'].append( Message(msg_inactive % player.tag, 'Inactive', type=Message.INFO)) base['charts'] = base['recentchange'].period_id > base[ 'firstrating'].period_id else: base['messages'].append( Message(_('%s has no rating yet.') % player.tag, type=Message.INFO)) base['charts'] = False # }}} # {{{ If the player has enough games to make a chart if base['charts']: ratings = (total_ratings( player.rating_set.filter( period_id__lte=base['recentchange'].period_id)).select_related( 'period').prefetch_related('prev__rta', 'prev__rtb').order_by('period')) # {{{ Add stories and other extra information earliest = base['firstrating'] latest = base['recentchange'] # Look through team changes teampoints = [] for mem in base['teammems']: if mem.start and earliest.period.end < mem.start < latest.period.end: teampoints.append({ 'date': mem.start, 'rating': interp_rating(mem.start, ratings), 'data': [{ 'date': mem.start, 'team': mem.group, 'jol': _('joins') }], }) if mem.end and earliest.period.end < mem.end < latest.period.end: teampoints.append({ 'date': mem.end, 'rating': interp_rating(mem.end, ratings), 'data': [{ 'date': mem.end, 'team': mem.group, 'jol': _('leaves') }], }) teampoints.sort(key=lambda p: p['date']) # Condense if team changes happened within 14 days cur = 0 while cur < len(teampoints) - 1: if (teampoints[cur + 1]['date'] - teampoints[cur]['date']).days <= 14: teampoints[cur]['data'].append(teampoints[cur + 1]['data'][0]) del teampoints[cur + 1] else: cur += 1 # Sort first by date, then by joined/left for point in teampoints: point['data'].sort(key=lambda a: a['jol'], reverse=True) point['data'].sort(key=lambda a: a['date']) # Look through stories stories = player.story_set.all().select_related('event') for s in stories: if earliest.period.start < s.date < latest.period.start: s.rating = interp_rating(s.date, ratings) else: s.skip = True # }}} base.update({ 'ratings': add_counts(ratings), 'patches': PATCHES, 'stories': stories, 'teampoints': teampoints, }) else: base['messages'].append( Message(msg_nochart % player.tag, type=Message.INFO)) # }}} return render_to_response('player.djhtml', base)
def adjustment(request, player_id, period_id): # {{{ Get objects period = get_object_or_404(Period, id=period_id, computed=True) player = get_object_or_404(Player, id=player_id) rating = get_object_or_404(Rating, player=player, period=period) base = base_ctx("Ranking", "Adjustments", request, context=player) base.update( { "period": period, "player": player, "rating": rating, "prevlink": etn(lambda: player.rating_set.filter(period__lt=period, decay=0).latest("period")), "nextlink": etn(lambda: player.rating_set.filter(period__gt=period, decay=0).earliest("period")), } ) # }}} # {{{ Matches matches = player.get_matchset(related=["rta", "rtb", "pla", "plb", "eventobj"]).filter(period=period) # If there are no matches, we don't need to continue if not matches.exists(): return render_to_response("ratingdetails.djhtml", base) base.update( { "matches": display_matches(matches, fix_left=player, ratings=True), "has_treated": False, "has_nontreated": False, } ) # }}} # {{{ Perform calculations tot_rating = {"M": 0.0, "P": 0.0, "T": 0.0, "Z": 0.0} ngames = {"M": 0.0, "P": 0.0, "T": 0.0, "Z": 0.0} expwins = {"M": 0.0, "P": 0.0, "T": 0.0, "Z": 0.0} nwins = {"M": 0.0, "P": 0.0, "T": 0.0, "Z": 0.0} for m in base["matches"]: if not m["match"].treated: base["has_nontreated"] = True continue base["has_treated"] = True total_score = m["pla"]["score"] + m["plb"]["score"] scale = sqrt(1 + m["pla"]["dev"] ** 2 + m["plb"]["dev"] ** 2) expected = total_score * cdf(m["pla"]["rating"] - m["plb"]["rating"], scale=scale) ngames["M"] += total_score tot_rating["M"] += m["plb"]["rating"] * total_score expwins["M"] += expected nwins["M"] += m["pla"]["score"] vs_races = [m["plb"]["race"]] if m["plb"]["race"] in "PTZ" else "PTZ" weight = 1 / len(vs_races) for r in vs_races: ngames[r] += weight * total_score tot_rating[r] += weight * m["plb"]["rating"] * total_score expwins[r] += weight * expected nwins[r] += weight * m["pla"]["score"] for r in "MPTZ": if ngames[r] > 0: tot_rating[r] /= ngames[r] base.update({"ngames": ngames, "tot_rating": tot_rating, "expwins": expwins, "nwins": nwins}) # }}} return render_to_response("ratingdetails.djhtml", base)
def player(request, player_id): # {{{ Get player object and base context, generate messages and make changes if needed player = get_object_or_404(Player, id=player_id) base = base_ctx("Ranking", "Summary", request, context=player) if request.method == "POST" and "modplayer" in request.POST and base["adm"]: modform = PlayerModForm(request) base["messages"] += modform.update_player(player) else: modform = PlayerModForm(player=player) base["messages"] += generate_messages(player) # }}} # {{{ Various easy data matches = player.get_matchset() recent = matches.filter(date__gte=(date.today() - relativedelta(months=2))) base.update( { "player": player, "modform": modform, "first": etn(lambda: matches.earliest("date")), "last": etn(lambda: matches.latest("date")), "totalmatches": matches.count(), "offlinematches": matches.filter(offline=True).count(), "aliases": player.alias_set.all(), "earnings": ntz(player.earnings_set.aggregate(Sum("earnings"))["earnings__sum"]), "team": player.get_current_team(), "total": count_winloss_player(matches, player), "vp": count_matchup_player(matches, player, P), "vt": count_matchup_player(matches, player, T), "vz": count_matchup_player(matches, player, Z), "totalf": count_winloss_player(recent, player), "vpf": count_matchup_player(recent, player, P), "vtf": count_matchup_player(recent, player, T), "vzf": count_matchup_player(recent, player, Z), } ) riv = player.rivals or [] nem = player.nemesis or [] vic = player.victim or [] base["riv_nem_vic"] = zip_longest(riv, nem, vic) if player.country is not None: base["countryfull"] = transformations.cc_to_cn(player.country) # }}} # {{{ Recent matches matches = player.get_matchset(related=["rta", "rtb", "pla", "plb", "eventobj"])[0:10] if matches.exists(): base["matches"] = display_matches(matches, fix_left=player, ratings=True) # }}} # {{{ Team memberships team_memberships = list(player.groupmembership_set.filter(group__is_team=True).select_related("group")) team_memberships.sort(key=lambda t: t.id, reverse=True) team_memberships.sort(key=meandate, reverse=True) team_memberships.sort(key=lambda t: t.current, reverse=True) base["teammems"] = team_memberships # }}} # {{{ If the player has at least one rating if player.current_rating: ratings = total_ratings(player.rating_set.filter(period__computed=True)).select_related("period") base.update( { "highs": ( ratings.latest("rating"), ratings.latest("tot_vp"), ratings.latest("tot_vt"), ratings.latest("tot_vz"), ), "recentchange": player.get_latest_rating_update(), "firstrating": ratings.earliest("period"), "rating": player.current_rating, } ) if player.current_rating.decay >= INACTIVE_THRESHOLD: base["messages"].append(Message(msg_inactive % player.tag, "Inactive", type=Message.INFO)) base["charts"] = base["recentchange"].period_id > base["firstrating"].period_id else: base["messages"].append(Message(_("%s has no rating yet.") % player.tag, type=Message.INFO)) base["charts"] = False # }}} # {{{ If the player has enough games to make a chart if base["charts"]: ratings = ( total_ratings(player.rating_set.filter(period_id__lte=base["recentchange"].period_id)) .select_related("period__end") .prefetch_related("prev__rta", "prev__rtb") .order_by("period") ) # {{{ Add stories and other extra information earliest = base["firstrating"] latest = base["recentchange"] # Look through team changes teampoints = [] for mem in base["teammems"]: if mem.start and earliest.period.end < mem.start < latest.period.end: teampoints.append( { "date": mem.start, "rating": interp_rating(mem.start, ratings), "data": [{"date": mem.start, "team": mem.group, "jol": _("joins")}], } ) if mem.end and earliest.period.end < mem.end < latest.period.end: teampoints.append( { "date": mem.end, "rating": interp_rating(mem.end, ratings), "data": [{"date": mem.end, "team": mem.group, "jol": _("leaves")}], } ) teampoints.sort(key=lambda p: p["date"]) # Condense if team changes happened within 14 days cur = 0 while cur < len(teampoints) - 1: if (teampoints[cur + 1]["date"] - teampoints[cur]["date"]).days <= 14: teampoints[cur]["data"].append(teampoints[cur + 1]["data"][0]) del teampoints[cur + 1] else: cur += 1 # Sort first by date, then by joined/left for point in teampoints: point["data"].sort(key=lambda a: a["jol"], reverse=True) point["data"].sort(key=lambda a: a["date"]) # Look through stories stories = player.story_set.all().select_related("event__fullname") for s in stories: if earliest.period.start < s.date < latest.period.start: s.rating = interp_rating(s.date, ratings) else: s.skip = True # }}} base.update({"ratings": add_counts(ratings), "patches": PATCHES, "stories": stories, "teampoints": teampoints}) else: base["messages"].append(Message(msg_nochart % player.tag, type=Message.INFO)) # }}} return render_to_response("player.djhtml", base)
def events(request, event_id=None): # {{{ Get base context, redirect if necessary if 'goto' in request.GET: return redirect('/results/events/' + request.GET['goto']) base = base_ctx('Results', 'By Event', request) # }}} # {{{ Display the main table if event ID is not given if event_id is None: root_events = (Event.objects.annotate( num_uplinks=Count("uplink")).filter( num_uplinks=1).order_by('name').only('id', 'name', 'big', 'category', 'fullname')) base.update({ 'bigs': (list(root_events.filter(big=True, category=CAT_INDIVIDUAL)) + list(root_events.filter(big=True, category=CAT_TEAM)) + list(root_events.filter(big=True, category=CAT_FREQUENT))), 'smalls': (list( root_events.filter(big=False, category=CAT_INDIVIDUAL).order_by('name')) + list( root_events.filter(big=False, category=CAT_TEAM).order_by('name')) + list( root_events.filter(big=False, category=CAT_FREQUENT).order_by('name'))) }) base['messages'].append( Message(_( 'The events are organized in a hierarchical fashion. Thus, all GSL tournaments ' 'are filed under GSL, all Code S under their respective seasons, all groups under ' 'their respective Code S event, and so on.'), type=Message.INFO)) return render_to_response('events.djhtml', base) # }}} # {{{ Get object, generate messages, and ensure big is set. Find familial relationships. event = get_object_or_404(Event, id=event_id) base['messages'] += generate_messages(event) matches = event.get_matchset() if matches.count() > 200 and not event.big: event.set_big(True) base.update({ 'event': event, 'siblings': event.get_parent().get_immediate_children().exclude( id=event.id) if event.get_parent() else None, 'path': event.get_ancestors(id=True), 'children': event.get_immediate_children(), }) # }}} # {{{ Make forms if base['adm']: def check_form(formname, cl, check): if request.method == 'POST' and check in request.POST: f = cl(request=request, event=event) base['messages'] += f.update_event(event) else: f = cl(event=event) base[formname] = f check_form('form', EventModForm, 'modevent') check_form('addform', AddForm, 'addevent') if event.has_children(): check_form('reorderform', ReorderForm, 'reorder') if event.type == TYPE_EVENT: check_form('ppform', PrizepoolModForm, 'modpp') if not event.has_children() and event.get_immediate_matchset().exists( ): check_form('stform', StoriesForm, 'modstory') # }}} # {{{ Prizepool information for the public total_earnings = Earnings.objects.filter(event__uplink__parent=event) local_earnings = Earnings.objects.filter(event=event) ranked_prize = local_earnings.exclude(placement=0)\ .order_by('-earnings', 'placement') unranked_prize = list( local_earnings.filter(placement=0).order_by('-earnings')) placements = get_placements(event) prize_pool_table = list() for k, g in groupby(ranked_prize, key=lambda x: x.earnings): gl = list(g) prize_pool_table.append((k, placements[k], gl, len(gl))) if len(prize_pool_table) > 0: base['ranked_prize'] = prize_pool_table if len(unranked_prize) > 0: base['unranked_prize'] = unranked_prize currencies = list( {r['currency'] for r in total_earnings.values('currency').distinct()}) base.update({ 'prizepool': total_earnings.aggregate(Sum('earnings'))['earnings__sum'], 'nousdpp': len(currencies) > 1 or len(currencies) == 1 and currencies[0] != 'USD', 'prizepoolorig': [{ 'pp': total_earnings.filter(currency=k).aggregate( Sum('origearnings'))['origearnings__sum'], 'cur': k, } for k in currencies], }) # }}} # {{{ Other easy statistics add_links = request.user.is_authenticated() and request.user.is_staff base.update({ 'game': etn(lambda: dict(GAMES)[matches.values('game').distinct()[0]['game']]), 'nmatches': matches.count(), 'ngames': sum(count_winloss_games(matches)), 'pvp_games': count_mirror_games(matches, 'P'), 'tvt_games': count_mirror_games(matches, 'T'), 'zvz_games': count_mirror_games(matches, 'Z'), 'matches': display_matches( matches.prefetch_related('message_set').prefetch_related( 'pla', 'plb', 'eventobj').annotate(Count('eventobj__match')).order_by( '-eventobj__latest', '-eventobj__idx', '-date', '-id')[0:200], eventcount=True, add_links=add_links), 'nplayers': Player.objects.filter( Q(id__in=matches.values('pla')) | Q(id__in=matches.values('plb'))).count(), }) offlines = list(matches.values('offline').distinct()) if len(offlines) > 1: base['offline'] = _('Both') elif len(offlines) == 1: base['offline'] = _('Offline') if offlines[0]['offline'] else _( 'Online') base['pvt_wins'], base['pvt_loss'] = count_matchup_games(matches, 'P', 'T') base['pvz_wins'], base['pvz_loss'] = count_matchup_games(matches, 'P', 'Z') base['tvz_wins'], base['tvz_loss'] = count_matchup_games(matches, 'T', 'Z') base['tot_mirror'] = base['pvp_games'] + base['tvt_games'] + base[ 'zvz_games'] # }}} return render_to_response('eventres.djhtml', base)
except: print('[%s] No such period' % str(datetime.now()), flush=True) sys.exit(1) print('[{0}] Recomputing #{1} ({2} -> {3})'.format(str(datetime.now()), period.id, period.start, period.end), flush=True) # If someone adds an early match while the system is updating, this check causes everything to be aborted # Since the master update script will start from the earliest "dirty" period anyway, it's not necessary #if Period.objects.filter(id__lt=period.id).filter(Q(computed=False) | Q(needs_recompute=True)).exists(): #print('[%s] Earlier period not refreshed. Aborting.' % str(datetime.now()), flush=True) #sys.exit(1) prev = etn(lambda: Period.objects.get(id=period.id - 1)) # }}} # {{{ Get players players = {} if prev: for r in Rating.objects.filter(period=prev).select_related( 'player').prefetch_related('prevrating'): players[r.player_id] = { 'player': r.player, 'rating': r, 'prev_ratings': { 'M': r.rating, 'P': r.rating_vp, 'T': r.rating_vt,