2
\$\begingroup\$

I was asked to program the following:

Develop a two-player dice game that will have the players roll two 6-sided dice each and get points depending on what they roll. There are 5 rounds in a game. In each round, each player rolls the two dice. The rules are:

  • The points rolled on each player’s dice are added to their score.
  • If the total is an even number, an additional 10 points are added to their score.
  • If the total is an odd number, 5 points are subtracted from their score.
  • If they roll a double, they get to roll one extra die and get the number of points rolled added to their score.
  • The score of a player cannot go below 0 at any point.
  • The person with the highest score at the end of the 5 rounds wins.
  • If both players have the same score at the end of the 5 rounds, they each roll 1 die and whoever gets the highest score wins (this repeats until someone wins).

Here is what I came up with but I think it is inefficient and too long:

import time
import random
import sys

print("\nRound 1 is about to commence!")
time.sleep(3)

print("\nPlayer 1's dice is rolling....")
time.sleep(3)

P1Rnd1Dice = random.randint(1,6)
P1Rnd1Dice2 = random.randint(1,6)

print("\nPlayer 1 has rolled a", P1Rnd1Dice, "and a", P1Rnd1Dice2)
time.sleep(3)

print("\nPlayer 2's dice is rolling....")
time.sleep(3)

P2Rnd1Dice = random.randint(1,6)
P2Rnd1Dice2 = random.randint(1,6)

print("\nPlayer 2 has rolled a", P2Rnd1Dice, "and a", P2Rnd1Dice2)
time.sleep(3)

P1OvrScore = 0

P1Rnd1Roll = P1Rnd1Dice + P1Rnd1Dice2
P1OvrScore = P1OvrScore + P1Rnd1Roll

print("\nPlayer 1's round 1 throw sums up to", P1Rnd1Roll,"which is added to their total score to give them", P1OvrScore, "overall")
time.sleep(4)

if P1Rnd1Roll % 2 == 0:
    P1OvrScore = P1OvrScore + 10
    print("\nIn addition, Player 1's total is an even number, so they get an additional 10 points added to their score, which is now", P1OvrScore)
    time.sleep(4)
else:
    P1OvrScore = P1OvrScore - 5
    print("\nIn addition, Player 1's total is an odd number, so they get 5 points taken away from their score, which is now", P1OvrScore)
    time.sleep(4)

if P1Rnd1Dice == P1Rnd1Dice2:
    P1Rnd1BnsDice = random.randint(1,6)
    P1OvrScore = P1OvrScore + P1Rnd1BnsDice
    print("\nFurthermore, Player 1 has rolled a double and therefore recieves an extra roll")
    time.sleep(4)
    print("\nPlayer 1's bonus dice is rolling...")
    time.sleep(3)
    print("\nPlayer 1's bonus roll has resulted in a", P1Rnd1BnsDice, ", which is added to their total to give them", P1OvrScore)
    time.sleep(4)

P2OvrScore = 0

P2Rnd1Roll = P2Rnd1Dice + P2Rnd1Dice2
P2OvrScore = P2OvrScore + P2Rnd1Roll

print("\nPlayer 2's round 1 throw sums up to", P2Rnd1Roll,"which is added to their total score to give them", P2OvrScore, "overall")
time.sleep(4)

if P2Rnd1Roll % 2 == 0:
    P2OvrScore = P2OvrScore + 10
    print("\nIn addition, Player 2's total is an even number, so they get an additional 10 points added to their score, which is now", P2OvrScore)
    time.sleep(4)
else:
    P2OvrScore = P2OvrScore - 5
    print("\nIn addition, Player 2's total is an odd number, so they get 5 points taken away from their score, which is now", P2OvrScore)
    time.sleep(4)

if P2Rnd1Dice == P2Rnd1Dice2:
    P2Rnd1BnsDice = random.randint(1,6)
    P2OvrScore = P2OvrScore + P2Rnd1BnsDice
    print("\nFurthermore, Player 2 has rolled a double and therefore recieves an extra roll")
    time.sleep(4)
    print("\nPlayer 2's bonus dice is rolling...")
    time.sleep(3)
    print("\nPlayer 2's bonus roll has resulted in a", P2Rnd1BnsDice, ", which is added to their total to give them", P2OvrScore)
    time.sleep(4)

if P1OvrScore < 0 and P2OvrScore > 0:
    print("\nAfter the conclusion of round 1, Player 1's total is below 0 and Player 2's total is greater than 0, meaning Player 2 automatically wins!")
    sys.exit()
elif P1OvrScore > 0 and P2OvrScore < 0:
    print("\nAfter the conclusion of round 1, Player 2's total is below 0 and Player 1's total is greater than 0, meaning Player 1 automatically wins!")
    sys.exit()
elif P1OvrScore < 0 and P2OvrScore < 0:
    print("\nAfter the conclusion of round 1, both Player 1's total and Player 2's total is below 0, meaning both players lose")
    sys.exit()
else:
    print("\nAfter the conclusion of round 1, both players' totals are above 0, meaning they can continue onto round 2")
    time.sleep(4)

#_______________________________________________________________ End of round 1 ______________________________________________ Next: Round 2  __________________________________________________#

print("\nRound 2 is about to commence!")
time.sleep(3)

print("\nPlayer 1's dice is rolling....")
time.sleep(3)

P1Rnd2Dice = random.randint(1,6)
P1Rnd2Dice2 = random.randint(1,6)

print("\nPlayer 1 has rolled a", P1Rnd2Dice, "and a", P1Rnd2Dice2)
time.sleep(3)

print("\nPlayer 2's dice is rolling....")
time.sleep(3)

P2Rnd2Dice = random.randint(1,6)
P2Rnd2Dice2 = random.randint(1,6)

print("\nPlayer 2 has rolled a", P2Rnd2Dice, "and a", P2Rnd2Dice2)
time.sleep(3)

P1Rnd2Roll = P1Rnd2Dice + P1Rnd2Dice2
P1OvrScore = P1OvrScore + P1Rnd2Roll

print("\nPlayer 1's round 2 throw sums up to", P1Rnd2Roll,"which is added to their total score to give them", P1OvrScore, "overall")
time.sleep(4)

if P1Rnd2Roll % 2 == 0:
    P1OvrScore = P1OvrScore + 10
    print("\nIn addition, Player 1's total is an even number, so they get an additional 10 points added to their score, which is now", P1OvrScore)
    time.sleep(4)
else:
    P1OvrScore = P1OvrScore - 5
    print("\nIn addition, Player 1's total is an odd number, so they get 5 points taken away from their score, which is now", P1OvrScore)
    time.sleep(4)

if P1Rnd2Dice == P1Rnd2Dice2:
    P1Rnd2BnsDice = random.randint(1,6)
    P1OvrScore = P1OvrScore + P1Rnd2BnsDice
    print("\nFurthermore, Player 1 has rolled a double and therefore recieves an extra roll")
    time.sleep(4)
    print("\nPlayer 1's bonus dice is rolling...")
    time.sleep(3)
    print("\nPlayer 1's bonus roll has resulted in a", P1Rnd2BnsDice, ", which is added to their total to give them", P1OvrScore)
    time.sleep(4)

P2Rnd2Roll = P2Rnd2Dice + P2Rnd2Dice2
P2OvrScore = P2OvrScore + P2Rnd2Roll

print("\nPlayer 2's round 2 throw sums up to", P2Rnd2Roll,"which is added to their total score to give them", P2OvrScore, "overall")
time.sleep(4)

if P2Rnd2Roll % 2 == 0:
    P2OvrScore = P2OvrScore + 10
    print("\nIn addition, Player 2's total is an even number, so they get an additional 10 points added to their score, which is now", P2OvrScore)
    time.sleep(4)
else:
    P2OvrScore = P2OvrScore - 5
    print("\nIn addition, Player 2's total is an odd number, so they get 5 points taken away from their score, which is now", P2OvrScore)
    time.sleep(4)

if P2Rnd2Dice == P2Rnd2Dice2:
    P2Rnd2BnsDice = random.randint(1,6)
    P2OvrScore = P2OvrScore + P2Rnd2BnsDice
    print("\nFurthermore, Player 2 has rolled a double and therefore recieves an extra roll")
    time.sleep(4)
    print("\nPlayer 2's bonus dice is rolling...")
    time.sleep(3)
    print("\nPlayer 2's bonus roll has resulted in a", P2Rnd2BnsDice, ", which is added to their total to give them", P2OvrScore)
    time.sleep(4)

if P1OvrScore < 0 and P2OvrScore > 0:
    print("\nAfter the conclusion of round 2, Player 1's total is below 0 and Player 2's total is greater than 0, meaning Player 2 automatically wins!")
    sys.exit()
elif P1OvrScore > 0 and P2OvrScore < 0:
    print("\nAfter the conclusion of round 2, Player 2's total is below 0 and Player 1's total is greater than 0, meaning Player 1 automatically wins!")
    sys.exit()
elif P1OvrScore < 0 and P2OvrScore < 0:
    print("\nAfter the conclusion of round 2, both Player 1's total and Player 2's total is below 0, meaning both players lose")
    sys.exit()
else:
    print("\nAfter the conclusion of round 2, both players' totals are above 0, meaning they can continue onto round 2")
    time.sleep(4)

#_______________________________________________________________ End of round 2 ______________________________________________ Next: Round 3  __________________________________________________#

print("\nRound 3 is about to commence!")
time.sleep(3)

print("\nPlayer 1's dice is rolling....")
time.sleep(3)

P1Rnd3Dice = random.randint(1,6)
P1Rnd3Dice2 = random.randint(1,6)

print("\nPlayer 1 has rolled a", P1Rnd3Dice, "and a", P1Rnd3Dice2)
time.sleep(3)

print("\nPlayer 2's dice is rolling....")
time.sleep(3)

P2Rnd3Dice = random.randint(1,6)
P2Rnd3Dice2 = random.randint(1,6)

print("\nPlayer 2 has rolled a", P2Rnd3Dice, "and a", P2Rnd3Dice2)
time.sleep(3)

P1Rnd3Roll = P1Rnd3Dice + P1Rnd3Dice2
P1OvrScore = P1OvrScore + P1Rnd3Roll

print("\nPlayer 1's round 3 throw sums up to", P1Rnd3Roll,"which is added to their total score to give them", P1OvrScore, "overall")
time.sleep(4)

if P1Rnd3Roll % 2 == 0:
    P1OvrScore = P1OvrScore + 10
    print("\nIn addition, Player 1's total is an even number, so they get an additional 10 points added to their score, which is now", P1OvrScore)
    time.sleep(4)
else:
    P1OvrScore = P1OvrScore - 5
    print("\nIn addition, Player 1's total is an odd number, so they get 5 points taken away from their score, which is now", P1OvrScore)
    time.sleep(4)

if P1Rnd3Dice == P1Rnd3Dice2:
    P1Rnd3BnsDice = random.randint(1,6)
    P1OvrScore = P1OvrScore + P1Rnd3BnsDice
    print("\nFurthermore, Player 1 has rolled a double and therefore recieves an extra roll")
    time.sleep(4)
    print("\nPlayer 1's bonus dice is rolling...")
    time.sleep(3)
    print("\nPlayer 1's bonus roll has resulted in a", P1Rnd3BnsDice, ", which is added to their total to give them", P1OvrScore)
    time.sleep(4)

P2Rnd3Roll = P2Rnd3Dice + P2Rnd3Dice2
P2OvrScore = P2OvrScore + P2Rnd3Roll

print("\nPlayer 2's round 3 throw sums up to", P2Rnd3Roll,"which is added to their total score to give them", P2OvrScore, "overall")
time.sleep(4)

if P2Rnd3Roll % 2 == 0:
    P2OvrScore = P2OvrScore + 10
    print("\nIn addition, Player 2's total is an even number, so they get an additional 10 points added to their score, which is now", P2OvrScore)
    time.sleep(4)
else:
    P2OvrScore = P2OvrScore - 5
    print("\nIn addition, Player 2's total is an odd number, so they get 5 points taken away from their score, which is now", P2OvrScore)
    time.sleep(4)

if P2Rnd3Dice == P2Rnd3Dice2:
    P2Rnd3BnsDice = random.randint(1,6)
    P2OvrScore = P2OvrScore + P2Rnd3BnsDice
    print("\nFurthermore, Player 2 has rolled a double and therefore recieves an extra roll")
    time.sleep(4)
    print("\nPlayer 2's bonus dice is rolling...")
    time.sleep(3)
    print("\nPlayer 2's bonus roll has resulted in a", P2Rnd3BnsDice, ", which is added to their total to give them", P2OvrScore)
    time.sleep(4)

if P1OvrScore < 0 and P2OvrScore > 0:
    print("\nAfter the conclusion of round 3, Player 1's total is below 0 and Player 2's total is greater than 0, meaning Player 2 automatically wins!")
    sys.exit()
elif P1OvrScore > 0 and P2OvrScore < 0:
    print("\nAfter the conclusion of round 3, Player 2's total is below 0 and Player 1's total is greater than 0, meaning Player 1 automatically wins!")
    sys.exit()
elif P1OvrScore < 0 and P2OvrScore < 0:
    print("\nAfter the conclusion of round 3, both Player 1's total and Player 2's total is below 0, meaning both players lose")
    sys.exit()
else:
    print("\nAfter the conclusion of round 3, both players' totals are above 0, meaning they can continue onto round 2")
    time.sleep(4)

#_______________________________________________________________ End of round 3 ______________________________________________ Next: Round 4  __________________________________________________#

print("\nRound 4 is about to commence!")
time.sleep(3)

print("\nPlayer 1's dice is rolling....")
time.sleep(3)

P1Rnd4Dice = random.randint(1,6)
P1Rnd4Dice2 = random.randint(1,6)

print("\nPlayer 1 has rolled a", P1Rnd4Dice, "and a", P1Rnd4Dice2)
time.sleep(3)

print("\nPlayer 2's dice is rolling....")
time.sleep(3)

P2Rnd4Dice = random.randint(1,6)
P2Rnd4Dice2 = random.randint(1,6)

print("\nPlayer 2 has rolled a", P2Rnd4Dice, "and a", P2Rnd4Dice2)
time.sleep(3)

P1Rnd4Roll = P1Rnd4Dice + P1Rnd4Dice2
P1OvrScore = P1OvrScore + P1Rnd4Roll

print("\nPlayer 1's round 4 throw sums up to", P1Rnd4Roll,"which is added to their total score to give them", P1OvrScore, "overall")
time.sleep(4)

if P1Rnd4Roll % 2 == 0:
    P1OvrScore = P1OvrScore + 10
    print("\nIn addition, Player 1's total is an even number, so they get an additional 10 points added to their score, which is now", P1OvrScore)
    time.sleep(4)
else:
    P1OvrScore = P1OvrScore - 5
    print("\nIn addition, Player 1's total is an odd number, so they get 5 points taken away from their score, which is now", P1OvrScore)
    time.sleep(4)

if P1Rnd4Dice == P1Rnd4Dice2:
    P1Rnd4BnsDice = random.randint(1,6)
    P1OvrScore = P1OvrScore + P1Rnd4BnsDice
    print("\nFurthermore, Player 1 has rolled a double and therefore recieves an extra roll")
    time.sleep(4)
    print("\nPlayer 1's bonus dice is rolling...")
    time.sleep(3)
    print("\nPlayer 1's bonus roll has resulted in a", P1Rnd4BnsDice, ", which is added to their total to give them", P1OvrScore)
    time.sleep(4)

P2Rnd4Roll = P2Rnd4Dice + P2Rnd4Dice2
P2OvrScore = P2OvrScore + P2Rnd4Roll

print("\nPlayer 2's round 2 throw sums up to", P2Rnd4Roll,"which is added to their total score to give them", P2OvrScore, "overall")
time.sleep(4)

if P2Rnd4Roll % 2 == 0:
    P2OvrScore = P2OvrScore + 10
    print("\nIn addition, Player 2's total is an even number, so they get an additional 10 points added to their score, which is now", P2OvrScore)
    time.sleep(4)
else:
    P2OvrScore = P2OvrScore - 5
    print("\nIn addition, Player 2's total is an odd number, so they get 5 points taken away from their score, which is now", P2OvrScore)
    time.sleep(4)

if P2Rnd4Dice == P2Rnd4Dice2:
    P2Rnd4BnsDice = random.randint(1,6)
    P2OvrScore = P2OvrScore + P2Rnd4BnsDice
    print("\nFurthermore, Player 2 has rolled a double and therefore recieves an extra roll")
    time.sleep(4)
    print("\nPlayer 2's bonus dice is rolling...")
    time.sleep(3)
    print("\nPlayer 2's bonus roll has resulted in a", P2Rnd4BnsDice, ", which is added to their total to give them", P2OvrScore)
    time.sleep(4)

if P1OvrScore < 0 and P2OvrScore > 0:
    print("\nAfter the conclusion of round 4, Player 1's total is below 0 and Player 2's total is greater than 0, meaning Player 2 automatically wins!")
    sys.exit()
elif P1OvrScore > 0 and P2OvrScore < 0:
    print("\nAfter the conclusion of round 4, Player 2's total is below 0 and Player 1's total is greater than 0, meaning Player 1 automatically wins!")
    sys.exit()
elif P1OvrScore < 0 and P2OvrScore < 0:
    print("\nAfter the conclusion of round 4, both Player 1's total and Player 2's total is below 0, meaning both players lose")
    sys.exit()
else:
    print("\nAfter the conclusion of round 4, both players' totals are above 0, meaning they can continue onto round 2")
    time.sleep(4)

#_______________________________________________________________ End of round 4 ______________________________________________ Next: Round 5  __________________________________________________#

print("\nRound 5 is about to commence!")
time.sleep(3)

print("\nPlayer 1's dice is rolling....")
time.sleep(3)

P1Rnd5Dice = random.randint(1,6)
P1Rnd5Dice2 = random.randint(1,6)

print("\nPlayer 1 has rolled a", P1Rnd5Dice, "and a", P1Rnd5Dice2)
time.sleep(3)

print("\nPlayer 2's dice is rolling....")
time.sleep(3)

P2Rnd5Dice = random.randint(1,6)
P2Rnd5Dice2 = random.randint(1,6)

print("\nPlayer 2 has rolled a", P2Rnd5Dice, "and a", P2Rnd5Dice2)
time.sleep(3)

P1Rnd5Roll = P1Rnd5Dice + P1Rnd5Dice2
P1OvrScore = P1OvrScore + P1Rnd5Roll

print("\nPlayer 1's round 5 throw sums up to", P1Rnd5Roll,"which is added to their total score to give them", P1OvrScore, "overall")
time.sleep(4)

if P1Rnd5Roll % 2 == 0:
    P1OvrScore = P1OvrScore + 10
    print("\nIn addition, Player 1's total is an even number, so they get an additional 10 points added to their score, which is now", P1OvrScore)
    time.sleep(4)
else:
    P1OvrScore = P1OvrScore - 5
    print("\nIn addition, Player 1's total is an odd number, so they get 5 points taken away from their score, which is now", P1OvrScore)
    time.sleep(4)

if P1Rnd5Dice == P1Rnd5Dice2:
    P1Rnd5BnsDice = random.randint(1,6)
    P1OvrScore = P1OvrScore + P1Rnd5BnsDice
    print("\nFurthermore, Player 1 has rolled a double and therefore recieves an extra roll")
    time.sleep(4)
    print("\nPlayer 1's bonus dice is rolling...")
    time.sleep(3)
    print("\nPlayer 1's bonus roll has resulted in a", P1Rnd5BnsDice, ", which is added to their total to give them", P1OvrScore)
    time.sleep(4)

P2Rnd5Roll = P2Rnd5Dice + P2Rnd5Dice2
P2OvrScore = P2OvrScore + P2Rnd5Roll

print("\nPlayer 2's round 5 throw sums up to", P2Rnd5Roll,"which is added to their total score to give them", P2OvrScore, "overall")
time.sleep(4)

if P2Rnd5Roll % 2 == 0:
    P2OvrScore = P2OvrScore + 10
    print("\nIn addition, Player 2's total is an even number, so they get an additional 10 points added to their score, which is now", P2OvrScore)
    time.sleep(4)
else:
    P2OvrScore = P2OvrScore - 5
    print("\nIn addition, Player 2's total is an odd number, so they get 5 points taken away from their score, which is now", P2OvrScore)
    time.sleep(4)

if P2Rnd5Dice == P2Rnd5Dice2:
    P2Rnd5BnsDice = random.randint(1,6)
    P2OvrScore = P2OvrScore + P2Rnd5BnsDice
    print("\nFurthermore, Player 2 has rolled a double and therefore recieves an extra roll")
    time.sleep(4)
    print("\nPlayer 2's bonus dice is rolling...")
    time.sleep(3)
    print("\nPlayer 2's bonus roll has resulted in a", P2Rnd5BnsDice, ", which is added to their total to give them", P2OvrScore)
    time.sleep(4)

if P1OvrScore < 0 and P2OvrScore > 0:
    print("\nAfter the conclusion of round 5, Player 1's total is below 0 and Player 2's total is greater than 0, meaning Player 2 automatically wins!")
    sys.exit()
elif P1OvrScore > 0 and P2OvrScore < 0:
    print("\nAfter the conclusion of round 5, Player 2's total is below 0 and Player 1's total is greater than 0, meaning Player 1 automatically wins!")
    sys.exit()
elif P1OvrScore < 0 and P2OvrScore < 0:
    print("\nAfter the conclusion of round 5, both Player 1's total and Player 2's total is below 0, meaning both players lose.")
    sys.exit()
#_______________________________________________________________ End of round 5 ______________________________________________ Next: Conclusion + Declaration of winner  __________________________________________________#

if P1OvrScore > P2OvrScore:
    print("\nFollowing the end of round 5, the game is now over. Player 1 has finished with a total of", P1OvrScore,"and Player 2 has finished with a total of", P2OvrScore)
    print("\nThis means that Player 1 has won the game after finishing with a higher total than Player 2")
elif P1OvrScore < P2OvrScore:
    print("\nFollowing the end of round 5, the game is now over. Player 1 has finished with a total of", P1OvrScore,"and Player 2 has finished with a total of", P2OvrScore)
    print("\nThis means that Player 2 has won the game after finishing with a higher total than Player 1")
elif P1OvrScore == P2OvrScore:
    print("\nFollowing the end of round 5, the game is now over. Player 1 has finished with a total of", P1OvrScore,"and Player 2 has finished with a total of", P2OvrScore)
    print("\nThis means that neither Player 1 or Player 2 has won the game after they both finish with the same total")

Could anyone help me make this shorter and more efficient?

\$\endgroup\$
2
  • \$\begingroup\$ Sorry, not gonna read all that. Review = Use a loop. \$\endgroup\$
    – Manuel
    Commented Apr 15, 2021 at 10:26
  • 1
    \$\begingroup\$ Welcome to the Code Review Community, I hope you get some good answers. \$\endgroup\$
    – pacmaninbw
    Commented Apr 15, 2021 at 16:14

1 Answer 1

6
\$\begingroup\$

There's a lot to work through here. I focused on taking the next step when improving the code, not fully rewriting it the way I personally would. I would recommend you work through the points and the resulting code, try to understand and apply these principles. Afterwards you're welcome to come back here and ask for another round of feedback. As there are a lot of points in this, I'll provide some further reading or video tutorials where appropriate to keep the length of this answer manageable. This is also not a complete list of possible improvements, but of the ones I found most obvious and impactful.


Loops

While writing out your code you should've noticed that each of the 5 rounds basically follows the same logic. Everytime you write out the same logic multiple times, you should immediately be dissatisfied with the unnecessary labour you're putting yourself through. You should consider placing the logic into a loop (or a function, but we'll come to that later). This will be the better (and more scalable) option, more or less always. There's a reason some IDEs will complain about a Duplicated code fragment. It doesn't only mean more work for you, it also makes code less readable and understandable (see the comments on your question for example).

Loops are an essential part of imperative programming languages. Here are some interactive exercises in Python.

So instead of writing out the same logic time and time again, we will only write it out once and put it inside a for loop like this:

rounds_to_play = 5

for round_num in range(1, rounds_to_play + 1):
    # every round happens in here

There are also other ways to approach this:

rounds_to_play = 5
round = 0

while (round := round + 1) <= rounds_to_play:
    # main gameplay here
    ...

or

rounds_to_play = 5
round = 1

while True:
    # main gameplay here
    ...
    
    round += 1
    if round > rounds_to_play:
        break

But a for loop is the most fitting and straight-forward solution here.

By adjusting rounds_to_play we can now also easily adjust the number of rounds we loop through play the game.

The same applies to the players playing each round. They go through the exact same steps, the only thing that changes is the player number, so we put our round logic into this loop:

for player_num in (1, 2):
    # every player turn happens in here

This also means we have to adjust our gameplay logic to behave differently depending on which iteration of each loop we're currently in. You'll see how we can approach that in the complete code at the bottom.


Magic numbers and constants

There are some constants throughout your code that you might want to play around with or adjust in the future. This will be a lot of unnecessary manual work in your current implementation. Two examples:

Line endings

You start all of the strings in print(...) statements with "\n". Instead of manually adding this to your strings you could create a constant

LINE_END = "\n\n"

and pass it as an argument to print:

print("Player 1's dice is rolling....", end=LINE_END)

More on print() and its arguments

Sleep time

You make a lot of calls to time.sleep. I couldn't quite figure out the logic behind waiting either 3 or 4 seconds so I created two constants:

SHORT_SLEEP_TIME = 3
LONG_SLEEP_TIME = 4

time.sleep(SHORT_SLEEP_TIME)

You might for example want to change this for testing purposes (since you probably wouldn't want the execution to take as long for you as it does for the user).


Python 3's f-Strings

f-Strings make using variables or calculations in strings really convenient and readable:

print("Round 1 is about to commence!", end=LINE_END)

becomes

print(f"Round {round_num} is about to commence!", end=LINE_END)

We're using round_num from our previously mentioned for loop here.


Imports

Since you only need one function from each library you can simply import only those functions.

from time import sleep
from random import randint

sleep(SHORT_SLEEP_TIME)
random_num = randint(1, 6)

This is not always a good idea, since it might lead to namespace collisions (especially when doing from library import *), but in this case sleep and randint are really descriptive and will most likely not collide with anything you implement yourself in this project.


Functions

You should use functions to abstract some of your logic and make it reusable. Functions also help split a long procedure into smaller chunks, that are easier to read and understand. Here is one example:

def dice_roll():
    return randint(1, 6)


def player_dice_roll(player_num):
    print(f"Player {player_num}'s dice is rolling....", end=LINE_END)
    sleep(SHORT_SLEEP_TIME)

    dice1, dice2 = dice_roll(), dice_roll()

    print(f"Player {player_num} has rolled a {dice1} and a {dice2}", end=LINE_END)
    sleep(SHORT_SLEEP_TIME)

    return dice1, dice2

This takes the whole logic of a player_dice_roll and puts it into a seperate chunk. Since we will also need to roll a die for the bonus die, I put it into the seperate function dice_roll().

You could also implement dice_roll to provide multiple dice, by passing the number of dice as an argument:

def dice_roll(num_dice=1):
    return [randint(1, 6) for _ in range(num_dice)]

This will provide a list of dice rolls. If you haven't encountered list comprehensions yet, they're a very useful concept: Python List Comprehension

Please note that there isn't one correct answer when it comes to splitting a procedure into functions. It depends on use case and personal coding style. Take my suggestion as a starting point and find what works best for you (and your teammates in the long run). This concept can (and should!) also be applied in a number of other places in your code. As I said in the beginning: Try to understand the concept and its benefits and then start applying it yourself.


main() and sys.exit()

It's a good idea to wrap your procedure into a main() function, which provides a standard entry point. It also makes the functionality of your code clearer at a glance. Since a function will not run on its own when we execute the script, we need to call it. For most use cases, we should wrap it in a if __name__ == “__main__”: condition.

def main():
    # this is where your procedure now runs

if __name__ == “__main__”:
    main()

What does if name == “main”: do?

Since we're not running the main procedure in a function we do not need to use sys.exit(), which halts all code execution. This might be fine here, but you might not want this when calling this script from somewhere else. We can now simply replace sys.exit() by return, which ends function execution without returning anything.


Simplified conditions

This is a small point. After checking

if player1_score > player2_score:
    # Player 1 wins
elif player1_score < player2_score:
    # Player 2 wins

we do not need to check if the scores are equal. So we can rewrite the last part of the condition:

elif player1_score == player2_score:
    # Tie

# becomes

else:
    # Tie

Complete code

As I said, this code isn't perfect by any means, but it's a lot closer to being manageable, readable, understandable and scalable.

from time import sleep
from random import randint

LINE_END = "\n\n"

SHORT_SLEEP_TIME = 3
LONG_SLEEP_TIME = 4


def dice_roll():
    return randint(1, 6)


def player_dice_roll(player_num):
    print(f"Player {player_num}'s dice is rolling....", end=LINE_END)
    sleep(SHORT_SLEEP_TIME)

    dice1, dice2 = dice_roll(), dice_roll()

    print(f"Player {player_num} has rolled a {dice1} and a {dice2}", end=LINE_END)
    sleep(SHORT_SLEEP_TIME)

    return dice1, dice2


def roll_total(roll):
    return sum(roll)


def dice_equal(roll):
    return len(set(roll)) == 1


def get_player_score(scores, player_num):
    return scores[player_num - 1]


def add_player_score(scores, player_num, amount):
    scores[player_num - 1] += amount


def main():
    rounds_to_play = 5
    player_scores = [0, 0]

    for round_num in range(1, rounds_to_play + 1):
        print(f"Round {round_num} is about to commence!", end=LINE_END)
        sleep(SHORT_SLEEP_TIME)

        for player_num in (1, 2):
            roll = player_dice_roll(player_num)

            round_score = roll_total(roll)
            add_player_score(player_scores, player_num, round_score)

            print(f"Player {player_num}'s round {round_num} throw sums up to {round_score} which is added to their "
                  f"total score to give them {get_player_score(player_scores, player_num)} overall", end=LINE_END)
            sleep(LONG_SLEEP_TIME)

            if round_score % 2 == 0:
                add_player_score(player_scores, player_num, 10)
                print(f"In addition, Player {player_num}'s total is an even number, so they get an additional "
                      f"10 points added to their score, which is now {get_player_score(player_scores, player_num)}",
                      end=LINE_END)
            else:
                add_player_score(player_scores, player_num, -5)
                print(f"In addition, Player {player_num}'s total is an odd number, so they get 5 points taken away "
                      f"from their score, which is now {get_player_score(player_scores, player_num)}",
                      end=LINE_END)

            sleep(LONG_SLEEP_TIME)

            if dice_equal(roll):
                print(f"Furthermore, Player {player_num} has rolled a double and therefore recieves an extra roll",
                      end=LINE_END)
                sleep(LONG_SLEEP_TIME)
                print(f"Player {player_num}'s bonus dice is rolling...", end=LINE_END)
                sleep(SHORT_SLEEP_TIME)

                bonus_roll = dice_roll()
                add_player_score(player_scores, player_num, bonus_roll)

                print(f"Player {player_num}'s bonus roll has resulted in a {bonus_roll}, "
                      f"which is added to their total to give them {get_player_score(player_scores, player_num)}",
                      end=LINE_END)
                sleep(LONG_SLEEP_TIME)

        if round_num < rounds_to_play:
            print(f"After the conclusion of round {round_num}, ", end="")

            if all(map(lambda x: x < 0, player_scores)):
                print("both Player 1's total and Player 2's total is below 0, meaning both players lose")
                return

            elif get_player_score(player_scores, 1) < 0:
                print("Player 1's total is below 0 and Player 2's total is greater than 0, "
                      "meaning Player 2 automatically wins!")
                return

            elif get_player_score(player_scores, 2) < 0:
                print("Player 2's total is below 0 and Player 1's total is greater than 0, "
                      "meaning Player 1 automatically wins!")
                return

            else:
                print(f"both players' totals are above 0, meaning they can continue onto round {round_num + 1}",
                      end=LINE_END)
                sleep(LONG_SLEEP_TIME)

    player1_score = get_player_score(player_scores, 1)
    player2_score = get_player_score(player_scores, 2)

    print(f"Following the end of round {rounds_to_play}, the game is now over. "
          f"Player 1 has finished with a total of {player1_score}. "
          f"Player 2 has finished with a total of {player2_score}.",
          end=LINE_END)

    if player1_score > player2_score:
        print("This means that Player 1 has won the game after finishing with a higher total than Player 2")
    elif player1_score < player2_score:
        print("This means that Player 2 has won the game after finishing with a higher total than Player 1")
    else:
        print("This means that neither Player 1 or Player 2 has won the game after they both finish "
              "with the same total")


if __name__ == "__main__":
    main()

Finally, here are some ideas you could look into for further improvements:

  1. Broader application of the concepts mentioned in this answer
  2. As you can see in the code, there is no need to split a dice roll into its single dice inside our main logic. You could go a step further and implement a class DiceRoll that can create and store a roll of multiple dice. The class could then provide some properties like dice_values, total_value, all_dice_equal, etc.. This would be a cleaner approach than the helper functions roll_total and dice_equal, which are basically already halfway to the class implementation. This is a useful exercise that will come in handy in the future.
  3. You might also implement a class ScoreBoard or similiar, instead of hardcoding the player_scores as [0, 0] and using helper functions get_player_score and add_player_score.
\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.