def addPlay(self, gameID, driveNo, prevPlayNo, prevPlay, possData, debug=False): debug = True text = None if gameID == "401012282": if driveNo == 8 and prevPlayNo == 11: text = "Tyrel Dodson 78 Yd Return of Blocked Field Goal (Seth Small Kick)" print(prevPlay) if text is not None: ptype = playtype(text) play = ptype.getPlay() play.analyze(debug=debug) playPossession = possData.determinePossession(play, debug=debug) playStart = prevPlay.start playResult = playsummary(possession=playPossession, start=playStart, play=play, valid=True) if debug: print( "Adding play [{0}] for team [{1}] with text [{2}]".format( play.name, playPossession.start, text)) return playResult return None
def splitKickoff(self, gameData): fname = sys._getframe().f_code.co_name self.logger.debug("\n{0}{1}()".format(self.ind, fname)) changes = [] for idr in range(len(gameData)): drivePlays = gameData[idr].plays for dp in range(len(drivePlays)): playData = drivePlays[dp] if playData.valid is not True: continue if isinstance(playData.play, kickoffplay): self.logger.debug("{0} Kickoff Play: {1}".format( self.ind, playData.play.text)) newReturnPlay = returnplay(text=playData.play.text) newReturnPlay.pa.kickoffplay = False newReturnPlay.pa.touchdown = playData.play.pa.touchdown newReturnPlay.pa.fumble = playData.play.pa.fumble newReturnPlay.pa.runback = playData.play.pa.runback playData.play.pa.touchdown = False playData.play.pa.fumble = False playData.play.pa.runback = False newPossession = playpossession(start=None, end=None, text=playData.play.text) if playData.play.pa.getKey( "forced" ) is not None and not playData.possession.isKnownStart(): self.logger.debug( "{0} Using previous kickoff data to set possession to {1}" .format(playData.play.pa.forced)) newPossession.start = playData.play.pa.forced playData.play.pa.forced = False playData.possession.start = self.flipPossession( newPossession.start) else: newPossession.start = self.flipPossession( playData.possession) newPlayData = playsummary(possession=newPossession, start=playData.start.copy(), play=newReturnPlay, valid=playData.valid) drivePlays.insert(dp + 1, newPlayData) newReturnPlay.connectedPlays.append(playData) playData.play.connectedPlays.append(newReturnPlay) changes.append(idr) break self.logger.debug("{0}Found {1} Drives With Splits in {2}()".format( self.ind, len(changes), fname)) for idr in set(changes): self.dc.showDrive(gameData[idr], idr, "Drive {0}".format(idr)) return gameData
def splitInterception(self, gameData): fname = sys._getframe().f_code.co_name self.logger.debug("\n{0}{1}()".format(self.ind, fname)) changes = [] mixposs = mixedpossession() for idr in range(len(gameData)): drivePlays = gameData[idr].plays for dp in range(len(drivePlays)): playData = drivePlays[dp] if playData.valid is not True: continue if isinstance(playData.play, passingplay ) and playData.play.pa.getKey("interception"): self.logger.debug("{0} Interception Play: {1}".format( self.ind, playData.play.text)) newReturnPlay = returnplay(text=playData.play.text) newReturnPlay.pa.passingplay = False newReturnPlay.pa.touchdown = playData.play.pa.touchdown newReturnPlay.pa.fumble = playData.play.pa.fumble newReturnPlay.pa.runback = playData.play.pa.runback newReturnPlay.pa.interception = False playData.play.pa.touchdown = False playData.play.pa.fumble = False playData.play.pa.runback = False playData = mixposs.determineInterception( playData, drivePlays, dp) newPossession = playpossession(start=None, end=None, text=playData.play.text) try: newPossession.start = self.copMap[ playData.possession.start] except: newPossession.start = playData.possession.setUnknownStart( ) newPlayData = playsummary(possession=newPossession, start=playData.start.copy(), play=newReturnPlay, valid=playData.valid) drivePlays.insert(dp + 1, newPlayData) newReturnPlay.connectedPlays.append(playData) playData.play.connectedPlays.append(newReturnPlay) changes.append(idr) break self.logger.debug("{0}Found {1} Drives With Splits in {2}()".format( self.ind, len(changes), fname)) for idr in set(changes): self.dc.showDrive(gameData[idr], idr, "Drive {0}".format(idr)) return gameData
def returns(self, gameData): self.logger.debug("\n{0}".format(2*self.sep)) self.logger.debug("{0}Analyzing Kickoff Returns".format(self.ind)) for idr,driveData in enumerate(gameData): drivePlays = driveData.plays retval = self.getKickoffPlays(drivePlays) if retval is None: continue try: kickplay, retplay, genplay = retval except: raise ValueError("Could not parse return value: {0}".format(retval)) self.dc.showDrive(driveData, idr) ### Get starting place startingLine = kickplay.start.distToEndZone kickingYards = kickplay.play.yds.yards self.logger.debug("{0} Starting/Kicking -> {1} {2}".format(self.ind, startingLine, kickingYards)) ### Set starting line returnStart = startingLine - kickingYards if returnStart < 65: retplay.start.side = retplay.possession.start retplay.start.startY = returnStart else: raise ValueError("Not sure what to do about this kickoff!!!") if kickplay.play.pa.getKey("outofbounds") is True: retplay.play.yds.yards = None oobplay = self.pt.getPlay("No Play") oobplay.text = "Penalty: Kickoff Out of Bounds" oobplay.penalty = penalty(oobplay.text) oobposs = playpossession(start=kickplay.possession.start, end=None, text=oobplay.text) oobstart = kickplay.start.copy() oobstart.startY = 35 playResult = playsummary(possession=oobposs, start=oobstart, play=oobplay, valid=True) playResult.start.setYards(playResult.possession.start) drivePlays.insert(1, playResult) noretplay = self.pt.getPlay("") noretplay.text = "Post Penalty: Starting at 35 yard line" noretplay.yds.yards = 0 noretposs = playpossession(start=retplay.possession.start, end=None, text=noretplay.text) noretstart = retplay.start.copy() noretstart.startY = 35 playResult = playsummary(possession=noretposs, start=noretstart, play=noretplay, valid=True) playResult.start.setYards(playResult.possession.start) drivePlays.pop(2) ## get rid of old return play drivePlays.insert(2, playResult) ## insert new return play of zero yards self.dc.showDrive(driveData, idr) self.logger.debug("{0}Analyzing Kickoff Returns -> Done".format(self.ind)) return gameData
def splitTouchdown(self, gameData): fname = sys._getframe().f_code.co_name self.logger.debug("\n{0}{1}()".format(self.ind, fname)) changes = [] mixposs = mixedpossession() for idr in range(len(gameData)): drivePlays = gameData[idr].plays for dp in range(len(drivePlays)): playData = drivePlays[dp] if playData.valid is not True: continue if playData.play.pa.getKey("touchdown") is True: playData = mixposs.determineTouchdown(playData, drivePlays, dp, debug=False) if sum([isinstance(x.play, patplay) for x in drivePlays]) > 0: break playData.play.pa.addPAT() if playData.play.pa.getKey("addpat") is True: self.logger.debug("{0} Touchdown Play: {1}".format( self.ind, playData.play.text)) playData.play.pa.addpat = False ## Split Depends on Offense vs Defense PAT if playData.play.pa.getKey("defpat"): newPATPlay = patplay(text=playData.play.text) newPATPlay.pa.touchdown = False newPATPlay.pa.runback = playData.play.pa.runback playData.play.pa.runback = False newPossession = playpossession( start=None, end=None, text=playData.play.text) try: newPossession.start = self.copMap[ playData.possession.start] except: newPossession.start = playData.possession.setUnknownStart( ) self.logger.debug( "{0}This is a DEF PAT with POSS = {1}".format( self.ind, newPossession.start)) newPlayData = playsummary( possession=newPossession, start=playData.start.copy(), play=newPATPlay, valid=playData.valid) newPATPlay.connectedPlays.append(playData) playData.play.connectedPlays.append(newPATPlay) drivePlays.insert(dp + 1, newPlayData) changes.append(idr) else: newPATPlay = patplay(text=playData.play.text) newPATPlay.pa.touchdown = False newPATPlay.pa.runback = playData.play.pa.runback playData.play.pa.runback = False newPossession = playpossession( start=None, end=None, text=playData.play.text) newPossession.start = playData.possession.start self.logger.debug( "{0}This is a REGULAR PAT with POSS = {1}". format(self.ind, newPossession.start)) newPlayData = playsummary( possession=playData.possession, start=playData.start.copy(), play=newPATPlay, valid=playData.valid) drivePlays.insert(dp + 1, newPlayData) newPATPlay.connectedPlays.append(playData) playData.play.connectedPlays.append(newPATPlay) changes.append(idr) break self.logger.debug("{0}Found {1} Drives With Splits in {2}()".format( self.ind, len(changes), fname)) for idr in set(changes): self.dc.showDrive(gameData[idr], idr, "Drive {0}".format(idr)) return gameData
def splitFumble(self, gameData): fname = sys._getframe().f_code.co_name self.logger.debug("\n{0}{1}()".format(self.ind, fname)) changes = [] mixposs = mixedpossession() for idr in range(len(gameData)): drivePlays = gameData[idr].plays for dp in range(len(drivePlays)): playData = drivePlays[dp] if playData.valid is not True: continue if playData.play.pa.getKey("fumble") is True: self.logger.debug("{0} Fumble Play: {1}".format( self.ind, playData.play.text)) lostFumble = True try: if playData.possession.start == drivePlays[ dp + 1].possession.start and drivePlays[ dp + 1].valid is True: lostFumble = False except: lostFumble = True newReturnPlay = returnplay(text=playData.play.text) newReturnPlay.pa.touchdown = playData.play.pa.touchdown newReturnPlay.pa.fumble = False newReturnPlay.pa.runback = playData.play.pa.runback playData.play.pa.touchdown = False playData.play.pa.runback = False playData.play.pa.fumblereturn = False playData = mixposs.determineFumble(playData, drivePlays, dp, debug=False) newPossession = playpossession(start=None, end=None, text=playData.play.text) if playData.play.pa.getKey("forced") is not None: self.logger.debug( "{0}Using previous fumble data to set possession to {1}" .format(self.ind, playData.play.pa.forced)) newPossession.start = playData.play.pa.forced try: playData.possession.start = self.copMap[ playData.possession.start] except: playData.possession.setPreviousStart() playData.play.pa.forced = False else: self.logger.debug( "{0}Result of a lost fumble is {1}".format( self.ind, lostFumble)) if lostFumble: try: newPossession.start = self.copMap[ playData.possession.start] except: newPossession.setPreviousStart() else: newPossession.start = playData.possession.start self.logger.debug("{0}Fumble Old possession is {1}".format( self.ind, playData.possession.start)) self.logger.debug("{0}Fumble New possession is {1}".format( self.ind, newPossession.start)) changes.append(idr) gameData[idr].plays[dp] = playData if lostFumble: newPlayData = playsummary(possession=newPossession, start=playData.start.copy(), play=newReturnPlay, valid=playData.valid) newReturnPlay.connectedPlays.append(playData) playData.play.connectedPlays.append(newReturnPlay) drivePlays.insert(dp + 1, newPlayData) break self.logger.debug("{0}Found {1} Drives With Splits in {2}()".format( self.ind, len(changes), fname)) for idr in set(changes): self.dc.showDrive(gameData[idr], idr, "Drive {0}".format(idr)) return gameData
def splitPunt(self, gameData): fname = sys._getframe().f_code.co_name self.logger.debug("\n{0}{1}()".format(self.ind, fname)) changes = [] mixposs = mixedpossession() for idr in range(len(gameData)): drivePlays = gameData[idr].plays for dp in range(len(drivePlays)): playData = drivePlays[dp] if playData.valid is not True: continue if isinstance(playData.play, puntplay): ## Ignore if there is a safety if playData.play.pa.getKey("safety") is True: continue self.logger.debug("{0} Punt Play: {1}".format( self.ind, playData.play.text)) newReturnPlay = returnplay(text=playData.play.text) newReturnPlay.pa.puntplay = False newReturnPlay.pa.touchdown = playData.play.pa.touchdown newReturnPlay.pa.fumble = playData.play.pa.fumble newReturnPlay.pa.runback = playData.play.pa.runback playData.play.pa.touchdown = False playData.play.pa.fumble = False playData.play.pa.runback = False playData = mixposs.determinePunt(playData, drivePlays, dp, debug=False) newPossession = playpossession(start=None, end=None, text=playData.play.text) newPossession.start = self.flipPossession( playData.possession) try: newPossession.start = self.copMap[ playData.possession.start] except: newPossession.start = playData.possession.setUnknownStart( ) newPlayData = playsummary(possession=newPossession, start=playData.start.copy(), play=newReturnPlay, valid=playData.valid) drivePlays.insert(dp + 1, newPlayData) newReturnPlay.connectedPlays.append(playData) playData.play.connectedPlays.append(newReturnPlay) changes.append(idr) ## Check if the first play of the next drive is unknown try: if not gameData[idr + 1].plays[0].possession.isKnownStart(): gameData[idr + 1].plays[ 0].possession.start = newPossession.start except: pass break self.logger.debug("{0}Found {1} Drives With Splits in {2}()".format( self.ind, len(changes), fname)) for idr in set(changes): self.dc.showDrive(gameData[idr], idr, "Drive {0}".format(idr)) return gameData
def parseGames(self, gameID=None, test=False, debug=False, verydebug=False): self.logger.info("Parsing Games") if self.hist is None: raise ValueError("Must set historical class!") sep = "======================================================" if verydebug: debug = True self.unknownPlays = [] self.toughParsing = ['400547724'] self.poorlyParsed = [ '401012731', '400547781', '400547808', '400548070', '400548428', '400610207', '400547822' ] self.poorlyParsed += [ '400547970', '400547835', '400548026', '400548167', '400547827', '400548458' ] self.poorlyParsed += [ '400547901', '400547976', '400548246', '400548278', '400548292', '400548448' ] self.statsToGet = {} self.badGames = {} self.goodGames = {} dc = debugclass() files = self.hist.getGamesResultsFiles() for ifile in files: try: year = int(getBaseFilename(ifile).split("-")[0]) except: raise ValueError("Could not get year from {0}".format(ifile)) if year != 2018: continue self.logger.info(" Parsing Games from {0}".format(year)) yearData = getFile(ifile) seasonData = self.hist.getSeasonResultsData(year) statsData = self.hist.getStatisticsResultsData(year) augmentedStatsData = self.hist.getStatisticsAugmentedData(year) totalGames = 0 for gameIdent, gameData in yearData.items(): if gameID is not None: if gameID != gameIdent: continue if gameIdent in self.hist.noGameData or gameIdent in self.poorlyParsed or gameIdent in self.toughParsing: continue self.logger.info(" Parsing Game ID {0}".format(gameIdent)) teamsMetaData = gameData["Teams"] homeTeamMetaData = teamsMetaData["Home"] awayTeamMetaData = teamsMetaData["Away"] driveData = gameData["Plays"] ################################################################################ ### Get maps ################################################################################ fieldMap = self.makeFieldMap(awayTeamMetaData, homeTeamMetaData) copmap = self.makeCopMap(awayTeamMetaData, homeTeamMetaData) ################################################################################ ### Get team data ################################################################################ homeTeamGameData = self.getTeamGameData( gameIdent, seasonData, homeTeamMetaData) if homeTeamGameData is None: continue awayTeamGameData = self.getTeamGameData( gameIdent, seasonData, awayTeamMetaData) if awayTeamGameData is None: continue ################################################################################ ### Learn key plays for use in determining possession ################################################################################ players = gameplayers(teamsMap=fieldMap, statsData=statsData) players.augmentData(augmentedStatsData) pfp = possessionfromplayer(players) ps = playstart() pc = playclock() pt = playtype() ap = analyzepossession(copmap, players) ay = analyzeyards() ak = analyzekicking() apen = analyzepenalties() pcc = possessionchangeclass(copmap) gameResult = [] totalPlays = 0 ################################################################################ ### Collect Post Drive Scores ################################################################################ postDriveScores = {"Drives": [], "Final": []} postDriveScores["Final"] = [ awayTeamGameData.teamAScore, homeTeamGameData.teamAScore ] ################################################################################ ### Iterate over drives ################################################################################ for idr, drive in enumerate(driveData): self.logger.debug("\n\n{0}".format(2 * sep)) self.logger.debug("{0}Parsing Plays for Drive {1}".format( self.ind, idr)) ds = drivesummary(drive, fieldMap) drivePlays = ds.getDrivePlays() postDriveScores["Drives"].append(ds.getPostDriveScore()) ################################################################################ ### Iterate over plays in drive ################################################################################ driveResults = [] for ipl, drivePlay in enumerate(drivePlays): #playNo = drivePlay['Play'] playStartText = drivePlay['Start'] playData = drivePlay['Data'] self.logger.debug("\n {0}".format(sep)) self.logger.debug("{0} Play {1}/{2}: {3}".format( self.ind, ipl, len(drivePlays), playData)) ### Determine play starting position startVals = ps.getStart(playStartText) ### Determine play clock and quarter pc.parsePlay(playData) startVals.setClock(pc) playText = pc.getPlayText() ### Determine play type play = pt.getPlay(playText) # ### Determine possession playPossession = pfp.determinePossession(play) if playPossession.isForced() is not None: play.pa.forced = playPossession.isForced() ### Result of play playResult = playsummary(possession=playPossession, start=startVals, play=play, valid=play.valid) ### Save and move on totalPlays += 1 driveResults.append(playResult) continue ### Check if we need to insert a play #newPlay = self.addPlay(gameIdent, idr, ipl, playResult, possData, verydebug) #if newPlay is not None: # totalPlays += 1 # driveResults.append(newPlay) fullDriveData = ds.getFullDrive() fullDriveData.setPlays(driveResults) #fullDriveData = self.insertMissingData(gameIdent, idr, fullDriveData, debug) #fullDriveData = self.augmentPlayWithScore(fullDriveData, fieldMap, debug) gameResult.append(fullDriveData) ################################################################################ ### Show State Before Alterations ################################################################################ self.logger.debug("\n{0}".format(2 * sep)) self.logger.debug("{0}Found {1} Drives For This Game".format( self.ind, len(gameResult))) self.logger.debug("\n{0}\n".format(2 * sep)) ################################################################################ ### Analyze Possession ################################################################################ dc.showGame(gameResult) gameResult = ap.continuity(gameResult) gameResult = pcc.splitChangeOfPossession(gameResult) gameResult = ap.continuity(gameResult) gameResult = ap.returns(gameResult) gameResult = ap.pats(gameResult) gameResult = ap.endofgame(gameResult, postDriveScores) gameResult = ap.noplays(gameResult) gameResult = ap.nextplay(gameResult) gameResult = ap.endofdrive(gameResult) dc.showGame(gameResult, "Game") gameResult = ay.analyze(gameResult) gameResult = ak.kickoffs(gameResult) gameResult = ak.returns(gameResult) #gameResult = apen.penalties(gameResult) #gameResult = apen.isPenaltyAdditive(gameResult) scoreResult = ap.gamescore(gameResult, postDriveScores) if scoreResult is False: if gameID is None: self.badGames[gameIdent] = True continue dc.showGame(gameResult, "Score Is Not Corrent") dc.showGame(gameResult, "Good Game") totalGames += 1 if debug: self.logger.info("Found {0} plays in this game {1}".format( totalPlays, gameID)) self.logger.info("Found {0} total games for {1}".format( totalGames, ifile))