I'm still a beginner with just a few months experience in programming. I'm writing a program to roll dice in a few modes. I'm having a problem with my Selective mode.
Code:
from os import system
from platform import system as operating_system
from random import randint, randrange
from textwrap import dedent
from time import sleep
from typing import Union
def user_input() -> tuple[list[int], list[int]]:
"""Option selection"""
dictionary_input: dict[str, str] = {
"dice":
"How many dice to roll?\n",
"sides":
"Type in the maximum number:\n",
"confirm": """
Your mode is {2}, you're rolling {0}d{1} dice.\n
Is this correct? (y/n/quit)\n""",
"includes_confirm": """
Your mode is {2}, you're rolling {0} dice from numbers:
{1}\n
Is this correct? (y/n/quit)\n""",
"mode": """
Please select a number of your desired mode:
1) Normal
2) Increments of 10 (0 included)
3) Selective (Only numbers specified by user)
4) Exclude (Do not repeat numbers)
5) Exit the app\n"""}
mode_input: dict[int, str] = {
1: "Normal",
2: "Increments",
3: "Selective",
4: "Exclude"
}
choice: list[int] = [0, 0, 0]
dice, sides, mode = 0, 6, 0
included_numbers: list[int] = []
confirmation: str = ""
while confirmation.upper() != "Y":
try:
# ask for mode
mode = int(input(dedent(dictionary_input["mode"])))
if mode == 5:
break
# ask for number of dice to roll
dice = int(input(dictionary_input["dice"]))
if mode == 3:
# selective numbers options
included_numbers.append(*number_inclusion()) # this part returns [], why?! (ノಠ益ಠ)ノ彡┻━┻
print(included_numbers) # <- doesn't work
if len(included_numbers) < 1:
continue
else:
# check for increment of 10 while in increments mode
if mode == 2:
while sides % 10 != 0:
sides = int(input(dictionary_input["sides"]))
if sides % 10 != 0:
print(f"{sides} is not an increment of 10")
continue
else:
sides = int(input(dictionary_input["sides"]))
# confirmation from user
if dice > 0 and sides > 0:
if mode in mode_input:
if mode != 3:
confirmation = input(
dedent(dictionary_input["confirm"]).format(
dice, sides, mode_input[mode]))
else:
confirmation = input(
dedent(dictionary_input["includes_confirm"])
.format(dice, included_numbers,
mode_input[mode]))
if confirmation.upper() != "QUIT":
choice[0], choice[1], choice[2] = dice, sides, mode
else:
break
else:
print("Mode accepts numbers 1 - 5\n\n")
continue
else:
print("Only positive numbers\n\n")
continue
except ValueError:
print("Only numbers accepted\n\n")
continue
return (choice, included_numbers)
def number_inclusion() -> list[int]:
"""Function used with mode Selective, stores user numbers"""
included_numbers: list[int] = []
temp_input: Union[int, str] = 0
ask = {
"first": """
Type \"review\" to view numbers,
type \"remove\" to delete numbers,
type \"done\" to finish.""",
"next":
"Type in your number:\n"
}
print(dedent(ask["first"]))
while str(temp_input).upper() != "DONE":
temp_input = input(dedent(ask["next"]))
# input verification
if temp_input.upper() not in ["DONE", "REVIEW", "REMOVE"]:
try:
if int(temp_input) < 0:
print("Only positive numbers accepted")
raise ValueError
if float(temp_input) % 1 != 0:
print("Only integers accepted")
raise ValueError
if int(temp_input) in included_numbers:
print("Number is already on the list")
continue
included_numbers.append(int(temp_input))
print(f"added number {temp_input} to selection")
continue
except ValueError:
print("Unsuported option")
continue
if str(temp_input).upper() == "REVIEW":
print(f"Saved numbers are:\n{included_numbers}")
continue
if str(temp_input).upper() == "REMOVE":
print(f"Saved numbers are:\n{included_numbers}")
try:
temp_remove: int = int(input(
"Which would you like to remove?\n"))
if temp_remove in included_numbers:
included_numbers.remove(temp_remove)
print("Number removed")
else:
raise ValueError
except ValueError:
print("Select a number from your list.\n\n")
else:
included_numbers.append(int(temp_input))
print(f"added number {temp_input} to selection")
print(included_numbers) # <- doesn't work
return included_numbers
The function number_inclusion()
should return a list with numbers and append into included_numbers
in user_input()
with that list. While everything seems fine when reviewing
Type in your number:
>>>1
>>>2
>>>3
>>>review
Saved numbers are:
[1, 2, 3]
after the number_inclusion()
execution in user_input()
i get straight to ValueError
with message Only numbers accepted
from the first try...except block in user_input()
I want number_inclusion()
to return a list[int]
which will replace included_numbers
in user_input()
Any tips how to improve this monster of a function would also be greatly appreciated!
EDIT: Thanks to Paul Cornelius I've managed to fix my bugs. For anyone going through here this is what worked:
Removing this part at bottom of number_inclusion()
since it's already covered in the while loop
else:
included_numbers.append(int(temp_input))
print(f"added number {temp_input} to selection")
Replacing append
with extend
in user_input()
if mode == 3:
# selective numbers options
included_numbers.extend(number_inclusion())
if len(included_numbers) < 1:
continue
There's probably more stuff to improve here but at least it works as intended.
CodePudding user response:
There is a logic problem in your function number_inclusion
, at the bottom of the loop:
if str(temp_input).upper() == "REMOVE":
print(f"Saved numbers are:\n{included_numbers}")
try:
temp_remove: int = int(input(
"Which would you like to remove?\n"))
if temp_remove in included_numbers:
included_numbers.remove(temp_remove)
print("Number removed")
else:
raise ValueError
except ValueError:
print("Select a number from your list.\n\n")
else:
included_numbers.append(int(temp_input))
print(f"added number {temp_input} to selection")
If temp_input
is 'done', the else:
branch will be taken and int(temp_input)
will raise a ValueError. You can simply eliminate the entire else block; the loop logic handles the case where temp_input is "done."
It is good practice to put as few lines of code between try: and except: as the program logic allows, as Tadhg McDonald-Jensen pointed out in his comment. Programs become hard to debug if there are too many lines of code where an Exception can possibly be raised before it gets handled.
You might also look at the traceback
module, which allows you to print a traceback from inside an Exception handler block. Sometimes it quickly leads you to the problem. In fact, that's how I found this one.