Dice "Game"
So, just started python a weeks time ago, so I'm looking for feedback/critique on things i can do to improve my code. I wrote a little user/pc dice rolling game. Any feedback at all is appreciated!
def dice(n: int) -> tuple:
"""
Simple function to roll 'n' number of dices.
Returns numbers of each roll and a total.
:param n: number of dices to roll
:return: dices_numbers, total
"""
numbers = []
total = 0
for dices in range(n):
number = random.randint(1, 6)
numbers.append(number)
total += number
dices_numbers = ", ".join(map(str, numbers))
return dices_numbers, total
def dice_check(user_total: int = 0, pc_total: int = 0) -> None:
"""
Function to check whether user or pc won dice roll.
:param user_total: user's total roll
:param pc_total: pc's total roll
:return: None
"""
if user_total > pc_total:
print("Congratulations! You won")
elif user_total < pc_total:
print("Sorry, BOT wins!")
else:
print("Tie!")
number_of_dices = ""
user_roll = ""
pc_roll = ""
while True:
number_of_dices = int(input("How many dices would you like to roll?"
" (0 to quit) >"))
if number_of_dices == 0:
break
else:
user_roll = dice(number_of_dices)
pc_roll = dice(number_of_dices)
print(f"You: Roll: {user_roll[0]}, a total of: {user_roll[1]}")
print(f"BOT: Roll: {pc_roll[0]}, a total of: {pc_roll[1]}")
dice_check(user_roll[1], pc_roll[1])
2 Answers 2
You're on the right path in putting most of your code inside of functions.
I encourage you to go the full distance and make it your standard habit.
The code below does that by creating a main()
function.
Python has a built-in sum()
function, so your dice()
and dice_check()
functions are probably doing more work than they need to. That's not a big
deal. Sometimes when you are learning, doing things the hard way can be
educational. In any case, the edited code below will illustrate how sum()
could simplify the situation.
The dice()
function can be shortened substantially using a tuple
comprehension, if you want. You could also consider simplifying all downstream
code by bundling the dice roll and their sum into a small object. In this
example, something very simple like a namedtuple
might be a good choice.
Notice how this change simplifies the return type of dice()
and also cleans
up code that has to use its return value. Notice also that this decision has
the unanticipated benefit of allowing us to directly compare the user
and
pc
dice rolls to determine the winner. This works because the total
attribute is placed first within the namedtuple
.
You already have a good suggestion to add some validation to the user input. By
shifting the collection of user input to its own function, you can keep
main()
focused on overall program orchestration. A general guideline is to
keep detailed computation out of a script's main()
. That function is almost always
the hardest to test in more complex programs, so you should get into the habit
of keeping it algorithmically simple. That thinking is behind the
get_result()
function: let some other piece of code determine the winner and
handle the grubby task of assembling whatever message should be printed.
For brevity in this example, I dropped most of the printing (you should enhance as needed) and the docstrings (its a good idea to retain them in the real program).
import random
import sys
from collections import namedtuple
Roll = namedtuple('Roll', 'total roll')
def main(args):
while True:
# Get N of dice from user or quit.
n = get_user_input()
if not n:
break
# Roll dice.
user = dice(n)
pc = dice(n)
# Report.
msg = get_result(user, pc)
print(msg)
def get_user_input() -> int:
while True:
prompt = 'How many dice would you like to roll? '
reply = input(prompt).strip()
try:
return int(reply) if reply else 0
except (ValueError, TypeError):
pass
def dice(n: int) -> Roll:
roll = tuple(random.randint(1, 6) for _ in range(n))
return Roll(sum(roll), roll)
def get_result(user, pc) -> str:
winner = (
'You' if user > pc else
'Bot' if pc > user else
'Tie'
)
return f'Winner: {winner} {user} {pc}'
if __name__ == '__main__':
main(sys.argv[1:])
I'm pretty new as well, but I like to create an exception whenever I try to convert user input to an integer. Something like this-
while True:
try:
number_of_dices = int(input("How many dices would you like to roll?"
" (0 to quit) >"))
except ValueError:
print("Please enter a number.")