In [2]:
import random, math
import numpy as np

Basketball Simulation Code

Our goal for this project is to create a monte carlo simulation model


oncourt(team)

this function chooses which players are on the court during a given possession. This takes in information on the team as an argument which must be a dictionary. Team is made up of players and one of the player attributes needs to be minutes played. Returns a list of five players.

We need to build this as a method of the team class. Then for each possession, we can call HomeTeam.oncourt()


In [95]:
def oncourt(team):        
    playermin =[]
    for x in team:
        playermin.append(x.minutes())
    
    totalmin = sum(playermin)
    
    
    
    for x in team:
        x.playprob(playermin)
    
    
    for x in team:
        
    for key in keys:
        pp_team.extend([key]*team[key][pl_min])

    active = []
    while len(active)<=4:
        add = random.choice(pp_team)
        try:
            active.index(add)
        except ValueError:
            active.append(add)
    return active

In [ ]:
HomeOnCourt = oncourt(HomeTeam)
AwayOnCourt = oncourt(AwayTeam)

In [197]:
playermin=[]
for x in TeamFirstYear:
    playermin.append(x.minutes())

In [12]:
HomeTeam[4].persfoul()
HomeTeam[4].game_pfoul


Amanda Miller committed a personal foul
Out[12]:
1

In [14]:
HomeTeam[4].playprob(389)
HomeTeam[4]._PT


Out[14]:
0.2544987146529563


In [76]:
daniel= [15, 8, 3, 20, 17, 8, .18, 99, .04, 'McIntosh', 'Daniel', 'FirstYear']
bradley= [15, 8, 3, 20, 17, 8, .18, 99, .04, 'Fay', 'Bradley', 'FirstYear']
tom= [15, 8, 3, 20, 17, 8, .18, 99, .04, 'Scovic', 'Tom', 'FirstYear']
john= [15, 8, 3, 20, 17, 8, .18, 99, .04, 'Prewitt', 'John', 'FirstYear']
amanda= [15, 8, 3, 20, 17, 8, .18, 99, .04, 'Miller', 'Amanda', 'FirstYear']
cameron= [15, 8, 3, 20, 17, 8, .18, 99, .04, 'North', 'Cameron', 'FirstYear']
lindsay= [15, 8, 3, 20, 17, 8, .18, 99, .04, 'Nicholl', 'Lindsay', 'FirstYear']
jennifer= [15, 8, 3, 20, 17, 8, .18, 99, .04, 'Clark', 'Jenn', 'FirstYear']
alyson= [15, 8, 3, 20, 17, 8, .18, 99, .04, 'Boyd', 'Alyson', 'FirstYear']
gordon= [15, 8, 3, 20, 17, 8, .18, 99, .04, 'Crape', 'Gordon', 'FirstYear']
kristen= [15, 8, 3, 20, 17, 8, .18, 99, .04, 'Arnold', 'Kristen', 'FirstYear']

clee = [15, 8, 3, 20, 17, 8, .18, 99, .04, 'Lee', 'Kristen', 'SecondYear']
bourke = [15, 8, 3, 20, 17, 8, .18, 99, .04, 'Bourke', 'Kristen', 'SecondYear']
gerken = [15, 8, 3, 20, 17, 8, .18, 99, .04, 'Gerken', 'Kristen', 'SecondYear']
milan = [15, 8, 3, 20, 17, 8, .18, 99, .04, 'Milan', 'Kristen', 'SecondYear']
walsh = [15, 8, 3, 20, 17, 8, .18, 99, .04, 'Walsh', 'Kristen', 'SecondYear']
rubens = [15, 8, 3, 20, 17, 8, .18, 99, .04, 'Rubens', 'Kristen', 'SecondYear']
sambrook = [15, 8, 3, 20, 17, 8, .18, 99, .04, 'Sambrook', 'Kristen', 'SecondYear']
lang = [15, 8, 3, 20, 17, 8, .18, 99, .04, 'Lang', 'Kristen', 'SecondYear']
mooney = [15, 8, 3, 20, 17, 8, .18, 99, .04, 'Mooney', 'Kristen', 'SecondYear']
yanni = [15, 8, 3, 20, 17, 8, .18, 99, .04, 'Yanni', 'Kristen', 'SecondYear']

#firstyear = {0:daniel,1:bradley,2:tom,3:john,4:amanda,5:cameron,6:lindsay,7:jennifer,8:alyson,9:gordon,10:kristen}
#secondyear = {0:clee,1:bourke,2:gerken,3:milan,4:walsh,5:rubens,6:sambrook,7:lang,8:mooney,9:yanni}

firstyear = [daniel, bradley, tom, john, amanda, cameron, lindsay, jennifer, alyson, gordon, kristen]
HomeTeam = [Player(teammate) for teammate in firstyear]

secondyear = [clee, bourke, gerken, milan, walsh, rubens, sambrook, lang, mooney, yanni]
AwayTeam = [Player(teammate) for teammate in secondyear]


matchup = (firstyear, secondyear)
score = [0,0]

In [8]:
for x in AwayTeam:
    print x.lastName()


Lee
Bourke
Gerken
Milan
Walsh
Rubens
Sambrook
Lang
Mooney
Yanni

In [93]:
def get_counts(sequence):
    counts = {}
    for x in sequence:
        if x in counts:
            counts[x] += 1
        else:
            counts[x] = 1
    return counts

In [102]:
players=[]
x=0
while x<1000:
    players.append(oncourt(firstyear))
    x+=1
playingtime=[]
for x in players:
    for y in x:
        playingtime.append(y)
        
        
get_counts(playingtime)


Out[102]:
{0: 772,
 1: 296,
 2: 863,
 3: 254,
 4: 272,
 5: 246,
 6: 268,
 7: 259,
 8: 585,
 9: 902,
 10: 283}

ShotFunction


In [ ]:
def shotfunction(player):
    twocount = player[4]     ##Map this to the rate at which a player shoots 2pts  
    threecount = player[5]   ##Map this to the rate at which a player shoots 3pts
    ftcount = player[3]
    twomake = player[1]/1000.0     ##Map this to the players success rate at 2ptrs       
    threemake = player[2]/1000.0   ##Map this to the players success rate at 3ptrs      
    ftmake = player[0]/1000.0      ##Map this to the players success rate at Free Throws 
    success = 0
    
    totalshots = twocount + threecount + ftcount      ##Double check to make sure FT's aren't overweighted using this
  
    #Choosing the type of shot taken
    shottype = np.random.uniform(0,totalshots)
    if shottype <= twocount:   #Two point
        success = np.random.binomial(1,twomake)*2
        if success>0:
            print "%s made a 2 pointer" % player
        else:
            print "%s missed a 2 pointer" %player
    elif shottype <= (twocount+threecount):  ##Three pointer
        success = np.random.binomial(1,threemake)*3
        if success>0:
            print "%s made a 3 pointer" % player
        else:
            print "%s missed a 3 pointer" %player
    else:  ##Free Throw
        numft = 
        pass
    ###Currently only using share of shots to compute free throws. Need to account for when free throws actually occur. Also, when free throw occurs, needs to assign a foul.
    return success

         else:
            numft = numpy.random.binomial(1,.8)+1   ##number of FTs shot by player. Need to revist .8 probability to see if there is a measure of how many FTs shot
            if numft == 1: ## only one shot
                  success= numpy.random.binomial(1,ftmake)*1
                  print "made", success, "of 1 FT's"
                  return success
            else: ## 1 and 1 or double bonus situations
                success1=numpy.random.binomial(1,ftmake)*1
                if success1==0:  ##missed first ft
                    doublebonus = numpy.random.binomial(1,.8) ##roll to see if we get second shot
                    if doublebonus == 1: ## This is a double bonus situation
                        success2=numpy.random.binomial(1,ftmake)*1
                        success= 0+success2
                        if success2>0:
                            print "made 1 of 2 FT's missing first, double bonus"
                        else:
                            print "missed both FT's, double bonus"
                        return success
                    else: ## This is a one and one situation
                        print "missed the front end of a 1 and 1"
                        return success
                else: ##made first ft
                    success2=numpy.random.binomial(1,ftmake)*1
                    success= 1+success2
                    print "made", success, "of 2FT's, making first"
                    return success
    ##return success  ###Make sure we account for make, miss rebound issues

Situations which result in foul shots

  • fouled shooting a two, miss two => 2 shots
  • fouled shooting a two, make two => 1 shot
  • fouled shooting a three, miss three => 3 shots
  • fouled shooting a three, make three => 1 shot
  • Technical foul => 1 shot
  • fouled not shooting, one and bonus => 1 or 2 shots
  • fouled not shooting, double bonus => 2 shots

Here is the formula for incrementing FGA accounting for being fouled

Shot taken - (Fouled * (1-shot make))       

In [81]:
def foulFcn(player):
    fouled = np.random.binomial(1,.4)
    if fouled ==1:
        if player in HomeTeam:
            fouler = random.choice(AwayTeam)
            fouler.persfoul()
        else:
            fouler = random.choice(HomeTeam)
            fouler.persfoul()
    return fouled

In [68]:
def twoPtFGA(player,fouled,tworate):
    attempt = 2
    success = np.random.binomial(1,tworate)*2
    if success>0:
        success += fouled*player.freethrow()
        pbp = "%s %s made a 2 pointer" %(player.firstName(), player.lastName())
        if fouled==1:
            pbp = pbp + ' and was fouled, resulting in a %s point play' % success
    else:
        success += fouled*player.freethrow()
        success += fouled*player.freethrow()
        pbp = "%s %s missed a 2 pointer" %(player.firstName(), player.lastName())
        if fouled==1:
            pbp = pbp + ' But was fouled, resulting in a %s point play' % success
            
    return attempt, success, pbp

In [69]:
def threePtFGA(player,fouled,threerate):    
    attempt=3
    success = np.random.binomial(1,threerate)*3
    if success>0:
        success += fouled*player.freethrow()
        pbp =  "%s %s made a 3 pointer" %(player.firstName(), player.lastName())
        if fouled==1:
            pbp = pbp + ' and was fouled, resulting in a %s point play' % success
    else:
        success += fouled*player.freethrow()
        success += fouled*player.freethrow()
        success += fouled*player.freethrow()
        pbp = "%s %s missed a 3 pointer" %(player.firstName(), player.lastName())
        if fouled==1:
            pbp = pbp + ' But was fouled, resulting in a %s point play' % success
            
    return attempt, success, pbp

Below is an abridged version of the jumpshot function that employs nested functions foulFcn, twoPtGMA, and threePtFGA. The code directly below is the unabridged version with the coat not wrapped in functions


In [66]:
def jumpshot(player):
    twocount = player.fga()     ##Map this to the rate at which a player shoots 2pts  
    threecount = player.p3fga()  ##Map this to the rate at which a player shoots 3pts
    twomake = player.fgm()     ##Map this to the players success rate at 2ptrs       
    threemake = player.p3fgm()   ##Map this to the players success rate at 3ptrs      
    success = 0
    totalshots = twocount + threecount     ##Double check to make sure FT's aren't overweighted using this
    
    fouled = foulFcn(player)    
    
    tworate = twomake/float(twocount)
    
    threerate = threemake/float(threecount)

    #Choosing the type of shot taken
    shottype = np.random.uniform(0,totalshots)
    if shottype <= twocount:   #Two point
        attempt,success,pbp = twoPtFGA(player,fouled,tworate)
    else:  ##Three pointer
        attempt,success,pbp = threePtFGA(player,fouled,threerate)
    
    #player.game_FGA.append(attempt)
    #player.game_FGM.append(success)
    
    print pbp
    return [fouled,attempt,success]

unabridged jumpshot function


In [165]:
def jumpshot(player):
    twocount = player.fga()     ##Map this to the rate at which a player shoots 2pts  
    threecount = player.p3fga()  ##Map this to the rate at which a player shoots 3pts
    twomake = player.fgm()     ##Map this to the players success rate at 2ptrs       
    threemake = player.p3fgm()   ##Map this to the players success rate at 3ptrs      
    success = 0
    totalshots = twocount + threecount     ##Double check to make sure FT's aren't overweighted using this
    
    fouled = np.random.binomial(1,.4)
    if fouled ==1:
        if player in HomeTeam:
            fouler = random.choice(AwayTeam)
            fouler.persfoul()
        else:
            fouler = random.choice(HomeTeam)
            fouler.persfoul()    
    
    tworate = twomake/float(twocount)
    
    threerate = threemake/float(threecount)

    #Choosing the type of shot taken
    shottype = np.random.uniform(0,totalshots)
    if shottype <= twocount:   #Two point
        attempt = 2
        success = np.random.binomial(1,tworate)*2
        if success>0:
            success += fouled*player.freethrow()
            pbp = "%s %s made a 2 pointer" %(player.firstName(), player.lastName())
            if fouled==1:
               pbp = pbp + ' and was fouled resulting in a %s point play' % success
        else:
            success += fouled*player.freethrow()
            success += fouled*player.freethrow()
            pbp = "%s %s missed a 2 pointer" %(player.firstName(), player.lastName())
            if fouled==1:
                pbp = pbp + ' But was fouled resulting in a %s point play' % success
    else:  ##Three pointer
        attempt=3
        success = np.random.binomial(1,threerate)*3
        if success>0:
            success += fouled*player.freethrow()
            pbp =  "%s %s made a 3 pointer" %(player.firstName(), player.lastName())
            if fouled==1:
                pbp = pbp + ' and was fouled resulting in a %s point play' % success
        else:
            success += fouled*player.freethrow()
            success += fouled*player.freethrow()
            success += fouled*player.freethrow()
            pbp = "%s %s missed a 3 pointer" %(player.firstName(), player.lastName())
            if fouled==1:
                pbp = pbp + ' But was fouled resulting in a %s point play' % success
    #player.game_FGA.append(attempt)
    #player.game_FGM.append(success)
    print pbp
    return [fouled,attempt,success]

player class definition


In [10]:
class Player():
    #def __init__(self, FTM, TwM, ThM, FTA, TwA, ThA, TOr, MIN, Frate, lname, fname, team):
    def __init__(self,player):
        self._FTM = player[0]
        self._FTA = player[3]
        self._FGM = player[1]+player[2]
        self._FGA = player[4]+player[5]
        self._P3FGM = player[2]
        self._P3FGA = player[5]
        #self._REB = RBr
        self._TO = player[6]
        self._MIN = player[7]
        self._FORCE = player[8]
        self._LName = player[9]
        self._FName = player[10]
        self._TEAM = player[11]
        self._FTRate = self._FTM/float(self._FTA)
        self.game_pfoul = 0  ##delete and add to game subclass

    def lastName(self):
        return self._LName
    def firstName(self):
        return self._FName
    def team(self):
        return self._TEAM
    def fgm(self):
        return self._FGM
    def fga(self):
        return self._FGA
    def p3fgm(self):
        return self._P3FGM
    def p3fga(self):
        return self._P3FGA
    def minutes(self):
        return self._MIN
    def playtime(self):
        return self._PT
        
    def freethrow(self):
        ftmake = np.random.binomial(1,self._FTRate)
        return ftmake
    
    def playprob(self, teammin):
        self._PT = self._MIN/float(teammin)

        
    ##Game class
    
    def persfoul(self):
        self.game_pfoul+=1
        print '%s %s committed a personal foul' %(self._FName, self._LName)
        if self.game_pfoul == 6:
            self._MIN = 0
            print '%s %s fouled out!' %(self._FName, self._LName)

In [140]:
##These are Cumulative Season Stats
    FGM= FGA= P3FGM= P3FGA= FTM= FTA=0
    OREB= DREB=0
    REB=OREB+DREB
    AST= STL= BLK= TO= PF=0
    FGPct= P3FGPct= FTPct=0
    PTS=2*(FGM-P3FGM)+3*P3FGM+1*FTM
    Team = "FreeAgent"
    
    ##These are in-game stats
    
            def __init__(self):
                self.FGM = self.FGM
                self.FGA = self.FGA
                self.P3FGA = self.P3FGA
                self.P3FGM = self.P3FGM
                self.FTM = self.FTM
                self.FTA = self.FTA
                self.OREB = self.OREB
                self.DREB = self.DREB
                self.REB = self.REB
                self.AST = self.AST
                self.STL = self.STL
                self.BLK = self.BLK
                self.TO = self.TO
                self.PF = self.PF
    
        def shooting(self):
            try:
                self.FGPct=float(self.FGM)/float(self.FGA)
                self.P3FGPct=float(self.P3FGM)/float(self.P3FGA)
                self.FTPct=float(self.FTM)/float(self.FTA)
            except: ZeroDivisionError
                print self.FGPct, self.P3FGPct, self.FTPct
        
        def freethrow(self):
            ftmake = np.random.binomial(1,self.FTRate)
            return ftmake


  File "<ipython-input-140-b2e8cc723bcb>", line 3
    FGM= FGA= P3FGM= P3FGA= FTM= FTA=0
    ^
IndentationError: unexpected indent

Team Class specification

Need to figure out how to assign a class to a list where the list is comprised of objects.

Basically, I want to compute team statistics using numbers that are taken from the members of the team. For example, to compute the total number of minutes played on a list of [Player1, Player2] where element of the list is an object with an attribute ._PT


In [51]:
class Team():
    def __init__(self):
        self._Conference = 'conference'
        self._Division = 'division'
        
    def DIV(self):
        return self._Division
    
    def oncourt(self):        
        _playerMin =[]
        for x in self:
            _playerMin.append(x.minutes())
        teamMin = sum(_playermin)

In [82]:
x=0
while x <100:
    jumpshot(HomeTeam[0])
    x+=1


Kristen Milan committed a personal foul
Daniel McIntosh made a 2 pointer and was fouled resulting in a 3 point play
Daniel McIntosh missed a 3 pointer
Daniel McIntosh made a 3 pointer
Kristen Lee committed a personal foul
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 1 point play
Daniel McIntosh missed a 2 pointer
Daniel McIntosh made a 2 pointer
Daniel McIntosh made a 2 pointer
Daniel McIntosh made a 2 pointer
Daniel McIntosh missed a 3 pointer
Kristen Mooney committed a personal foul
Daniel McIntosh made a 2 pointer and was fouled resulting in a 3 point play
Daniel McIntosh missed a 2 pointer
Daniel McIntosh made a 2 pointer
Daniel McIntosh made a 2 pointer
Daniel McIntosh missed a 2 pointer
Kristen Yanni committed a personal foul
Daniel McIntosh made a 2 pointer and was fouled resulting in a 3 point play
Kristen Mooney committed a personal foul
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 2 point play
Kristen Yanni committed a personal foul
Daniel McIntosh made a 2 pointer and was fouled resulting in a 3 point play
Daniel McIntosh made a 2 pointer
Daniel McIntosh made a 2 pointer
Kristen Walsh committed a personal foul
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 1 point play
Kristen Walsh committed a personal foul
Daniel McIntosh made a 2 pointer and was fouled resulting in a 3 point play
Daniel McIntosh missed a 2 pointer
Kristen Gerken committed a personal foul
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 2 point play
Kristen Walsh committed a personal foul
Kristen Walsh fouled out!
Daniel McIntosh made a 2 pointer and was fouled resulting in a 2 point play
Daniel McIntosh missed a 2 pointer
Kristen Walsh committed a personal foul
Daniel McIntosh made a 2 pointer and was fouled resulting in a 2 point play
Daniel McIntosh missed a 3 pointer
Kristen Walsh committed a personal foul
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 1 point play
Daniel McIntosh missed a 3 pointer
Kristen Gerken committed a personal foul
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 2 point play
Kristen Bourke committed a personal foul
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 2 point play
Daniel McIntosh made a 2 pointer
Daniel McIntosh missed a 2 pointer
Daniel McIntosh missed a 2 pointer
Daniel McIntosh made a 2 pointer
Kristen Rubens committed a personal foul
Daniel McIntosh made a 2 pointer and was fouled resulting in a 3 point play
Kristen Rubens committed a personal foul
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 2 point play
Kristen Gerken committed a personal foul
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 2 point play
Daniel McIntosh missed a 2 pointer
Daniel McIntosh made a 2 pointer
Daniel McIntosh made a 2 pointer
Kristen Bourke committed a personal foul
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 1 point play
Daniel McIntosh missed a 2 pointer
Daniel McIntosh made a 2 pointer
Daniel McIntosh missed a 3 pointer
Daniel McIntosh made a 2 pointer
Kristen Yanni committed a personal foul
Daniel McIntosh missed a 3 pointer But was fouled resulting in a 2 point play
Daniel McIntosh missed a 2 pointer
Daniel McIntosh made a 2 pointer
Kristen Walsh committed a personal foul
Daniel McIntosh made a 2 pointer and was fouled resulting in a 3 point play
Daniel McIntosh missed a 2 pointer
Kristen Bourke committed a personal foul
Daniel McIntosh made a 3 pointer and was fouled resulting in a 4 point play
Daniel McIntosh missed a 3 pointer
Kristen Bourke committed a personal foul
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 1 point play
Daniel McIntosh made a 2 pointer
Daniel McIntosh missed a 3 pointer
Kristen Rubens committed a personal foul
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 1 point play
Daniel McIntosh missed a 2 pointer
Kristen Rubens committed a personal foul
Kristen Rubens fouled out!
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 2 point play
Kristen Bourke committed a personal foul
Kristen Bourke fouled out!
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 1 point play
Kristen Lee committed a personal foul
Daniel McIntosh missed a 3 pointer But was fouled resulting in a 3 point play
Daniel McIntosh missed a 2 pointer
Daniel McIntosh missed a 2 pointer
Kristen Yanni committed a personal foul
Daniel McIntosh made a 2 pointer and was fouled resulting in a 2 point play
Kristen Lang committed a personal foul
Daniel McIntosh made a 2 pointer and was fouled resulting in a 3 point play
Daniel McIntosh missed a 2 pointer
Daniel McIntosh missed a 2 pointer
Kristen Lang committed a personal foul
Daniel McIntosh made a 2 pointer and was fouled resulting in a 3 point play
Daniel McIntosh made a 3 pointer
Daniel McIntosh missed a 2 pointer
Kristen Yanni committed a personal foul
Kristen Yanni fouled out!
Daniel McIntosh made a 2 pointer and was fouled resulting in a 3 point play
Kristen Bourke committed a personal foul
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 1 point play
Daniel McIntosh missed a 2 pointer
Kristen Sambrook committed a personal foul
Daniel McIntosh made a 3 pointer and was fouled resulting in a 3 point play
Daniel McIntosh missed a 2 pointer
Daniel McIntosh made a 2 pointer
Kristen Lee committed a personal foul
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 2 point play
Daniel McIntosh missed a 2 pointer
Daniel McIntosh made a 2 pointer
Daniel McIntosh made a 2 pointer
Daniel McIntosh made a 2 pointer
Kristen Sambrook committed a personal foul
Daniel McIntosh made a 3 pointer and was fouled resulting in a 3 point play
Kristen Lee committed a personal foul
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 2 point play
Daniel McIntosh made a 2 pointer
Kristen Mooney committed a personal foul
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 1 point play
Daniel McIntosh made a 2 pointer
Daniel McIntosh missed a 3 pointer
Kristen Yanni committed a personal foul
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 2 point play
Kristen Sambrook committed a personal foul
Daniel McIntosh missed a 2 pointer But was fouled resulting in a 2 point play
Daniel McIntosh missed a 2 pointer
Daniel McIntosh made a 2 pointer
Daniel McIntosh missed a 2 pointer
Daniel McIntosh missed a 3 pointer
Daniel McIntosh made a 2 pointer
Daniel McIntosh missed a 2 pointer
Kristen Mooney committed a personal foul
Daniel McIntosh made a 2 pointer and was fouled resulting in a 3 point play
Daniel McIntosh made a 3 pointer
Daniel McIntosh missed a 2 pointer
Daniel McIntosh made a 2 pointer
Daniel McIntosh made a 3 pointer

In [ ]: