4
\$\begingroup\$

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])
\$\endgroup\$
1
\$\begingroup\$

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:])
\$\endgroup\$
1
\$\begingroup\$

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.")
\$\endgroup\$
1
  • \$\begingroup\$ Will add that! thanks for the input :) \$\endgroup\$ – Monoxide Mar 2 at 21:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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