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?
-
\$\begingroup\$ Sorry, not gonna read all that. Review = Use a loop. \$\endgroup\$Manuel– Manuel2021年04月15日 10:26:09 +00:00Commented Apr 15, 2021 at 10:26
-
1\$\begingroup\$ Welcome to the Code Review Community, I hope you get some good answers. \$\endgroup\$pacmaninbw– pacmaninbw ♦2021年04月15日 16:14:33 +00:00Commented Apr 15, 2021 at 16:14
1 Answer 1
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).
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:
- Broader application of the concepts mentioned in this answer
- 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 likedice_values
,total_value
,all_dice_equal
, etc.. This would be a cleaner approach than the helper functionsroll_total
anddice_equal
, which are basically already halfway to the class implementation. This is a useful exercise that will come in handy in the future. - You might also implement a
class ScoreBoard
or similiar, instead of hardcoding theplayer_scores
as[0, 0]
and using helper functionsget_player_score
andadd_player_score
.