Python骰子投掷程序问题:如何统计符合阈值的成功命中次数
Hey there! Let's work through your dice roller issue step by step. I can see you're building a tool for tabletop gaming (looks like Warhammer 40k from the username!) and have a few bugs in your current code, plus plans to expand it with modifiers. Let's fix the core functionality first, then talk about those future features.
Issues in Your Current Code
- Fragile input checking:
whatisneededtoday [1] == 't'relies on the second character of the input being 't', which breaks if the user types a capitalized word (like "Attack") or misspells it. Normalizing input to lowercase and checking for the full action name is much more reliable. - Incorrect loop logic: When you use
for i in randomlist:,irepresents the actual dice roll value (e.g., 3, 5), not an index. Trying to accessrandomlist[i]will cause index errors (for example, a roll of 6 will try to access the 6th element in a shorter list). - No hit tracking: Your current code just prints the number of dice instead of counting how many rolls meet or exceed your Ballistic Skill (BS) value.
- Missing input validation: If the user enters a non-number for BS or dice count, the code will crash immediately. We can add a helper function to handle this.
Fixed Code for Core Hit Counting
This version fixes all the above issues and adds basic melee support too:
import random def get_integer_input(prompt): # Helper function to safely get integer input from the user while True: try: return int(input(prompt).strip()) except ValueError: print("Oops, please enter a valid whole number!") # Get and normalize the selected action selected_action = input('Select an action: attack, psychic, charge, unit table.').strip().lower() if selected_action == 'attack': attack_type = input('Melee or ranged? ').strip().lower() if attack_type == 'ranged': print("--- Ranged Attack Phase ---") bs = get_integer_input('What is your Ballistic Skill? ') dice_count = get_integer_input('How many dice to roll? ') # Roll all the dice dice_rolls = [random.randint(1, 6) for _ in range(dice_count)] print(f"Your rolls: {dice_rolls}") # Calculate total hits total_hits = 0 for roll in dice_rolls: if roll >= bs: total_hits += 1 print(f"Total successful hits: {total_hits}") elif attack_type == 'melee': print("--- Melee Attack Phase ---") ws = get_integer_input('What is your Weapon Skill? ') dice_count = get_integer_input('How many dice to roll? ') dice_rolls = [random.randint(1, 6) for _ in range(dice_count)] print(f"Your rolls: {dice_rolls}") total_hits = 0 for roll in dice_rolls: if roll >= ws: total_hits += 1 print(f"Total successful hits: {total_hits}") elif selected_action == 'psychic': print("Psychic test functionality coming soon!") elif selected_action == 'charge': print("Charge test functionality coming soon!") elif selected_action == 'unit table': print("Unit table functionality coming soon!") else: print("Invalid action selected. Please choose from attack, psychic, charge, unit table.")
Expanding for Special Roll Modifiers
To add rules like extra hits on critical rolls (e.g., 6s) or mortal wounds, here's how you can extend the code:
1. Track Special Roll Types
Add variables to count critical hits, fumbles, or other special outcomes:
total_hits = 0 critical_hits = 0 mortal_wounds = 0 for roll in dice_rolls: if roll >= bs: total_hits += 1 if roll == 6: critical_hits += 1 # Example: Critical hits cause an extra mortal wound mortal_wounds += 1 elif roll == 1: print(f"Fumble on roll {roll}! Your weapon jams!") print(f"Total hits: {total_hits} | Critical hits: {critical_hits} | Mortal wounds: {mortal_wounds}")
2. Make Modifiers Configurable
Let users toggle special rules with input prompts:
extra_hit_on_crit = input("Does this attack grant an extra hit on 6s? (y/n) ").strip().lower() == 'y' # Then in the roll loop: if roll == 6 and extra_hit_on_crit: total_hits += 1 # Add an extra hit for the critical roll
3. Reusable Functions
Since melee and ranged attacks share most logic, create a helper function to avoid repetition:
def calculate_hits(skill, dice_count, critical_rule=False): rolls = [random.randint(1,6) for _ in range(dice_count)] hits = 0 crits = 0 for roll in rolls: if roll >= skill: hits +=1 if roll ==6: crits +=1 if critical_rule: hits +=1 return rolls, hits, crits # Use it in ranged attack: dice_rolls, total_hits, critical_hits = calculate_hits(bs, dice_count, extra_hit_on_crit)
内容的提问来源于stack exchange,提问作者warhammer40knerd

