Racquetball using OOD

Simulate a series of racquetball games between two players and record some statistics about the series of games.

Object Candidates:

  • Simulation of the Game
  • Statistics Tracking

Imports

In [1]:
from random import random

Functions

In [2]:
def main():
    games_played = []
    
    # Simple, just make these functions
    print_intro()
    prob_a, prob_b, n = get_inputs()
    
    # We just need on instance of the statistics tracking class, SimStats
    stats = SimStats()
    
    # Play n games of racquetball
    for i in range(n):
        the_game = RBallGame(prob_a, prob_b)
        the_game.play()
        stats.update(the_game)
        games_played.append(the_game)
        
    stats.print_report()
    
    for a_game in games_played:
        print(a_game, "Scores are: ", a_game.get_scores())
In [3]:
def print_intro():
    print("This plays racquetball, good luck I don't know the rules.")
In [4]:
def get_inputs():
    player_a = float(input("What is the prob player A wins a serve? "))
    player_b = float(input("What is the prob player B wins a serve? "))
    n_games = int(input("How many games to simulate? "))
    return player_a, player_b, n_games

Classes

In [5]:
class SimStats:
    def __init__(self):
        # 4 instance variables initializing the state of a SimStats object
        self.wins_a = 0
        self.wins_b = 0
        self.shuts_a = 0
        self.shuts_b = 0
        
    def update(self, a_game):
        # RBallGame instance will return two int values when get_scores() is called
        # a, b are the scores of players A and B
        a, b = a_game.get_scores()
        
        if a > b:
            # Player A won the game
            self.wins_a += 1
            if b == 0:
                self.shuts_a += 1
        else:
            # Player B won the game
            self.wins_b += 1
            if a == 0:
                self.shuts_b += 1
                
    def print_report(self):
        n = self.wins_a + self.wins_b
        print("Summary of", n, "games:\n")
        print("          wins (% total)  shutouts (% wins) ")
        print("-------------------------------------------")
        self.__print_line("A", self.wins_a, self.shuts_a, n)
        self.__print_line("B", self.wins_b, self.shuts_b, n)
        
        
    def __print_line(self, label, wins, shuts, n):
        template = "Player {0}:{1:5}   ({2:5.1%}) {3:11}    ({4})"
        if wins == 0:
            # Avoid division by zero
            shut_str = "-----"
        else:
            shut_str = "{0:4.1%}".format(shuts/wins)
        print(template.format(label, wins, wins/n, shuts, shut_str))
In [6]:
class Player:
    def __init__(self, prob, name="NO_NAME"):
        self.prob = prob
        self.score = 0
        self.name = name
    
    def wins_serve(self):
        return random() <= self.prob
    
    def inc_score(self):
        self.score += 1
    
    def get_score(self):
        return self.score
    
    def get_name(self):
        return self.name.title()
    
    def __repr__(self):
        if self.name == "NO_NAME":
            return "Player({0})".format(self.prob)
        else:
            return "Player({0}, name=\"{1}\")".format(self.prob, self.name)
In [7]:
test_player_1 = Player(0.54)
test_player_2 = Player(0.43, name="bob")
In [8]:
print(test_player_1, test_player_2)
Player(0.54) Player(0.43, name="bob")
In [9]:
Player(0.43, name="bob")
Out[9]:
Player(0.43, name="bob")
In [10]:
class RBallGame:
    def __init__(self, prob_a, prob_b):
        self.player_a = Player(prob_a)
        self.player_b = Player(prob_b)
        self.server = self.player_a
    
    def play(self):
        while not self.is_over():
            if self.server.wins_serve():
                self.server.inc_score()
            else:
                self.change_server()
         
    def is_over(self):
        return ((self.player_a.get_score() == 15 or self.player_b.get_score() == 15) or 
                (self.player_a.get_score() == 7 and self.player_b.get_score() == 0))
        
    def change_server(self):
        if self.server == self.player_a:
            self.server = self.player_b
        else:
            self.server = self.player_a
    
    def get_scores(self):
        # returns the current scores of players A and B
        return self.player_a.get_score(), self.player_b.get_score()
    
    def __repr__(self):
        return "RBallGame({0}, {1})".format(self.player_a.prob, self.player_b.prob)

Call main()!

In [11]:
main()
This plays racquetball, good luck I don't know the rules.
What is the prob player A wins a serve? 0.65
What is the prob player B wins a serve? 0.67
How many games to simulate? 50
Summary of 50 games:

          wins (% total)  shutouts (% wins) 
-------------------------------------------
Player A:   29   (58.0%)          10    (34.5%)
Player B:   21   (42.0%)           0    (0.0%)
RBallGame(0.65, 0.67) Scores are:  (7, 0)
RBallGame(0.65, 0.67) Scores are:  (7, 15)
RBallGame(0.65, 0.67) Scores are:  (15, 14)
RBallGame(0.65, 0.67) Scores are:  (11, 15)
RBallGame(0.65, 0.67) Scores are:  (8, 15)
RBallGame(0.65, 0.67) Scores are:  (5, 15)
RBallGame(0.65, 0.67) Scores are:  (7, 0)
RBallGame(0.65, 0.67) Scores are:  (15, 12)
RBallGame(0.65, 0.67) Scores are:  (1, 15)
RBallGame(0.65, 0.67) Scores are:  (8, 15)
RBallGame(0.65, 0.67) Scores are:  (15, 8)
RBallGame(0.65, 0.67) Scores are:  (8, 15)
RBallGame(0.65, 0.67) Scores are:  (9, 15)
RBallGame(0.65, 0.67) Scores are:  (7, 0)
RBallGame(0.65, 0.67) Scores are:  (15, 11)
RBallGame(0.65, 0.67) Scores are:  (15, 13)
RBallGame(0.65, 0.67) Scores are:  (15, 12)
RBallGame(0.65, 0.67) Scores are:  (7, 15)
RBallGame(0.65, 0.67) Scores are:  (10, 15)
RBallGame(0.65, 0.67) Scores are:  (15, 10)
RBallGame(0.65, 0.67) Scores are:  (5, 15)
RBallGame(0.65, 0.67) Scores are:  (15, 4)
RBallGame(0.65, 0.67) Scores are:  (7, 0)
RBallGame(0.65, 0.67) Scores are:  (4, 15)
RBallGame(0.65, 0.67) Scores are:  (11, 15)
RBallGame(0.65, 0.67) Scores are:  (15, 13)
RBallGame(0.65, 0.67) Scores are:  (7, 0)
RBallGame(0.65, 0.67) Scores are:  (15, 4)
RBallGame(0.65, 0.67) Scores are:  (15, 14)
RBallGame(0.65, 0.67) Scores are:  (12, 15)
RBallGame(0.65, 0.67) Scores are:  (7, 15)
RBallGame(0.65, 0.67) Scores are:  (13, 15)
RBallGame(0.65, 0.67) Scores are:  (7, 0)
RBallGame(0.65, 0.67) Scores are:  (15, 5)
RBallGame(0.65, 0.67) Scores are:  (15, 8)
RBallGame(0.65, 0.67) Scores are:  (7, 0)
RBallGame(0.65, 0.67) Scores are:  (13, 15)
RBallGame(0.65, 0.67) Scores are:  (6, 15)
RBallGame(0.65, 0.67) Scores are:  (7, 0)
RBallGame(0.65, 0.67) Scores are:  (8, 15)
RBallGame(0.65, 0.67) Scores are:  (15, 13)
RBallGame(0.65, 0.67) Scores are:  (15, 10)
RBallGame(0.65, 0.67) Scores are:  (5, 15)
RBallGame(0.65, 0.67) Scores are:  (15, 7)
RBallGame(0.65, 0.67) Scores are:  (7, 0)
RBallGame(0.65, 0.67) Scores are:  (7, 0)
RBallGame(0.65, 0.67) Scores are:  (15, 11)
RBallGame(0.65, 0.67) Scores are:  (12, 15)
RBallGame(0.65, 0.67) Scores are:  (15, 5)
RBallGame(0.65, 0.67) Scores are:  (15, 12)
In [12]:
(a = 10)
  File "<ipython-input-12-9ef713e35d1f>", line 1
    (a = 10)
       ^
SyntaxError: invalid syntax
In [ ]: