Example #1
0
 def __init__(self, playerid, name, home):
     """
     Create a new Player instance with the player id (from NFL.com's
     GameCenter), the player's name (e.g., "T.Brady") and whether the
     player is playing in a home game or not.
     """
     self.playerid = playerid
     self.name = name
     self.home = home
     self._stats = OrderedDict()
Example #2
0
def _json_play_players(play, data):
    """
    Takes a single JSON play entry (data) and converts it to an OrderedDict
    of player statistics.

    play is the instance of Play that this data is part of. It is used
    to determine whether the player belong to the home team or not.
    """
    players = OrderedDict()
    for playerid, statcats in data.iteritems():
        if playerid == '0':
            continue
        for info in statcats:
            if info['statId'] not in nflgame.statmap.idmap:
                continue
            if playerid not in players:
                home = play.drive.game.is_home(info['clubcode'])
                if home:
                    team_name = play.drive.game.home
                else:
                    team_name = play.drive.game.away
                stats = nflgame.player.PlayPlayerStats(playerid,
                                                       info['playerName'],
                                                       home, team_name)
                players[playerid] = stats
            statvals = nflgame.statmap.values(info['statId'], info['yards'])
            players[playerid]._add_stats(statvals)
    return players
Example #3
0
def _json_game_player_stats(game, data):
    """
    Parses the 'home' and 'away' team stats and returns an OrderedDict
    mapping player id to their total game statistics as instances of
    nflgame.player.GamePlayerStats.
    """
    players = OrderedDict()
    for team in ('home', 'away'):
        for category in nflgame.statmap.categories:
            if category not in data[team]['stats']:
                continue
            for pid, raw in data[team]['stats'][category].iteritems():
                stats = {}
                for k, v in raw.iteritems():
                    if k == 'name':
                        continue
                    stats['%s_%s' % (category, k)] = v
                if pid not in players:
                    home = team == 'home'
                    if home:
                        team_name = game.home
                    else:
                        team_name = game.away
                    players[pid] = nflgame.player.GamePlayerStats(
                        pid, raw['name'], home, team_name)
                players[pid]._add_stats(stats)
    return players
Example #4
0
    def max_player_stats(self):
        """
        Returns a GenPlayers sequence of player statistics that combines
        game statistics and play statistics by taking the max value of
        each corresponding statistic.

        This is useful when accuracy is desirable. Namely, using only
        play-by-play data or using only game statistics can be unreliable.
        That is, both are inconsistently correct.

        Taking the max values of each statistic reduces the chance of being
        wrong (particularly for stats that are in both play-by-play data
        and game statistics), but does not eliminate them.
        """
        game_players = list(self.players)
        play_players = list(self.drives.plays().players())
        max_players = OrderedDict()

        # So this is a little tricky. It's possible for a player to have
        # only statistics at the play level, and therefore not be represented
        # in the game level statistics. Therefore, we initialize our
        # max_players with play-by-play stats first. Then go back through
        # and combine them with available game statistics.
        for pplay in play_players:
            newp = nflgame.player.GamePlayerStats(pplay.playerid,
                                                  pplay.name, pplay.home,
                                                  pplay.team)
            maxstats = {}
            for stat, val in pplay._stats.iteritems():
                maxstats[stat] = val

            newp._overwrite_stats(maxstats)
            max_players[pplay.playerid] = newp

        for newp in max_players.itervalues():
            for pgame in game_players:
                if pgame.playerid != newp.playerid:
                    continue

                maxstats = {}
                for stat, val in pgame._stats.iteritems():
                    maxstats[stat] = max([val,
                                          newp._stats.get(stat, -_MAX_INT)])

                newp._overwrite_stats(maxstats)
                break
        return nflgame.seq.GenPlayerStats(max_players)
Example #5
0
    def max_player_stats(self):
        """
        Returns a GenPlayers sequence of player statistics that combines
        game statistics and play statistics by taking the max value of
        each corresponding statistic.

        This is useful when accuracy is desirable. Namely, using only
        play-by-play data or using only game statistics can be unreliable.
        That is, both are inconsistently correct.

        Taking the max values of each statistic reduces the chance of being
        wrong (particularly for stats that are in both play-by-play data
        and game statistics), but does not eliminate them.
        """
        game_players = list(self.players)
        play_players = list(self.drives.plays().players())
        max_players = OrderedDict()

        # So this is a little tricky. It's possible for a player to have
        # only statistics at the play level, and therefore not be represented
        # in the game level statistics. Therefore, we initialize our
        # max_players with play-by-play stats first. Then go back through
        # and combine them with available game statistics.
        for pplay in play_players:
            newp = nflgame.player.GamePlayerStats(pplay.playerid,
                                                  pplay.name, pplay.home,
                                                  pplay.team)
            maxstats = {}
            for stat, val in pplay._stats.iteritems():
                maxstats[stat] = val

            newp._overwrite_stats(maxstats)
            max_players[pplay.playerid] = newp

        for newp in max_players.itervalues():
            for pgame in game_players:
                if pgame.playerid != newp.playerid:
                    continue

                maxstats = {}
                for stat, val in pgame._stats.iteritems():
                    maxstats[stat] = max([val,
                                          newp._stats.get(stat, -_MAX_INT)])

                newp._overwrite_stats(maxstats)
                break
        return nflgame.seq.GenPlayerStats(max_players)
Example #6
0
def new_schedule():
    """
    Builds an entire schedule from scratch.
    """
    sched = OrderedDict()
    for year, stype, week in year_phase_week():
        update_week(sched, year, stype, week)
    return sched
Example #7
0
 def __init__(self, playerid, name, home):
     """
     Create a new Player instance with the player id (from NFL.com's
     GameCenter), the player's name (e.g., "T.Brady") and whether the
     player is playing in a home game or not.
     """
     self.playerid = playerid
     self.name = name
     self.home = home
     self._stats = OrderedDict()
Example #8
0
 def __add__(self, other):
     """
     Adds two sequences of players by combining repeat players and summing
     their statistics.
     """
     players = OrderedDict()
     for p in itertools.chain(self, other):
         if p.playerid not in players:
             players[p.playerid] = p
         else:
             players[p.playerid] += p
     return GenPlayerStats(players)
Example #9
0
 def players(self):
     """
     Returns the combined player stats for every play in the sequence.
     """
     players = OrderedDict()
     for play in self:
         for player in play.players:
             if player.playerid not in players:
                 players[player.playerid] = player
             else:
                 players[player.playerid] += player
     return GenPlayerStats(players)
Example #10
0
def diff(before, after):
    """
    Returns the difference between two points of time in a game in terms of
    plays and player statistics. The return value is a GameDiff namedtuple
    with two attributes: plays and players. Each contains *only* the data
    that is in the after game but not in the before game.

    This is useful for sending alerts where you're guaranteed to see each
    play statistic only once (assuming NFL.com behaves itself).

    XXX: There is an assertion that requires after's game clock be the same
    or later than before's game clock. This may need to be removed if NFL.com
    allows its game clock to be rolled back due to corrections from refs.
    """
    assert after.time >= before.time, \
        'When diffing two games, "after" (%s) must be later or the ' \
        'same time as "before" (%s).' % (after.time, before.time)
    assert after.eid == before.eid

    plays = []
    after_plays = list(after.drives.plays())
    before_plays = list(before.drives.plays())
    for play in after_plays:
        if play not in before_plays:
            plays.append(play)

    # You might think that updated play data is enough. You could scan
    # it for statistics you're looking for (like touchdowns).
    # But sometimes a play can sneak in twice if its description gets
    # updated (late call? play review? etc.)
    # Thus, we do a diff on the play statistics for player data too.
    _players = OrderedDict()
    after_players = list(after.drives.players())
    before_players = list(before.drives.players())
    for aplayer in after_players:
        has_before = False
        for bplayer in before_players:
            if aplayer.playerid == bplayer.playerid:
                has_before = True
                pdiff = aplayer - bplayer
                if pdiff is not None:
                    _players[aplayer.playerid] = pdiff
        if not has_before:
            _players[aplayer.playerid] = aplayer
    players = nflgame.seq.GenPlayerStats(_players)

    return GameDiff(plays=plays, players=players)
Example #11
0
def build_old(nfl_schedules_path):
    sched = OrderedDict()
    xml_filenames = get_filenames(nfl_schedules_path, "", ".xml")
    sort_nicely(xml_filenames)
    xml_filenames.reverse()
    cur_year = DETAILED_STATS_START_YEAR
    for xml_file in xml_filenames:
        year, week, stype = xml_file.split(".xml")[0].split("-")
        year = int(year)
        week = int(week)
        if year < cur_year:
            print(str(year))
            cur_year = year
        if year < DETAILED_STATS_START_YEAR:
            print('Building (%d, %s, %d)...' % (year, stype, week))
            update_week(sched, year, stype, week, nfl_schedules_path)
    return sched
Example #12
0
def diff(before, after):
    """
    Returns the difference between two points of time in a game in terms of
    plays and player statistics. The return value is a GameDiff namedtuple
    with two attributes: plays and players. Each contains *only* the data
    that is in the after game but not in the before game.

    This is useful for sending alerts where you're guaranteed to see each
    play statistic only once (assuming NFL.com behaves itself).
    """
    assert after.eid == before.eid

    plays = []
    after_plays = list(after.drives.plays())
    before_plays = list(before.drives.plays())
    for play in after_plays:
        if play not in before_plays:
            plays.append(play)

    # You might think that updated play data is enough. You could scan
    # it for statistics you're looking for (like touchdowns).
    # But sometimes a play can sneak in twice if its description gets
    # updated (late call? play review? etc.)
    # Thus, we do a diff on the play statistics for player data too.
    _players = OrderedDict()
    after_players = list(after.max_player_stats())
    before_players = list(before.max_player_stats())
    for aplayer in after_players:
        has_before = False
        for bplayer in before_players:
            if aplayer.playerid == bplayer.playerid:
                has_before = True
                pdiff = aplayer - bplayer
                if pdiff is not None:
                    _players[aplayer.playerid] = pdiff
        if not has_before:
            _players[aplayer.playerid] = aplayer
    players = nflgame.seq.GenPlayerStats(_players)

    return GameDiff(before=before, after=after, plays=plays, players=players)
Example #13
0
class PlayerStats(object):
    """
    Player represents a single player and all of his statistical categories.
    Every player has 'playerid', 'name' and 'home' fields.
    Additionally, depending upon which statistical categories that player
    was involved in for the game, he'll have properties such as 'passing_tds',
    'rushing_yds', 'defense_int' and 'kicking_fgm'.

    In order to know whether a paricular player belongs to a statical category,
    you may use the filtering methods of a player sequence or alternatively,
    use the has_cat method with arguments like 'passing', 'rushing', 'kicking',
    etc. (A player sequence in this case would be an instance of
    GenPlayerStats.)

    You may also inspect whether a player has a certain property by using
    the special __dict__ attribute. For example::

        if 'passing_yds' in player.__dict__:
            # Do something with player.passing_yds
    """

    def __init__(self, playerid, name, home, team):
        """
        Create a new Player instance with the player id (from NFL.com's
        GameCenter), the player's name (e.g., "T.Brady") and whether the
        player is playing in a home game or not.
        """
        self.playerid = playerid
        self.name = name
        self.home = home
        self.team = team
        self._stats = OrderedDict()

        self.player = None
        if self.playerid in nflgame.players:
            self.player = nflgame.players[self.playerid]

    def has_cat(self, cat):
        for f in self._stats:
            if f.startswith(cat):
                return True
        return False

    @property
    def guess_position(self):
        """
        Guesses the position of this player based on the statistical
        categories present in this object when player meta is not
        present.

        Note that if this resorts to a guess, then it will be more
        effective on aggregate data rather than data from just a
        single play. (e.g., if a QB runs the ball, and that's the
        only data available, the position returned will be RB.)

        When a position is guessed, only the following positions will
        be returned: QB, RB, WR, DEF, K and P.
        """
        # Look for the player meta first. Duh.
        if self.player is not None:
            return self.player.position

        stats = [
            (self.passing_att, "QB"),
            (self.rushing_att, "RB"),
            (self.receiving_tar, "WR"),
            (self.defense_tkl, "DEF"),
            (self.defense_ast, "DEF"),
            (self.kicking_tot, "K"),
            (self.kicking_fga, "K"),
            (self.punting_tot, "P"),
        ]
        return sorted(stats, reverse=True)[0][1]

    @property
    def tds(self):
        """
        Returns the total number of touchdowns credited to this player across
        all statistical categories.
        """
        n = 0
        for f, v in self.__dict__.iteritems():
            if f.endswith("tds"):
                n += v
        return n

    @property
    def twopta(self):
        """
        Returns the total number of two point conversion attempts for
        the passing, rushing and receiving categories.
        """
        return self.passing_twopta + self.rushing_twopta + self.receiving_twopta

    @property
    def twoptm(self):
        """
        Returns the total number of two point conversions for
        the passing, rushing and receiving categories.
        """
        return self.passing_twoptm + self.rushing_twoptm + self.receiving_twoptm

    @property
    def twoptmissed(self):
        """
        Returns the total number of two point conversion failures for
        the passing, rushing and receiving categories.
        """
        return self.passing_twoptmissed + self.rushing_twoptmissed + self.receiving_twoptmissed

    @property
    def stats(self):
        """
        Returns a dict of all stats for the player.
        """
        return self._stats

    def formatted_stats(self):
        """
        Returns a roughly-formatted string of all statistics for this player.
        """
        s = []
        for stat, val in self._stats.iteritems():
            s.append("%s: %s" % (stat, val))
        return ", ".join(s)

    def _add_stats(self, stats):
        for k, v in stats.iteritems():
            self.__dict__[k] = self.__dict__.get(k, 0) + v
            self._stats[k] = self.__dict__[k]

    def _overwrite_stats(self, stats):
        for k, v in stats.iteritems():
            self.__dict__[k] = v
            self._stats[k] = self.__dict__[k]

    def __str__(self):
        """
        Simply returns the player's name, e.g., "T.Brady".
        """
        return self.name

    def __add__(self, other):
        """
        Adds two players together. Only two player objects that correspond
        to the same human (i.e., GameCenter identifier) can be added together.

        If two different players are added together, an assertion will
        be raised.

        The effect of adding two player objects simply corresponds to the
        sums of all statistical values.

        Note that as soon as two players have been added, the 'home' property
        becomes undefined if the two operands have different values of 'home'.
        """
        assert self.playerid == other.playerid
        assert type(self) == type(other)

        if self.home != other.home:
            home = None
        else:
            home = self.home
        new_player = self.__class__(self.playerid, self.name, home, self.team)
        new_player._add_stats(self._stats)
        new_player._add_stats(other._stats)

        return new_player

    def __sub__(self, other):
        assert self.playerid == other.playerid
        assert type(self) == type(other)

        new_player = GamePlayerStats(self.playerid, self.name, self.home, self.team)
        new_player._add_stats(self._stats)
        for bk, bv in other._stats.iteritems():
            if bk not in new_player._stats:  # stat was taken away? ignore.
                continue

            new_player._stats[bk] -= bv
            if new_player._stats[bk] == 0:
                del new_player._stats[bk]
            else:
                new_player.__dict__[bk] = new_player._stats[bk]

        anydiffs = False
        for k, v in new_player._stats.iteritems():
            if v > 0:
                anydiffs = True
                break
        if not anydiffs:
            return None
        return new_player

    def __getattr__(self, name):
        # If name has one of the categories as a prefix, then return
        # a default value of zero
        for cat in nflgame.statmap.categories:
            if name.startswith(cat):
                return 0
        raise AttributeError

    def passer_rating(self):
        """
        Calculate and return the passer rating using the NFL formula. Passer
        rating is calculated using a player's passing attempts, completions,
        yards, touchdowns, and interceptions. Passer rating in the NFL is on a
        scale from 0 to 158.3.
        """
        l = [((self.passing_cmp / self.passing_att) - 0.3) * 5]
        l.append(((self.passing_yds / self.passing_att) - 3) * 0.25)
        l.append((self.tds / self.passing_att) * 20)
        l.append(2.375 - (self.passing_ints / self.passing_att * 25))

        m = []
        for a in l:
            if a < 0:
                a = 0
                m.append(a)
            elif a > 2.375:
                a = 2.375
                m.append(a)
            else:
                m.append(a)

            rating = round((sum(m) / 6) * 100, 1)
        return rating
Example #14
0
class PlayerStats (object):
    """
    Player represents a single player and all of his statistical categories.
    Every player has 'playerid', 'name' and 'home' fields.
    Additionally, depending upon which statistical categories that player
    was involved in for the game, he'll have properties such as 'passing_tds',
    'rushing_yds', 'defense_int' and 'kicking_fgm'.

    In order to know whether a paricular player belongs to a statical category,
    you may use the filtering methods of a player sequence or alternatively,
    use the has_cat method with arguments like 'passing', 'rushing', 'kicking',
    etc. (A player sequence in this case would be an instance of
    GenPlayerStats.)

    You may also inspect whether a player has a certain property by using
    the special __dict__ attribute. For example::

        if 'passing_yds' in player.__dict__:
            # Do something with player.passing_yds
    """
    def __init__(self, playerid, name, home):
        """
        Create a new Player instance with the player id (from NFL.com's
        GameCenter), the player's name (e.g., "T.Brady") and whether the
        player is playing in a home game or not.
        """
        self.playerid = playerid
        self.name = name
        self.home = home
        self._stats = OrderedDict()

    def has_cat(self, cat):
        return self.__dict__.get(cat, False)

    def __refresh_categories(self):
        for cat in nflgame.statmap.categories:
            for f in self.__dict__:
                if f.startswith(cat):
                    self.__dict__[cat] = True
                    break

    @property
    def tds(self):
        """
        Returns the total number of touchdowns credited to this player across
        all statistical categories.
        """
        n = 0
        for f, v in self.__dict__.iteritems():
            if f.endswith('tds'):
                n += v
        return n

    @property
    def stats(self):
        """
        Returns a dict of all stats for the player.
        """
        return self._stats

    def formatted_stats(self):
        """
        Returns a roughly-formatted string of all statistics for this player.
        """
        s = []
        for stat, val in self._stats.iteritems():
            s.append('%s: %s' % (stat, val))
        return ', '.join(s)

    def _add_stats(self, stats):
        for k, v in stats.iteritems():
            self.__dict__[k] = self.__dict__.get(k, 0) + v
            self._stats[k] = self.__dict__[k]
        self.__refresh_categories()

    def __str__(self):
        """
        Simply returns the player's name, e.g., "T.Brady".
        """
        return self.name

    def __add__(self, other):
        """
        Adds two players together. Only two player objects that correspond
        to the same human (i.e., GameCenter identifier) can be added together.

        If two different players are added together, an assertion will
        be raised.

        The effect of adding two player objects simply corresponds to the
        sums of all statistical values.

        Note that as soon as two players have been added, the 'home' property
        becomes undefined.
        """
        assert self.playerid == other.playerid
        assert type(self) == type(other)

        new_player = self.__class__(self.playerid, self.name, None)
        new_player._add_stats(self._stats)
        new_player._add_stats(other._stats)

        return new_player

    def __sub__(self, other):
        assert self.playerid == other.playerid
        assert type(self) == type(other)

        new_player = GamePlayerStats(self.playerid, self.name, self.home)
        new_player._add_stats(self._stats)
        for bk, bv in other._stats.iteritems():
            new_player._stats[bk] -= bv
            if new_player._stats[bk] == 0:
                del new_player._stats[bk]
            else:
                new_player.__dict__[bk] = new_player._stats[bk]

        anydiffs = False
        for k, v in new_player._stats.iteritems():
            if v > 0:
                anydiffs = True
                break
        if not anydiffs:
            return None
        return new_player

    def __getattr__(self, name):
        # If name has one of the categories as a prefix, then return
        # a default value of zero
        for cat in nflgame.statmap.categories:
            if name.startswith(cat):
                return 0
        print name
        raise AttributeError
Example #15
0
def _xml_plays(data, coach=True):
    """
    Parses the XML raw string `data` given into an ordered dictionary
    of `nflvid.Play` objects corresponding to coach play timings. If
    `coach` is set to `False`, then play timings for the broadcast are
    retrieved.

    The dictionary is keyed by play id.

    A second return value, the ending time of the broadcast footage,
    is also returned. (This is used to compute an offset between the
    ArchiveTCIN time and when the play really starts.)
    """
    if data is None:
        return None
    soup = bs4.BeautifulSoup(data)

    game_end_time = soup.find('dataset').get('endtime', None)
    if game_end_time is not None:
        game_end_time = PlayTime(game_end_time.strip())

    # Load everything into a list first, since we need to look ahead to see
    # the next play's start time to compute the current play's duration.
    rows = []
    for row in soup.find_all('row'):
        playid = row.find('id')
        if not playid:
            playid = row.get('playid', None)
            if not playid:
                continue
            playid = playid.strip()
        else:
            playid = playid.get_text().strip()

        if coach:
            start = row.find('catin')
        else:
            start = row.find('archivetcin')
        if not start:
            continue
        start = PlayTime(start.get_text().strip())
        rows.append((playid, start, row))

    # A predicate for determining whether to ignore a row or not in our final
    # result set. For example, timeouts take a lot of time but aren't needed
    # for play-by-play footage.
    def ignore(row):
        if 'playdescription' in row.attrs:
            if row['playdescription'].lower().startswith('timeout'):
                return True
            if row['playdescription'].lower().startswith('two-minute'):
                return True

        # Did we miss anything?
        if 'preplaybyplay' in row.attrs:
            if row['preplaybyplay'].lower().startswith('timeout'):
                return True
        return False

    d = OrderedDict()
    for i, (playid, start, row) in enumerate(rows):
        if ignore(row):
            continue
        end = None
        if i < len(rows) - 1:
            end = rows[i+1][1]
        d[playid] = Play(start, end, playid, game_end_time)
    return d
Example #16
0
class PlayerStats(object):
    """
    Player represents a single player and all of his statistical categories.
    Every player has 'playerid', 'name' and 'home' fields.
    Additionally, depending upon which statistical categories that player
    was involved in for the game, he'll have properties such as 'passing_tds',
    'rushing_yds', 'defense_int' and 'kicking_fgm'.

    In order to know whether a paricular player belongs to a statical category,
    you may use the filtering methods of a player sequence or alternatively,
    use the has_cat method with arguments like 'passing', 'rushing', 'kicking',
    etc. (A player sequence in this case would be an instance of
    GenPlayerStats.)

    You may also inspect whether a player has a certain property by using
    the special __dict__ attribute. For example::

        if 'passing_yds' in player.__dict__:
            # Do something with player.passing_yds
    """
    def __init__(self, playerid, name, home, team):
        """
        Create a new Player instance with the player id (from NFL.com's
        GameCenter), the player's name (e.g., "T.Brady") and whether the
        player is playing in a home game or not.
        """
        self.playerid = playerid
        self.name = name
        self.home = home
        self.team = team
        self._stats = OrderedDict()

        self.player = None
        if self.playerid in nflgame.players:
            self.player = nflgame.players[self.playerid]

    def has_cat(self, cat):
        for f in self._stats:
            if f.startswith(cat):
                return True
        return False

    @property
    def guess_position(self):
        """
        Guesses the position of this player based on the statistical
        categories present in this object when player meta is not
        present.

        Note that if this resorts to a guess, then it will be more
        effective on aggregate data rather than data from just a
        single play. (e.g., if a QB runs the ball, and that's the
        only data available, the position returned will be RB.)

        When a position is guessed, only the following positions will
        be returned: QB, RB, WR, DEF, K and P.
        """
        # Look for the player meta first. Duh.
        if self.player is not None:
            return self.player.position

        stats = [
            (self.passing_att, 'QB'),
            (self.rushing_att, 'RB'),
            (self.receiving_tar, 'WR'),
            (self.defense_tkl, 'DEF'),
            (self.defense_ast, 'DEF'),
            (self.kicking_tot, 'K'),
            (self.kicking_fga, 'K'),
            (self.punting_tot, 'P'),
        ]
        return sorted(stats, reverse=True)[0][1]

    @property
    def tds(self):
        """
        Returns the total number of touchdowns credited to this player across
        all statistical categories.
        """
        n = 0
        for f, v in self.__dict__.iteritems():
            if f.endswith('tds'):
                n += v
        return n

    @property
    def twopta(self):
        """
        Returns the total number of two point conversion attempts for
        the passing, rushing and receiving categories.
        """
        return (self.passing_twopta + self.rushing_twopta +
                self.receiving_twopta)

    @property
    def twoptm(self):
        """
        Returns the total number of two point conversions for
        the passing, rushing and receiving categories.
        """
        return (self.passing_twoptm + self.rushing_twoptm +
                self.receiving_twoptm)

    @property
    def twoptmissed(self):
        """
        Returns the total number of two point conversion failures for
        the passing, rushing and receiving categories.
        """
        return (self.passing_twoptmissed + self.rushing_twoptmissed +
                self.receiving_twoptmissed)

    @property
    def stats(self):
        """
        Returns a dict of all stats for the player.
        """
        return self._stats

    def formatted_stats(self):
        """
        Returns a roughly-formatted string of all statistics for this player.
        """
        s = []
        for stat, val in self._stats.iteritems():
            s.append('%s: %s' % (stat, val))
        return ', '.join(s)

    def _add_stats(self, stats):
        for k, v in stats.iteritems():
            self.__dict__[k] = self.__dict__.get(k, 0) + v
            self._stats[k] = self.__dict__[k]

    def _overwrite_stats(self, stats):
        for k, v in stats.iteritems():
            self.__dict__[k] = v
            self._stats[k] = self.__dict__[k]

    def __str__(self):
        """
        Simply returns the player's name, e.g., "T.Brady".
        """
        return self.name

    def __add__(self, other):
        """
        Adds two players together. Only two player objects that correspond
        to the same human (i.e., GameCenter identifier) can be added together.

        If two different players are added together, an assertion will
        be raised.

        The effect of adding two player objects simply corresponds to the
        sums of all statistical values.

        Note that as soon as two players have been added, the 'home' property
        becomes undefined if the two operands have different values of 'home'.
        """
        assert self.playerid == other.playerid
        assert type(self) == type(other)

        if self.home != other.home:
            home = None
        else:
            home = self.home
        new_player = self.__class__(self.playerid, self.name, home, self.team)
        new_player._add_stats(self._stats)
        new_player._add_stats(other._stats)

        return new_player

    def __sub__(self, other):
        assert self.playerid == other.playerid
        assert type(self) == type(other)

        new_player = GamePlayerStats(self.playerid, self.name, self.home,
                                     self.team)
        new_player._add_stats(self._stats)
        for bk, bv in other._stats.iteritems():
            if bk not in new_player._stats:  # stat was taken away? ignore.
                continue

            new_player._stats[bk] -= bv
            if new_player._stats[bk] == 0:
                del new_player._stats[bk]
            else:
                new_player.__dict__[bk] = new_player._stats[bk]

        anydiffs = False
        for k, v in new_player._stats.iteritems():
            if v > 0:
                anydiffs = True
                break
        if not anydiffs:
            return None
        return new_player

    def __getattr__(self, name):
        # If name has one of the categories as a prefix, then return
        # a default value of zero
        for cat in nflgame.statmap.categories:
            if name.startswith(cat):
                return 0
        raise AttributeError
Example #17
0
class PlayerStats(object):
    """
    Player represents a single player and all of his statistical categories.
    Every player has 'playerid', 'name' and 'home' fields.
    Additionally, depending upon which statistical categories that player
    was involved in for the game, he'll have properties such as 'passing_tds',
    'rushing_yds', 'defense_int' and 'kicking_fgm'.

    In order to know whether a paricular player belongs to a statical category,
    you may use the filtering methods of a player sequence or alternatively,
    use the has_cat method with arguments like 'passing', 'rushing', 'kicking',
    etc. (A player sequence in this case would be an instance of
    GenPlayerStats.)

    You may also inspect whether a player has a certain property by using
    the special __dict__ attribute. For example::

        if 'passing_yds' in player.__dict__:
            # Do something with player.passing_yds
    """

    def __init__(self, playerid, name, home):
        """
        Create a new Player instance with the player id (from NFL.com's
        GameCenter), the player's name (e.g., "T.Brady") and whether the
        player is playing in a home game or not.
        """
        self.playerid = playerid
        self.name = name
        self.home = home
        self._stats = OrderedDict()

    def has_cat(self, cat):
        return self.__dict__.get(cat, False)

    def __refresh_categories(self):
        for cat in nflgame.statmap.categories:
            for f in self.__dict__:
                if f.startswith(cat):
                    self.__dict__[cat] = True
                    break

    @property
    def tds(self):
        """
        Returns the total number of touchdowns credited to this player across
        all statistical categories.
        """
        n = 0
        for f, v in self.__dict__.iteritems():
            if f.endswith("tds"):
                n += v
        return n

    @property
    def stats(self):
        """
        Returns a dict of all stats for the player.
        """
        return self._stats

    def formatted_stats(self):
        """
        Returns a roughly-formatted string of all statistics for this player.
        """
        s = []
        for stat, val in self._stats.iteritems():
            s.append("%s: %s" % (stat, val))
        return ", ".join(s)

    def _add_stats(self, stats):
        for k, v in stats.iteritems():
            self.__dict__[k] = self.__dict__.get(k, 0) + v
            self._stats[k] = self.__dict__[k]
        self.__refresh_categories()

    def __str__(self):
        """
        Simply returns the player's name, e.g., "T.Brady".
        """
        return self.name

    def __add__(self, other):
        """
        Adds two players together. Only two player objects that correspond
        to the same human (i.e., GameCenter identifier) can be added together.

        If two different players are added together, an assertion will
        be raised.

        The effect of adding two player objects simply corresponds to the
        sums of all statistical values.

        Note that as soon as two players have been added, the 'home' property
        becomes undefined.
        """
        assert self.playerid == other.playerid
        assert type(self) == type(other)

        new_player = self.__class__(self.playerid, self.name, None)
        new_player._add_stats(self._stats)
        new_player._add_stats(other._stats)

        return new_player

    def __sub__(self, other):
        assert self.playerid == other.playerid
        assert type(self) == type(other)

        new_player = GamePlayerStats(self.playerid, self.name, self.home)
        new_player._add_stats(self._stats)
        for bk, bv in other._stats.iteritems():
            new_player._stats[bk] -= bv
            if new_player._stats[bk] == 0:
                del new_player._stats[bk]
            else:
                new_player.__dict__[bk] = new_player._stats[bk]

        anydiffs = False
        for k, v in new_player._stats.iteritems():
            if v > 0:
                anydiffs = True
                break
        if not anydiffs:
            return None
        return new_player

    def __getattr__(self, name):
        # If name has one of the categories as a prefix, then return
        # a default value of zero
        for cat in nflgame.statmap.categories:
            if name.startswith(cat):
                return 0
        print name
        raise AttributeError