Пример #1
0
    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'),
        )
Пример #2
0
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
Пример #3
0
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
Пример #4
0
    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'),
        )
Пример #5
0
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)
Пример #6
0
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)
Пример #7
0
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)
Пример #8
0
# {{{ 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': [],
        }
Пример #9
0
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)
Пример #10
0
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)
Пример #11
0
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)
Пример #12
0
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)
Пример #13
0
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)
Пример #14
0
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)
Пример #15
0
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,