~dlh/armascript/armastats

« back to all changes in this revision

Viewing changes to rank.py

  • Committer: Daniel Lee Harple
  • Date: 2012-09-27 23:54:03 UTC
  • Revision ID: leeharple@gmail.com-20120927235403-bqa4edd2kcha732w
Initial commit.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
 
 
3
from __future__ import with_statement
 
4
import re
 
5
import os
 
6
import os.path
 
7
import armascript
 
8
 
 
9
def ordinalize(number):
 
10
    if number % 100 in xrange(11, 14):
 
11
        suffix = "th"
 
12
    else:
 
13
        n = number % 10
 
14
        if n == 1:
 
15
            suffix = "st"
 
16
        elif n == 2:
 
17
            suffix = "nd"
 
18
        elif n == 3:
 
19
            suffix = "rd"
 
20
        else:   
 
21
            suffix = "th"
 
22
    
 
23
    return str(number) + suffix
 
24
 
 
25
STATS_RE_FORMAT_STR = "^([0-9]+)[ \t]+(%s)\n$"
 
26
 
 
27
def find_position(lines, player):
 
28
    """
 
29
    Returns the a tuple of (index in lines, number won) for the specified ``player''
 
30
    """
 
31
    player_re = re.compile(STATS_RE_FORMAT_STR % re.escape(player))
 
32
    for index, line in enumerate(lines):
 
33
        match = player_re.match(line)
 
34
        if match:
 
35
            return (index, int(match.groups()[0]))
 
36
    
 
37
    return (-1, 0)
 
38
    
 
39
def find_next_position(lines, next_won):
 
40
    """
 
41
    Returns the index in ``lines'' where the stat will be inserted if player
 
42
    has ``next_won'' wins.
 
43
    """
 
44
    index = 0
 
45
    for index, line in enumerate(lines):
 
46
        other_won = int(re.findall("^\d+", line)[0])
 
47
        if next_won > other_won:
 
48
            return index
 
49
    return index
 
50
 
 
51
class BasicStat(object):
 
52
    def parse(self, line, position):
 
53
        """Parse a line from a won_matches or won_rounds file"""
 
54
        won, self.player = re.findall(STATS_RE_FORMAT_STR % ".*", line)[0]
 
55
        self.won = int(won)
 
56
        self.position = position
 
57
        return self
 
58
 
 
59
def format_stats_message(before_lines, after_lines, player_stat):
 
60
    """
 
61
    Formats a stats message
 
62
    
 
63
    before_lines -- the raw lines for before context
 
64
    after_lines  -- the raw lines for after context
 
65
    player_stat  -- a BasicStat object for the player who won
 
66
    """
 
67
    
 
68
    def convert(lines, position):
 
69
        return [BasicStat().parse(line, position + index) for index, line in enumerate(lines)]
 
70
        
 
71
    def format(stat, color):
 
72
        return '\\    %s%s) %d  %s' % (color, ordinalize(stat.position), stat.won, stat.player)
 
73
        
 
74
    def format_all(stats, color, trailing_newline):
 
75
        if len(stats) > 0:
 
76
            msg = "\\n".join([format(stat, color) for stat in stats])
 
77
            if trailing_newline:
 
78
                msg += "\\n"
 
79
            return msg
 
80
        return ""
 
81
    
 
82
    before = convert(before_lines, player_stat.position - len(before_lines))
 
83
    after  = convert(after_lines, player_stat.position + 1)
 
84
    
 
85
    message = ""
 
86
    message += format_all(before, "0xffff7f", True)
 
87
    message += format(player_stat, "0xff0000") + "\\n"
 
88
    message += format_all(after, "0xffff7f", False)
 
89
    return message
 
90
 
 
91
def stats_message(path, player, display_name, context):
 
92
    with open(path, "r") as f:
 
93
        lines = f.readlines()
 
94
    current_line, previous_won = find_position(lines, player)
 
95
    if previous_won == 0:
 
96
        return ""
 
97
        
 
98
    del lines[current_line]
 
99
    
 
100
    next_position_line = find_next_position(lines, previous_won + 1)
 
101
    before_lines = lines[max(next_position_line - context, 0):next_position_line]
 
102
    
 
103
    if len(before_lines) < context:
 
104
        context += context - len(before_lines)
 
105
        
 
106
    after_lines  = lines[next_position_line:min(next_position_line + context, len(lines))]
 
107
    
 
108
    player_stat = BasicStat()
 
109
    player_stat.player = display_name
 
110
    player_stat.won = previous_won + 1
 
111
    player_stat.position = next_position_line + 1
 
112
    
 
113
    return format_stats_message(before_lines, after_lines, player_stat)
 
114
 
 
115
def match_stat_message(player, display_name, matches_path="var/won_matches.txt", context=2):
 
116
    msg = stats_message(matches_path, player, display_name, context)
 
117
    
 
118
    if len(msg) == 0:
 
119
        msg = "0x00ff00%s won their first match!" % display_name
 
120
    else:
 
121
        msg = "0x00ff00Won Matches:\\n" + msg
 
122
        
 
123
    return msg
 
124
 
 
125
class RankReactor(armascript.Reactor):
 
126
    def __init__(self):
 
127
        self.won_matches_path = os.path.join(os.environ["ARMAGETRONAD_DIR_VAR"], "won_matches.txt")
 
128
        self.screen_names = {}
 
129
 
 
130
    def screen_name(self, player):
 
131
        return self.screen_names.get(player, player)
 
132
        
 
133
    def PLAYER_ENTERED(self, event):
 
134
        self.screen_names[event.player] = event.screen_name
 
135
    
 
136
    def PLAYER_RENAMED(self, event):
 
137
        if event.old_name in self.screen_names:
 
138
            del self.screen_names[event.old_name]
 
139
        self.screen_names[event.new_name] = event.screen_name
 
140
        
 
141
    def PLAYER_LEFT(self, event):
 
142
        if event.player in self.screen_names:
 
143
            del self.screen_names[event.player]
 
144
            
 
145
    def MATCH_WINNER(self, event):
 
146
        for player in event.players:
 
147
            armascript.console_message(match_stat_message(player, self.screen_name(player), self.won_matches_path))