Example #1
0
 def _transpire(self):
     """Play out the at-bat."""
     # TODO substitutions will change where this should be done
     assert not self.resolved, "Call to _transpire() of already resolved AtBat."
     while not self.resolved:
         self.playing_action = None  # Don't retain prior playing action
         # Players get in position, pitcher decides his pitch
         PitchInterim(at_bat=self)
         # The pitch...
         pitch = self.pitcher.pitch(at_bat=self)
         if not pitch.bean:
             self.batter.decide_whether_to_swing(pitch)
             if not self.batter.will_swing:
                 # Catcher attempts to receive pitch
                 pitch.caught = self.catcher.receive_pitch(pitch)  # TODO wild pitches, passed balls
                 # Umpire makes his call
                 pitch.call = pitch.would_be_call
                 if pitch.call == "Strike":
                     Strike(pitch=pitch, looking=True)
                 elif pitch.call == "Ball":
                     Ball(pitch=pitch)
             # ...the swing...
             elif self.batter.will_swing:
                 self.batter.decide_swing(pitch)
                 swing = self.batter.swing(pitch)
                 if not swing.contact:
                     # ...swing and a miss!
                     Strike(pitch=pitch, looking=False)
                 elif swing.foul_tip:
                     # ...foul tip
                     foul_tip = swing.result
                     if self.catcher.receive_foul_tip():
                         Strike(pitch=pitch, looking=False, foul_tip=foul_tip)
                     else:
                         # ...foul ball
                         FoulBall(batted_ball=foul_tip)
                 elif swing.contact:
                     # ...the ball is hit!
                     self.playing_action = PlayingAction(batted_ball=swing.result)
                     self.playing_action.enact()
                     if self.batter.safely_on_base:
                         self.resolved = True
     if self.playing_action:
         self._review()
Example #2
0
class AtBat(object):
    """An at-bat in a frame."""

    def __init__(self, frame):
        """Initialize an AtBat object."""
        self.game = frame.game
        self.frame = frame
        frame.at_bats.append(self)
        # Set attributes for record keeping
        self.pitcher = frame.pitching_team.roster.pitcher
        self.catcher = frame.pitching_team.roster.catcher
        self.fielders = list(frame.pitching_team.roster.fielders)
        self.umpire = self.game.umpire
        # Summon the next batter to the plate
        self.batter = frame.batting_team.roster.next_batter()
        # Prepare attributes
        self.pitches = []
        self.pitch_interims = []
        self.balls = 0
        self.strikes = 0
        self.count = 00  # See playing_action.PitchInterim for info on how counts are represented
        self.playing_action = None  # This gets set by _transpire(), as appropriate
        self.outs = []  # Keep track of this so that we can listen for double- and triple plays
        self.resolved = False
        self.result = None
        self.run_queue = []  # Potential runs; will be counted only if a third out isn't recorded during the play
        if self.game.trace:
            print "1B: {}, 2B: {}, 3B: {}, AB: {}".format(frame.on_first, frame.on_second, frame.on_third, self.batter)
        if not self.game.radio_announcer:
            self._transpire()
        if self.game.radio_announcer:
            self.game.radio_announcer.call_at_bat(at_bat=self)  # This will _transpire the at-bat midway

    def _transpire(self):
        """Play out the at-bat."""
        # TODO substitutions will change where this should be done
        assert not self.resolved, "Call to _transpire() of already resolved AtBat."
        while not self.resolved:
            self.playing_action = None  # Don't retain prior playing action
            # Players get in position, pitcher decides his pitch
            PitchInterim(at_bat=self)
            # The pitch...
            pitch = self.pitcher.pitch(at_bat=self)
            if not pitch.bean:
                self.batter.decide_whether_to_swing(pitch)
                if not self.batter.will_swing:
                    # Catcher attempts to receive pitch
                    pitch.caught = self.catcher.receive_pitch(pitch)  # TODO wild pitches, passed balls
                    # Umpire makes his call
                    pitch.call = pitch.would_be_call
                    if pitch.call == "Strike":
                        Strike(pitch=pitch, looking=True)
                    elif pitch.call == "Ball":
                        Ball(pitch=pitch)
                # ...the swing...
                elif self.batter.will_swing:
                    self.batter.decide_swing(pitch)
                    swing = self.batter.swing(pitch)
                    if not swing.contact:
                        # ...swing and a miss!
                        Strike(pitch=pitch, looking=False)
                    elif swing.foul_tip:
                        # ...foul tip
                        foul_tip = swing.result
                        if self.catcher.receive_foul_tip():
                            Strike(pitch=pitch, looking=False, foul_tip=foul_tip)
                        else:
                            # ...foul ball
                            FoulBall(batted_ball=foul_tip)
                    elif swing.contact:
                        # ...the ball is hit!
                        self.playing_action = PlayingAction(batted_ball=swing.result)
                        self.playing_action.enact()
                        if self.batter.safely_on_base:
                            self.resolved = True
        if self.playing_action:
            self._review()

    def _review(self):
        """Review the at-bat to effect its outcomes and record statistics."""
        # Score any runs that remain in the run queue -- these are runs whose being scored
        # depended on the at bat not ending with a fly out or force out
        for run in self.run_queue:
            run.dequeue()
        # Check for whether a hit was made; if one was, instantiate the appropriate outcome object
        # [Note: if the batter-runner was part of a call at a base, PlayAtBaseCall.__init__() will
        # score the hit -- in those cases it is precluded here by self.result having already been
        # attributed by the scored hit]
        if not self.result and self.batter.base_reached_on_hit:
            if self.batter.base_reached_on_hit == "1B":
                Single(playing_action=self.playing_action, call=None)
            elif self.batter.base_reached_on_hit == "2B":
                Double(playing_action=self.playing_action, call=None)
            elif self.batter.base_reached_on_hit == "3B":
                Triple(playing_action=self.playing_action, call=None)
            elif self.batter.base_reached_on_hit == "H":
                HomeRun(batted_ball=self.playing_action.batted_ball, call=None, inside_the_park=True)
        # Next, check for whether a double- or triple play was turned -- if one was, instantiate
        # the appropriate outcome object
        if len(self.outs) == 2:
            DoublePlay(at_bat=self, outs=self.outs)
        elif len(self.outs) == 3:
            TriplePlay(at_bat=self, outs=self.outs)
        # Lastly, survey for which bases are now occupied and by whom
        if self.playing_action.running_to_third and self.playing_action.running_to_third.safely_on_base:
            self.frame.on_third = self.playing_action.running_to_third
        elif self.playing_action.retreating_to_third and self.playing_action.retreating_to_third.safely_on_base:
            self.frame.on_third = self.playing_action.retreating_to_third
        else:
            self.frame.on_third = None
        if self.playing_action.running_to_second and self.playing_action.running_to_second.safely_on_base:
            self.frame.on_second = self.playing_action.running_to_second
        elif self.playing_action.retreating_to_second and self.playing_action.retreating_to_second.safely_on_base:
            self.frame.on_second = self.playing_action.retreating_to_second
        else:
            self.frame.on_second = None
        if self.playing_action.running_to_first and self.playing_action.running_to_first.safely_on_base:
            self.frame.on_first = self.playing_action.running_to_first
        elif self.playing_action.retreating_to_first and self.playing_action.retreating_to_first.safely_on_base:
            self.frame.on_first = self.playing_action.retreating_to_first
        else:
            self.frame.on_first = None