예제 #1
0
    def GET(self):
        web.header("Content-Type", "text/html; charset=utf-8")  

        query_dict = dict(urlparse.parse_qsl(web.ctx.env['QUERY_STRING']))
        target_player = query_dict['player'].decode('utf-8')

        db = utils.get_mongo_database()
        games = db.games
        norm_target_player = norm_name(target_player)
        games_coll = games.find({'players': norm_target_player})

        leaderboard_history_result = db.leaderboard_history.find_one(
            {'_id': norm_target_player})
        leaderboard_history = None
        if leaderboard_history_result:
            leaderboard_history = leaderboard_history_result['history']

        game_list = []
        aliases = set()

        overall_record = RecordSummary()
        rec_by_game_size = collections.defaultdict(RecordSummary)
        rec_by_date = collections.defaultdict(RecordSummary)
        rec_by_turn_order =  collections.defaultdict(RecordSummary)

        expansion_dist = collections.defaultdict(float)
        expansion_win_points = collections.defaultdict(float)

        date_buckets = [1, 3, 5, 10]
        for g in games_coll:
            game_val = game.Game(g)
            if game_val.dubious_quality():
                continue
            all_player_names = game_val.all_player_names()
            norm_names = map(norm_name, all_player_names)
            if len(set(norm_names)) != len(all_player_names):
                continue
            target_player_cur_name_cand = [
                n for n in all_player_names
                if norm_name(n) == norm_target_player]
            if len(target_player_cur_name_cand) != 1:
                continue
            game_list.append(game_val)
            target_player_cur_name = target_player_cur_name_cand[0]
            aliases.add(target_player_cur_name)

            pd = game_val.get_player_deck(target_player_cur_name)
            wp = pd.WinPoints()

            res = game_val.win_loss_tie(target_player_cur_name)
            overall_record.record_result(res, wp)
            game_len = len(game_val.get_player_decks())
            rec_by_game_size[game_len].record_result(res, wp)

            _ord = pd.TurnOrder()
            rec_by_turn_order[_ord].record_result(res, wp)
            for delta in date_buckets:
                _padded = (game_val.date() +
                           datetime.timedelta(days = delta))
                delta_padded_date = _padded.date()
                today = datetime.datetime.now().date()
                if delta_padded_date >= today:
                    rec_by_date[delta].record_result(res, wp)

            for (ex, wt) in game_val.get_expansion_weight().items():
                expansion_dist[ex] += wt
                expansion_win_points[ex] += wt * wp


        #TODO: a good choice for a template like jinja2
        ret = standard_heading("CouncilRoom.com: Dominion Stats: %s" % 
                               target_player)

        ret += '<form action="/player" method="get">'
        ret += '<span class="subhead">Profile for %s</span>' % target_player

        leaderboard_history_most_recent = (leaderboard_history[-1] if 
                                           leaderboard_history else None)
        if leaderboard_history_most_recent:
            level = (leaderboard_history_most_recent[1] - 
                     leaderboard_history_most_recent[2])
            level = int(max(math.floor(level), 0))
            ret += '<span class="level">Level ' + str(level) + '</span>'

        ret += '<span class="search2">'
        ret += """
               Search for another player:
               <input type="text" name="player" style="width:100px;" />
               <input type="submit" value="View Stats!" />
               </span></form><br><br>
               """

        if len(aliases) > 1:
            ret += 'Aliases: ' + ', '.join(aliases) + '\n'


        ret += render_record_table('Record by game size', overall_record,
                                   rec_by_game_size,
                                   lambda game_size: '%d players' % game_size)
        ret += render_record_table('Recent Record', overall_record,
                                   rec_by_date,
                                   lambda num_days: 'Last %d days' % num_days)
        ret += render_record_table('Record by turn order', overall_record,
                                   rec_by_turn_order,
                                   lambda pos: 'Table position %d' % pos)

        ret += '<div style="clear: both;">&nbsp;</div>'
        ret += '<div class="cardborder yellow"><h3>Expansion Data</h3><table class="stats">'
        ret += '<tr><th>Card Set<th>Avg. Cards<br/> Per Kingdom<th>Weighted<br/> Win Points<th>Favor'

        for (ex, weight) in sorted(expansion_dist.iteritems(), 
                      key=operator.itemgetter(1), reverse=True):

            if ex == 'Fan':
                continue

            wp = expansion_win_points[ex] / weight
            average = overall_record.average_win_points()

            ret += '<tr><th>%s</th>'%ex
            ret += '<td>%.2f</td>'% (weight * 10. / len(game_list))
            ret += '<td>%.2f<td>' % wp
            if average > 0:
                ret += '<td>%.2f%%</td>'% ( (wp - average) * 100. / average )
            else:
                ret += '<td>0</td>' 
        ret += '</table></div>'

        ret += '<div style="clear: both;">&nbsp;</div>'

        ret += goals.MaybeRenderGoals(db, norm_target_player)

        ret += '<A HREF="/popular_buys?player=%s"><h2>Stats by card</h2></A>\n' % target_player
        ret += '<A HREF="/games_by_opponent?player=%s"><h2>Record by opponent</h2></A>\n' % target_player

        if leaderboard_history:
            render = web.template.render('')
            ret += str(render.player_page_leaderboard_history_template(
                    json.dumps(leaderboard_history)))

        ret += '<h2>Most recent games</h2>\n'
        game_list.sort(key = game.Game.get_id, reverse = True)
        qm = query_matcher.QueryMatcher(p1_name=target_player)
        for g in game_list[:3]:
            ret += (query_matcher.GameMatcher(g, qm).display_game_snippet() +
                    '<br>')

        ret += ('<A HREF="/search_result?p1_name=%s">(See more)</A>' % 
                target_player)
        ret += '</body></html>'

        return ret
예제 #2
0
    def GET(self):
        web.header("Content-Type", "text/html; charset=utf-8")  

        query_dict = dict(urlparse.parse_qsl(web.ctx.env['QUERY_STRING']))
        target_player = query_dict['player'].decode('utf-8')

        db = utils.get_mongo_database()
        game_stats = db.game_stats
        norm_target_player = norm_name(target_player)
        games_coll = game_stats.find({compkey('_id', NAME): norm_target_player})

        leaderboard_history_result = db.leaderboard_history.find_one(
            {'_id': norm_target_player})
        leaderboard_history = None
        if leaderboard_history_result:
            leaderboard_history = leaderboard_history_result['history']

        game_list = []
        aliases = set()

        overall_record = RecordSummary()
        rec_by_game_size = collections.defaultdict(RecordSummary)
        rec_by_date = collections.defaultdict(RecordSummary)
        rec_by_turn_order =  collections.defaultdict(RecordSummary)

        expansion_dist = collections.defaultdict(float)
        expansion_win_points = collections.defaultdict(float)

        date_buckets = [1, 3, 5, 10]
        cutoffs = {}
        for delta in date_buckets:
            cutoff = datetime.datetime.now().date() + datetime.timedelta(days = -delta)
            cutoffs[delta] = cutoff.strftime("%Y%m%d")

        # NOTE: This assumes that game IDs can be lexically sorted
        # into temporal order
        for g in games_coll.sort('_id', pymongo.DESCENDING):
            g_id = g['_id']['game_id']
            game_list.append(g_id)

            name = g['_id'][NAME]

            # TODO: Turn this back. The concept of aliases only comes
            #into play when two different "real" player names both
            #normalize to the same "normalized" player name.
            # aliases.add(target_player_cur_name)

            wp = g[WIN_POINTS]
            res = g[RESULT]
            overall_record.record_result(res, wp)
            game_len = len( g[PLAYERS] ) + 1
            rec_by_game_size[game_len].record_result(res, wp)

            _ord = g[ORDER]
            rec_by_turn_order[_ord].record_result(res, wp)
            for delta in date_buckets:
                if g['game_date'] >= cutoffs[delta]:
                    rec_by_date[delta].record_result(res, wp)
            supply = [dominioncards.index_to_card(i) for i in g[SUPPLY]]

            for (ex, wt) in dominioncards.get_expansion_weight(supply).items():
                expansion_dist[ex] += wt
                expansion_win_points[ex] += wt * wp

        #TODO: a good choice for a template like jinja2
        ret = standard_heading("CouncilRoom.com: Dominion Stats: %s" % 
                               target_player)

        ret += '<form action="/player" method="get">'
        ret += '<span class="subhead">Profile for %s</span>' % target_player

        leaderboard_history_most_recent = (leaderboard_history[-1] if 
                                           leaderboard_history else None)
        if leaderboard_history_most_recent:
            level = (leaderboard_history_most_recent[1] - 
                     leaderboard_history_most_recent[2])
            level = int(max(math.floor(level), 0))
            ret += '<span class="level">Level ' + str(level) + '</span>'

        ret += '<span class="search2">'
        ret += """
               Search for another player:
               <input type="text" name="player" style="width:100px;" />
               <input type="submit" value="View Stats!" />
               </span></form><br><br>
               """

        if len(aliases) > 1:
            ret += 'Aliases: ' + ', '.join(aliases) + '\n'


        ret += render_record_table('Record by game size', overall_record,
                                   rec_by_game_size,
                                   lambda game_size: '%d players' % game_size)
        ret += render_record_table('Recent Record', overall_record,
                                   rec_by_date,
                                   lambda num_days: 'Last %d days' % num_days)
        ret += render_record_table('Record by turn order', overall_record,
                                   rec_by_turn_order,
                                   lambda pos: 'Table position %d' % pos)

        ret += '<div style="clear: both;">&nbsp;</div>'
        ret += '<div class="cardborder yellow"><h3>Expansion Data</h3><table class="stats">'
        ret += '<tr><th>Card Set<th>Avg. Cards<br/> Per Kingdom<th>Weighted<br/> Win Points<th>Favor'

        for (ex, weight) in sorted(expansion_dist.iteritems(), 
                      key=operator.itemgetter(1), reverse=True):

            if ex == 'Fan':
                continue

            wp = expansion_win_points[ex] / weight
            average = overall_record.average_win_points()

            ret += '<tr><th>%s</th>'%ex
            ret += '<td>%.2f</td>'% (weight * 10. / len(game_list))
            ret += '<td>%.2f<td>' % wp
            if average > 0:
                ret += '<td>%.2f%%</td>'% ( (wp - average) * 100. / average )
            else:
                ret += '<td>0</td>' 
        ret += '</table></div>'

        ret += '<div style="clear: both;">&nbsp;</div>'

        ret += goals.MaybeRenderGoals(db, norm_target_player)

        ret += '<A HREF="/popular_buys?player=%s"><h2>Stats by card</h2></A>\n' % target_player
        ret += '<A HREF="/games_by_opponent?player=%s"><h2>Record by opponent</h2></A>\n' % target_player

        if leaderboard_history:
            render = web.template.render('')
            ret += str(render.player_page_leaderboard_history_template(
                    json.dumps(leaderboard_history)))

        ret += '<h2>Most recent games</h2>\n'
        qm = query_matcher.QueryMatcher(p1_name=target_player)
        goko_games = [g for g in game_list if '.txt' in game_list]
        if len(goko_games) > 2:
            goko_games.sort(reverse=True)
            most_recent = goko_games[:3]
        else:
            most_recent = game_list[:3]
        for g_id in most_recent:
            g = db.games.find_one({'_id': g_id})
            game_val = game.Game(g)
            ret += (query_matcher.GameMatcher(game_val, qm).display_game_snippet() +
                    '<br>')

        ret += ('<A HREF="/search_result?p1_name=%s">(See more)</A>' % 
                target_player)
        ret += '</body></html>'

        return ret
예제 #3
0
    def GET(self):
        web.header("Content-Type", "text/html; charset=utf-8")  

        query_dict = dict(urlparse.parse_qsl(web.ctx.env['QUERY_STRING']))
        target_player = query_dict['player'].decode('utf-8')

        db = utils.get_mongo_database()
        games = db.games
        norm_target_player = norm_name(target_player)
        games_coll = games.find({'players': norm_target_player})

        keyed_by_opp = collections.defaultdict(list)
        real_name_usage = collections.defaultdict(
            lambda: collections.defaultdict(int))

        game_list = []
        aliases = set()

        overall_record = RecordSummary()
        rec_by_game_size = collections.defaultdict(RecordSummary)
        rec_by_date = collections.defaultdict(RecordSummary)
        rec_by_turn_order =  collections.defaultdict(RecordSummary)

        date_buckets = ( 1, 3, 5, 10 )
        for g in games_coll:
            game_val = game.Game(g)
            if game_val.dubious_quality():
                continue
            all_player_names = game_val.all_player_names()
            norm_names = map(norm_name, all_player_names)
            if len(set(norm_names)) != len(all_player_names):
                continue
            target_player_cur_name_cand = [
                n for n in all_player_names
                if norm_name(n) == norm_target_player]
            if len(target_player_cur_name_cand) != 1:
                continue
            game_list.append(game_val)
            target_player_cur_name = target_player_cur_name_cand[0]
            aliases.add(target_player_cur_name)
            for p in game_val.get_player_decks():
                if p.name() != target_player_cur_name:
                    other_norm_name = norm_name(p.name())
                    keyed_by_opp[other_norm_name].append(
                        (p.name(), target_player_cur_name, game_val))
                    real_name_usage[other_norm_name][p.name()] += 1
                else:
                    #this is getting fidgety about 80 chars, which sometimes
                    #can mean that it's getting too nested and could use a
                    #rethink
                    res = game_val.win_loss_tie(p.name())
                    overall_record.record_result(res, p.WinPoints())
                    game_len = len(game_val.get_player_decks())
                    rec_by_game_size[game_len].record_result(res,
                                                             p.WinPoints())
                    _ord = p.TurnOrder()
                    rec_by_turn_order[_ord].record_result(res, p.WinPoints())
                    for delta in date_buckets:
                        _padded = (game_val.date() +
                                   datetime.timedelta(days = delta))
                        delta_padded_date = _padded.date()
                        today = datetime.datetime.now().date()
                        if delta_padded_date >= today:
                            rec_by_date[delta].record_result(res,
                                                             p.WinPoints())

        keyed_by_opp_list = keyed_by_opp.items()
        keyed_by_opp_list.sort(key = lambda x: (-len(x[1]), x[0]))
        #TODO: a good choice for a template like jinja2
        ret = ('<html><head><title>CouncilRoom.com: Dominion Stats: '
               '%s</title></head>\n' % target_player)
        ret += '<body><A HREF="/">Back to CouncilRoom.com</A><BR><BR>'

        ret += """
               Search for another player: <form action='/player' method='get'>
               <input type="text" name="player" style="width:100px;" />
               <input type="submit" value="Submit" />
               </form><hr>
               """
        ret += '<h2>CouncilRoom Profile for %s</h2><BR>' % target_player

        if len(aliases) > 1:
            ret += 'Aliases: ' + ', '.join(aliases) + '<br>\n'


        ret += render_record_table('Record by game size', overall_record,
                                   rec_by_game_size,
                                   lambda game_size: '%d players' % game_size)
        ret += render_record_table('Recent Record', overall_record,
                                   rec_by_date,
                                   lambda num_days: 'Last %d days' % num_days)
        ret += render_record_table('Record by turn order', overall_record,
                                   rec_by_turn_order,
                                   lambda pos: 'Table position %d' % pos)

        ret += '<div style="clear: both;">&nbsp;</div>'

        ret += goals.MaybeRenderGoals(db, norm_target_player)

        ret += '<A HREF="/popular_buys?player=%s"><h2>Stats by card</h2></A><BR>\n' % target_player

        ret += '<h2>Most recent games</h2>\n'
        game_list.sort(key = game.Game.get_id, reverse = True)
        qm = query_matcher.QueryMatcher(p1_name=target_player)
        for g in game_list[:3]:
            ret += (query_matcher.GameMatcher(g, qm).display_game_snippet() +
                    '<br>')

        ret += ('<A HREF="/search_result?p1_name=%s">(See more)</A>' % 
                target_player)

        ret += '<h2>Record by opponent</h2>'
        ret += '<table border=1>'
        ret += '<tr><td>Opponent</td><td>Record</td></tr>'
        for opp_norm_name, game_list in keyed_by_opp_list:
            record = [0, 0, 0]
            for opp_name, tgt_player_curname, g in game_list:
                record[g.win_loss_tie(tgt_player_curname, opp_name)] += 1
            ret += '<tr>'

            # Get most freq used name for opponent
            #TODO: lambdas can be switched to itemgetters
            opp_cannon_name = max(real_name_usage[opp_norm_name].iteritems(),
                                  key=lambda x: x[1])[0]

            row_span = (len(game_list) - 1) / 10 + 1
            ret += '<td rowspan=%d>%s</td>' % (
                row_span, game.PlayerDeck.PlayerLink(opp_cannon_name))
            ret += '<td rowspan=%d>%d-%d-%d</td>' % (row_span, record[0],
                                                     record[1], record[2])
            for idx, (opp_name, tgt_player_curname, g) in enumerate(
                game_list):
                if idx % 10 == 0 and idx > 0:
                    ret += '</tr><tr>'
                ret += g.short_render_cell_with_perspective(tgt_player_curname,
                                                            opp_name)
            ret += '</tr>\n'
        ret += '</table></body></html>'
        return ret
예제 #4
0
    def GET(self):
        web.header("Content-Type", "text/html; charset=utf-8")

        query_dict = dict(urlparse.parse_qsl(web.ctx.env['QUERY_STRING']))
        target_player = query_dict['player'].decode('utf-8')

        db = utils.get_mongo_database()
        games = db.games
        norm_target_player = NormName(target_player)
        games_coll = games.find({'players': norm_target_player})

        keyed_by_opp = collections.defaultdict(list)
        real_name_usage = collections.defaultdict(
            lambda: collections.defaultdict(int))

        game_list = []
        aliases = set()

        overall_record = RecordSummary()
        rec_by_game_size = collections.defaultdict(RecordSummary)
        rec_by_date = collections.defaultdict(RecordSummary)
        rec_by_turn_order = collections.defaultdict(RecordSummary)

        date_buckets = (1, 3, 5, 10)
        for g in games_coll:
            game_val = game.Game(g)
            if game_val.DubiousQuality():
                continue
            all_player_names = game_val.AllPlayerNames()
            norm_names = map(NormName, all_player_names)
            if len(set(norm_names)) != len(all_player_names):
                continue
            target_player_cur_name_cand = [
                n for n in all_player_names
                if NormName(n) == norm_target_player
            ]
            if len(target_player_cur_name_cand) != 1:
                continue
            game_list.append(game_val)
            target_player_cur_name = target_player_cur_name_cand[0]
            aliases.add(target_player_cur_name)
            for p in game_val.PlayerDecks():
                if p.Name() != target_player_cur_name:
                    other_norm_name = NormName(p.Name())
                    keyed_by_opp[other_norm_name].append(
                        (p.Name(), target_player_cur_name, game_val))
                    real_name_usage[other_norm_name][p.Name()] += 1
                else:
                    res = game_val.WinLossTie(p.Name())
                    overall_record.RecordResult(res, p.WinPoints())
                    game_len = len(game_val.PlayerDecks())
                    rec_by_game_size[game_len].RecordResult(res, p.WinPoints())
                    rec_by_turn_order[p.TurnOrder()].RecordResult(
                        res, p.WinPoints())
                    for delta in date_buckets:
                        delta_padded_date = (
                            game_val.Date() +
                            datetime.timedelta(days=delta)).date()
                        today = datetime.datetime.now().date()
                        if (delta_padded_date >= today):
                            rec_by_date[delta].RecordResult(res, p.WinPoints())

        keyed_by_opp_list = keyed_by_opp.items()
        keyed_by_opp_list.sort(key=lambda x: (-len(x[1]), x[0]))

        ret = ('<html><head><title>CouncilRoom.com: Dominion Stats: '
               '%s</title></head>\n' % target_player)
        ret += '<body><A HREF="/">Back to CouncilRoom.com</A><BR><BR>'

        ret += """
	    Player: <form action='/player' method='get'>
		   <input type="text" name="player" style="width:100px;" />
		   <input type="submit" value="Submit" />
		</form>
		"""

        if len(aliases) > 1:
            ret += 'Player aliases: ' + ', '.join(aliases) + '<br>\n'

        ret += RenderRecordTable('Record by game size', overall_record,
                                 rec_by_game_size,
                                 lambda game_size: '%d players' % game_size)
        ret += RenderRecordTable('Recent Record', overall_record, rec_by_date,
                                 lambda num_days: 'Last %d days' % num_days)
        ret += RenderRecordTable('Record by turn order', overall_record,
                                 rec_by_turn_order,
                                 lambda pos: 'Table position %d' % pos)

        ret += '<div style="clear: both;">&nbsp;</div>'

        ret += goals.MaybeRenderGoals(db, norm_target_player)

        ret += '<h2>Most recent games</h2>\n'
        game_list.sort(key=game.Game.Id, reverse=True)
        qm = query_matcher.QueryMatcher(p1_name=target_player)
        for g in game_list[:3]:
            ret += (query_matcher.GameMatcher(g, qm).DisplayGameSnippet() +
                    '<br>')

        ret += ('<A HREF="/search_result?p1_name=%s">(See more)</A>' %
                target_player)

        ret += '<h2>Record by opponent</h2>'
        ret += '<table border=1>'
        ret += '<tr><td>Opponent</td><td>Record</td></tr>'
        for opp_norm_name, game_list in keyed_by_opp_list:
            record = [0, 0, 0]
            for opp_name, targ_player_cur_name, g in game_list:
                record[g.WinLossTie(targ_player_cur_name, opp_name)] += 1
            ret += '<tr>'

            opp_cannon_name = max(  # Get most freq used name for opponent
                real_name_usage[opp_norm_name].iteritems(),
                key=lambda x: x[1])[0]

            row_span = (len(game_list) - 1) / 10 + 1
            ret += '<td rowspan=%d>%s</td>' % (
                row_span, game.PlayerDeck.PlayerLink(opp_cannon_name))
            ret += '<td rowspan=%d>%d-%d-%d</td>' % (row_span, record[0],
                                                     record[1], record[2])
            for idx, (opp_name, targ_player_cur_name,
                      g) in enumerate(game_list):
                if idx % 10 == 0 and idx > 0:
                    ret += '</tr><tr>'
                ret += g.ShortRenderCellWithPerspective(
                    targ_player_cur_name, opp_name)
            ret += '</tr>\n'
        ret += '</table></body></html>'
        return ret
예제 #5
0
    def GET(self):
        web.header("Content-Type", "text/html; charset=utf-8")  

        query_dict = dict(urlparse.parse_qsl(web.ctx.env['QUERY_STRING']))
        target_player = query_dict['player'].decode('utf-8')

        db = utils.get_mongo_database()
        games = db.games
        norm_target_player = norm_name(target_player)
        games_coll = games.find({'players': norm_target_player})

        keyed_by_opp = collections.defaultdict(list)
        real_name_usage = collections.defaultdict(
            lambda: collections.defaultdict(int))

        game_list = []
        aliases = set()

        overall_record = RecordSummary()
        rec_by_game_size = collections.defaultdict(RecordSummary)
        rec_by_date = collections.defaultdict(RecordSummary)
        rec_by_turn_order =  collections.defaultdict(RecordSummary)

        date_buckets = ( 1, 3, 5, 10 )
        for g in games_coll:
            game_val = game.Game(g)
            if game_val.dubious_quality():
                continue
            all_player_names = game_val.all_player_names()
            norm_names = map(norm_name, all_player_names)
            if len(set(norm_names)) != len(all_player_names):
                continue
            target_player_cur_name_cand = [
                n for n in all_player_names
                if norm_name(n) == norm_target_player]
            if len(target_player_cur_name_cand) != 1:
                continue
            game_list.append(game_val)
            target_player_cur_name = target_player_cur_name_cand[0]
            aliases.add(target_player_cur_name)
            for p in game_val.get_player_decks():
                if p.name() != target_player_cur_name:
                    other_norm_name = norm_name(p.name())
                    keyed_by_opp[other_norm_name].append(
                        (p.name(), target_player_cur_name, game_val))
                    real_name_usage[other_norm_name][p.name()] += 1
                else:
                    #this is getting fidgety about 80 chars, which sometimes
                    #can mean that it's getting too nested and could use a
                    #rethink
                    res = game_val.win_loss_tie(p.name())
                    overall_record.record_result(res, p.WinPoints())
                    game_len = len(game_val.get_player_decks())
                    rec_by_game_size[game_len].record_result(res,
                                                             p.WinPoints())
                    _ord = p.TurnOrder()
                    rec_by_turn_order[_ord].record_result(res, p.WinPoints())
                    for delta in date_buckets:
                        _padded = (game_val.date() +
                                   datetime.timedelta(days = delta))
                        delta_padded_date = _padded.date()
                        today = datetime.datetime.now().date()
                        if delta_padded_date >= today:
                            rec_by_date[delta].record_result(res,
                                                             p.WinPoints())

        keyed_by_opp_list = keyed_by_opp.items()
        keyed_by_opp_list.sort(key = lambda x: (-len(x[1]), x[0]))
        #TODO: a good choice for a template like jinja2
	ret = standard_heading("CouncilRoom.com: Dominion Stats: %s" % target_player)

	ret += '<form action="/player" method="get">'
	ret += '<span class="subhead">Profile for %s</span>' % target_player
	ret += '<span class="search2">'
        ret += """
               Search for another player: 
               <input type="text" name="player" style="width:100px;" />
               <input type="submit" value="View Stats!" />
               </span></form><br><br>
               """

        if len(aliases) > 1:
            ret += 'Aliases: ' + ', '.join(aliases) + '\n'


        ret += render_record_table('Record by game size', overall_record,
                                   rec_by_game_size,
                                   lambda game_size: '%d players' % game_size)
        ret += render_record_table('Recent Record', overall_record,
                                   rec_by_date,
                                   lambda num_days: 'Last %d days' % num_days)
        ret += render_record_table('Record by turn order', overall_record,
                                   rec_by_turn_order,
                                   lambda pos: 'Table position %d' % pos)

        ret += '<div style="clear: both;">&nbsp;</div>'

        ret += goals.MaybeRenderGoals(db, norm_target_player)

        ret += '<A HREF="/popular_buys?player=%s"><h2>Stats by card</h2></A><BR>\n' % target_player

        ret += '<h2>Most recent games</h2>\n'
        game_list.sort(key = game.Game.get_id, reverse = True)
        qm = query_matcher.QueryMatcher(p1_name=target_player)
        for g in game_list[:3]:
            ret += (query_matcher.GameMatcher(g, qm).display_game_snippet() +
                    '<br>')

        ret += ('<A HREF="/search_result?p1_name=%s">(See more)</A>' % 
                target_player)

        ret += '<h2>Record by opponent</h2>'
        ret += '<table border=1>'
        ret += '<tr><td>Opponent</td><td>Record</td></tr>'
        for opp_norm_name, game_list in keyed_by_opp_list:
            record = [0, 0, 0]
            for opp_name, tgt_player_curname, g in game_list:
                record[g.win_loss_tie(tgt_player_curname, opp_name)] += 1
            ret += '<tr>'

            # Get most freq used name for opponent
            #TODO: lambdas can be switched to itemgetters
            opp_cannon_name = max(real_name_usage[opp_norm_name].iteritems(),
                                  key=lambda x: x[1])[0]

            row_span = (len(game_list) - 1) / 10 + 1
            ret += '<td rowspan=%d>%s</td>' % (
                row_span, game.PlayerDeck.PlayerLink(opp_cannon_name))
            ret += '<td rowspan=%d>%d-%d-%d</td>' % (row_span, record[0],
                                                     record[1], record[2])
            for idx, (opp_name, tgt_player_curname, g) in enumerate(
                game_list):
                if idx % 10 == 0 and idx > 0:
                    ret += '</tr><tr>'
                ret += g.short_render_cell_with_perspective(tgt_player_curname,
                                                            opp_name)
            ret += '</tr>\n'
        ret += '</table></body></html>'
        return ret
예제 #6
0
    def GET(self):
        web.header("Content-Type", "text/html; charset=utf-8")  

        query_dict = dict(urlparse.parse_qsl(web.ctx.env['QUERY_STRING']))
        target_player = query_dict['player'].decode('utf-8')

        db = utils.get_mongo_database()
        game_stats = db.game_stats
        norm_target_player = norm_name(target_player)
        games_coll = game_stats.find({compkey('_id', NAME): norm_target_player})

        leaderboard_history_result = db.leaderboard_history.find_one(
            {'_id': norm_target_player})
        leaderboard_history = None
        if leaderboard_history_result:
            leaderboard_history = leaderboard_history_result['history']

        game_list = []
        aliases = set()

        overall_record = RecordSummary()
        rec_by_game_size = collections.defaultdict(RecordSummary)
        rec_by_date = collections.defaultdict(RecordSummary)
        rec_by_turn_order =  collections.defaultdict(RecordSummary)

        expansion_dist = collections.defaultdict(float)
        expansion_win_points = collections.defaultdict(float)

        date_buckets = [1, 3, 5, 10]
        cutoffs = {}
        for delta in date_buckets:
            cutoff = datetime.datetime.now().date() + datetime.timedelta(days = -delta)
            cutoffs[delta] = cutoff.strftime("%Y%m%d")

        # NOTE: This assumes that game IDs can be lexically sorted
        # into temporal order
        for g in games_coll.sort('_id', pymongo.DESCENDING):
            g_id = g['_id']['game_id']
            game_list.append(g_id)

            name = g['_id'][NAME]

            # TODO: Turn this back. The concept of aliases only comes
            #into play when two different "real" player names both
            #normalize to the same "normalized" player name.
            # aliases.add(target_player_cur_name)

            wp = g[WIN_POINTS]
            res = g[RESULT]
            overall_record.record_result(res, wp)
            game_len = len( g[PLAYERS] ) + 1
            rec_by_game_size[game_len].record_result(res, wp)

            _ord = g[ORDER]
            rec_by_turn_order[_ord].record_result(res, wp)
            for delta in date_buckets:
                if g['game_date'] >= cutoffs[delta]:
                    rec_by_date[delta].record_result(res, wp)
            supply = [dominioncards.index_to_card(i) for i in g[SUPPLY]]

            for (ex, wt) in dominioncards.get_expansion_weight(supply).items():
                expansion_dist[ex] += wt
                expansion_win_points[ex] += wt * wp


        #TODO: a good choice for a template like jinja2
        ret = standard_heading("CouncilRoom.com: Dominion Stats: %s" % 
                               target_player)

        ret += '<form action="/player" method="get">'
        ret += '<span class="subhead">Profile for %s</span>' % target_player

        leaderboard_history_most_recent = (leaderboard_history[-1] if 
                                           leaderboard_history else None)
        if leaderboard_history_most_recent:
            level = (leaderboard_history_most_recent[1] - 
                     leaderboard_history_most_recent[2])
            level = int(max(math.floor(level), 0))
            ret += '<span class="level">Level ' + str(level) + '</span>'

        ret += '<span class="search2">'
        ret += """
               Search for another player:
               <input type="text" name="player" style="width:100px;" />
               <input type="submit" value="View Stats!" />
               </span></form><br><br>
               """

        if len(aliases) > 1:
            ret += 'Aliases: ' + ', '.join(aliases) + '\n'


        ret += render_record_table('Record by game size', overall_record,
                                   rec_by_game_size,
                                   lambda game_size: '%d players' % game_size)
        ret += render_record_table('Recent Record', overall_record,
                                   rec_by_date,
                                   lambda num_days: 'Last %d days' % num_days)
        ret += render_record_table('Record by turn order', overall_record,
                                   rec_by_turn_order,
                                   lambda pos: 'Table position %d' % pos)

        ret += '<div style="clear: both;">&nbsp;</div>'
        ret += '<div class="cardborder yellow"><h3>Expansion Data</h3><table class="stats">'
        ret += '<tr><th>Card Set<th>Avg. Cards<br/> Per Kingdom<th>Weighted<br/> Win Points<th>Favor'

        for (ex, weight) in sorted(expansion_dist.iteritems(), 
                      key=operator.itemgetter(1), reverse=True):

            if ex == 'Fan':
                continue

            wp = expansion_win_points[ex] / weight
            average = overall_record.average_win_points()

            ret += '<tr><th>%s</th>'%ex
            ret += '<td>%.2f</td>'% (weight * 10. / len(game_list))
            ret += '<td>%.2f<td>' % wp
            if average > 0:
                ret += '<td>%.2f%%</td>'% ( (wp - average) * 100. / average )
            else:
                ret += '<td>0</td>' 
        ret += '</table></div>'

        ret += '<div style="clear: both;">&nbsp;</div>'

        ret += goals.MaybeRenderGoals(db, norm_target_player)

        ret += '<A HREF="/popular_buys?player=%s"><h2>Stats by card</h2></A>\n' % target_player
        ret += '<A HREF="/games_by_opponent?player=%s"><h2>Record by opponent</h2></A>\n' % target_player

        if leaderboard_history:
            render = web.template.render('')
            ret += str(render.player_page_leaderboard_history_template(
                    json.dumps(leaderboard_history)))

        ret += '<h2>Most recent games</h2>\n'
        qm = query_matcher.QueryMatcher(p1_name=target_player)
        for g_id in game_list[:3]:
            g = db.games.find_one({'_id': g_id})
            game_val = game.Game(g)
            ret += (query_matcher.GameMatcher(game_val, qm).display_game_snippet() +
                    '<br>')

        ret += ('<A HREF="/search_result?p1_name=%s">(See more)</A>' % 
                target_player)
        ret += '</body></html>'

        return ret