0

I wrote a program that simulates a tennisgame. I made the points count from 0-4, where getting 4 points wins you the game, I did this just as a temporary solution. Now that I am pretty much finished I can't figure out how to actually change the points to count 0, 15, 30, 40.

Here is my class:

class Players: #define class players
    ratio = 0
    def __init__(self, name, winningProb, wonGames, playedGames):
        self.name = name
        self.winningProb = winningProb
        self.wonGames = wonGames
        self.playedGames = playedGames
        if playedGames == 0:
            self.ratio = 0
        else:
            self.ratio = self.wonGames/self.playedGames
        self.score = 0
    def showPlayerInfo(self):
        print(self.name, self.wonGames, self.playedGames, self.winningProb)
    def playerInfo(self, position): 
        return [str(position), self.name, str(self.wonGames), str(self.playedGames), str(self.winningProb)]
    def getWinningProb(self):
        return self.winningProb
    def getScore(self):
        return self.score
    def setScore(self, score):
        self.score = score
    def getName(self):
        return self.name
    def getWonGames(self):
        return self.wonGames
    def getPlayedGames(self):
        return self.playedGames

Function that defines a game:

def playGame(players, displayBoardPerBall, displayBoardPerGame, flag, pauseAfterBalls):
    ballCounter = 0
    while True:
        if flag == 1:
            flag = 2
            if isWonTheBall(players[0]):
                players[0].setScore(players[0].getScore() + 1)
            else:
                players[1].setScore(players[1].getScore() + 1)
        elif flag == 2:
            flag == 1
            if isWonTheBall(players[1]):
                players[1].setScore(players[1].getScore() + 1)
            else:
                players[0].setScore(players[0].getScore() + 1)
        ballCounter += 1
        if displayBoardPerBall:
            print("\nBall scores until now")
            print(players[0].name, players[0].getScore())
            print(players[1].name, players[1].getScore())
            print()
        if pauseAfterBalls ==  ballCounter:
            ballCounter = 0
            nothing = input("Game Paused. Enter Any Letter To Continue.")
        #whoWon stores 0 if nobody won
        whoWon = checkGameWinner(players)
        if whoWon!=0:
            print("\n\nPlayer",whoWon+1,"won this game.")
            players[0].setScore(0)
            players[1].setScore(0)
            return whoWon
        if players[0].getScore() == 3 and players[1].getScore() == 3:
            print("\nDEUCE!!\n")

Not sure if this function is helpful, but it just checks who won the game:

def checkGameWinner(players):
    if players[0].getScore() == 4 and players[1].getScore() <= 2:
        return 1
    if players[1].getScore() == 4 and players[0].getScore() <= 2:
        return 2
    if players[1].getScore() > 2 and players[0].getScore() > 2:
        if players[1].getScore() >= players[0].getScore()+2:
            return 2
        elif players[0].getScore() >= players[1].getScore()+2:
            return 1
    return 0

Any help is appreciated! I tried by figuring out an equation so that it would count 0,15,30,40 but could not figure out an equation that would work.

If you more of the code, perhaps the main-function, just comment and I will post it.

  • There is really no point/need to define all those getters/setters. Read about [`property`](https://stackoverflow.com/questions/17330160/how-does-the-property-decorator-work-in-python). Also interesting: [What's the pythonic way to use getters and setters?](https://stackoverflow.com/questions/2627002/whats-the-pythonic-way-to-use-getters-and-setters) – Tomerikoo Nov 30 '20 at 16:53

3 Answers3

1

Use a list to look up the score to display, internally you can just increment a counter each time a point is won.

display_score = [0, 15, 30, 40]
...
def get_score():
    return display_score[self.score]
    

A better implementation would also check for invalid scores to prevent reading past the end of the array, but if implemented in your class you should be doing that in the set/increment score method.

The advantage to using classes is you encapsulate logic, hiding it from the code which uses your class. To keep score you can move the logic of this code in to the class:

players[0].setScore(players[0].getScore() + 1)

Replace your setScore method with incrementScore as the object already knows its current score.

def increment_score():
    if (self.score < 3):  # player has not reached 40 points
        self.score += 1

You can then change you score code from

if isWonTheBall(players[0]):
    players[0].setScore(players[0].getScore() + 1)
else:
    players[1].setScore(players[1].getScore() + 1)

to this

if isWonTheBall(players[0]):
    players[0].incrementScore()
else:
    players[1].incrementScore()

This code does not handle the case of 'deuce' and 'advantage' but as you can mix strings and integers in a python array you can add them to the display_score list and some extra logic when the player's score is incremented. I leave that for you to have a go at.

By removing the setScore method you prevent someone changing the players score to some silly value (such as -10 or 236) which simplifies the checking for invalid scores. Once you have removed the setting of a score you'll also need methods such as reset_score to set the score to zero ready for the next game.

At the moment your class is a collection of methods giving direct access to the member variables, moving to using methods to perform some action on your object helps with abstraction. You might find this article interesting about why getter and setter methods are evil, it's written about Java but the principle applies to all object oriented languages.

Tony
  • 9,672
  • 3
  • 47
  • 75
  • I implemented it into my class and it works, how would I go about to check for invalid scores in the set/increment score method? – gurka583new Nov 30 '20 at 19:00
  • @gurka583new - I've added some more information about checking the score and how to implement action-oriented methods on your class. – Tony Nov 30 '20 at 22:46
  • Instead of linking a Java article you can use the Python SO question I linked above... – Tomerikoo Nov 30 '20 at 22:56
  • @Tomerikoo - fair point, I missed your comment. the article I linked to is one I read years ago and has become my "go to" article about getters and setters. I should update my list of bookmarks ;) However, it's a shame the highest voted answer simply replaces getters and setters with properties when the OO way is to move away from them. I think I'll leave the link to the Java article. – Tony Nov 30 '20 at 23:08
  • I admit that I didn't read the article (I will try to) and I coded in Java ages ago (I thought there it is idiomatic to use getters/setters?). But it might be more relevant to link something Python-specific as it is really non-idiomatic and almost an anti-pattern to use those in Python... – Tomerikoo Nov 30 '20 at 23:12
  • *the highest voted answer simply replaces getters and setters with properties when the OO way is to move away from them* - I don't agree. The idea is to avoid stuff like `def get_x` def `set_x`. `property` just gives you a nice control over setting values and some functionality for returning them. And anyway the second answer is a bit more descriptive :) – Tomerikoo Nov 30 '20 at 23:15
0

Define a function to convert a score to points

for example

def getPoints(score):
    # TODO: Handle score == 4

    if score == 3:
        return 40
    return 15 * score
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
0

If you don't want to change any of your internal code, you could write a simple function to convert from your score to display values

def getDisplayScore(self):
    score_map = [0, 15, 30, 40]
    return score_map[self.score]
big_bad_bison
  • 1,021
  • 1
  • 7
  • 12