Python Forum
Lab Assignment with Array's & Loops
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Lab Assignment with Array's & Loops
#1
Well I'm at a loss on this one now, and of course it doesn't help that I'm not that good at python. I got a lot of good help with the last assignment I posted on here, so I'm back again, doing something different.

This time around I'm trying to make a dice roller based off rules for a tabletop RPG called Hero System. In this game you roll 3d6 for your attack roll, and then between 1 or as many as you can hold other d6's, although for this lab, the array I set uses 12d6.

3d6 is three six sided dice, and 12d6 would of course be twelve six sided dice for those who are not familiar with the terminology.

So to get started, the parameters of the assignment are:
  • Your name given as the author.
  • Comments including a brief description of the program, Input List and Output List, and full pseudocode. Place the pseudocode for each module above the module's Python code.
  • The program must have at least one input and at least one output.
  • All user input must be validated. This means the user is not allowed to just enter any value. You must check the value, and ask the user to enter it again, and repeat this loop until the user enters a valid value.
  • Your program must use at least two arrays in meaningful ways. These two arrays can contain any type of values, as long as they are both used meaningfully in your program.
  • Your program must have at least one loop that accesses the data in the arrays. For example, you might have an input loop that asks the user to enter the data one element at a time (be sure to validate the data). Or, you might have an output loop that writes the data to the console. Or, you might have a calculation loop that calculates one or more values, such as minimum value, maximum value, averages, and so on. You can have all three of those types of loops, if you want (the Lab 5 walkthrough video shows an example of each).
  • Your program should be organized into separate modules. Each module should be "cohesive" and should only do one thing.
  • Use parameters and arguments to pass values into your modules (don't use global variables).
  • The Python code should run correctly, and the logic should match your pseudocode.

No Pseudocode is entered, I typically enter that after doing the functioning code since the pseudocode doesn't do anything to make the program work.

I'll break my code up to explain my thoughts.

import random

def attack_roll():
    dice_roll = (input("Press [ENTER] to make your attack roll.") == "")
    while True:
        dice = [0, 0, 0,]
        for x in range(3):
            dice[x] = random.randint(1,6)
        print("Your attack roll total is:", dice)
        break
So in this first function, it will roll 3 dice and display the results. This part works.

But now we come to the problem part.

def successful_attack(attack_hit):
    while True:
        success = input("Did your attack hit? (Y / N)  ")
        if success in ['Yes', 'yes', 'Y', 'y']:
            return 'Y'
        elif success in ['No', 'no', 'N', 'n']:
            return "N"
The above section is meant to check with you to see if your attack hit. If you choose Yes then you move on to the next part, but if no then it should kick you backup to roll your 3 dice again. But it doesn't.

def doing_damage():
    while True:
        attack_hit = print("You may only roll a maximum of 12 dice.")
        damage_dice = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        for y in range == input("How many damage dice will you roll (1 to 12)?  ", int()):
            damage_dice[y] = random.randint(1,6)
        print("Your damage dice roll is:  ", damage_dice[y])
        break

def main():
    while True:
        attack_roll()
        successful_attack(attack_hit)
        attack_hit = doing_damage()

main()
Now in this last part the Yes/No check is supposed move you onto selecting between 1 and 12 dice to roll if you choose yes. But instead I just get the usual error messages. I'm hoping that what I've set up will allow you to enter said number and output each die result.

Now I have tried to code this a few different ways, and I've attempted any number of combinations of calls in the main(), adding and removing elements, but I haven't managed to work out a way to get this to work.

I would like to add that my code cannot be too complex or move outside the boundaries of what we've been taught in class (sequence, input/output, modularity, decision structures, repetition, function, validation, and currently on arrays).

Once again, any help is appreciated.
Reply
#2
With regards to your first code snippet:
You don´t need the variable dice_roll as you don´t use it and why do you compare the input with an empty string?
What is the while-loop for if you break out of it immediately?
The for-loop can be simplified with a list comprehension.
import random
 
def attack_roll():
    input("Press any key to make your attack roll.")
    dice = [random.randint(1,6) for _ in range(3)]
    print(f"Your attack roll is: {dice}")
With regards to your 2nd code snippet:
Ok, now the while-loop runs until you enter a valid answer Y/N
but you need to call above attack_roll() again if you answer 'No'
and you leave the function with return only if you answer 'Yes'
def successful_attack(attack_hit):
    while True:
        answer = input("Did your attack hit? (Y/N) ")
        if answer.lower() in ['yes', 'y']:
            return
        elif answer.lower() in ['no', 'n']:
            attack_roll()
With regards to your 3rd code snippet:
This is complete garbage: attack_hit = print() WHY?
This is pure nonsense: for y in range == input("How many damage dice will you roll (1 to 12)? ", int()):
Why damage_dice[y] in the print("Your damage dice roll is: ", damage_dice[y])?
And agin, why a while-loop if you break out of it immediately?
You need to do some more python learning, you are guessing what might be correct
and that´s not the way programming works.
def doing_damage():
    while True:
        attack_hit = print("You may only roll a maximum of 12 dice.")
        damage_dice = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        for y in range == input("How many damage dice will you roll (1 to 12)?  ", int()):
            damage_dice[y] = random.randint(1,6)
        print("Your damage dice roll is:  ", damage_dice[y])
        break 
Why a while-loop in the main() function without any way to leave it? Wanna run the code forever?
Where does the variable attack_hit come from? Out of nowhere?
And you are not using it inside the function, so useless.
And last you are not returning anything in your function doing_damage()
so attack_hit is None as this is the default return value if you don´t call return with a value.
def main():
    while True:
        attack_roll()
        successful_attack(attack_hit)
        attack_hit = doing_damage()

main()
Reply
#3
(Aug-06-2019, 06:17 PM)jonstryder Wrote: No Pseudocode is entered, I typically enter that after doing the functioning code since the pseudocode doesn't do anything to make the program work.

Pseudocode does nothing to make the program work if you write it after you write the code. But if you write it before you write the code, it can help quite a bit. It's called planning, and when you are coding larger projects with a team, it's essential.

Your first bit of code can be simplified:

import random
 
def attack_roll():
    input("Press [ENTER] to make your attack roll.")
    dice = [0, 0, 0,]
    for x in range(3):
        dice[x] = random.randint(1,6)
    print("Your attack roll total is:", dice)
You don't need to test that they just pressed enter, and you don't need to store that test. You don't need a loop if you are always going to break out of it after going through it once. Note that if you want the total of the dice, you can use sum(dice) to get that. If you have covered append, this becomes even simpler:

def attack_roll():
    input("Press [ENTER] to make your attack roll.")
    dice = []
    for x in range(3):
        dice.append(random.randint(1,6))
    print("Your attack roll total is:", dice)
Your successful_hit function is working, although I'm not sure why you are passing the attack_hit to hit. You don't do anything with it in the function. Maybe you're planning on doing that later. The problem is that you are not getting or testing the return value of that function. The call to the function should be success = successful_attack(attack_hit). Then you would test the success variable to see if it is 'Y', in which case you would ask for damage.

Note that your doing_damage function has several problems. The range function is never going to be equal to a string from input, and int() should go around the input, not as a parameter to it. Also, you are not returning anything to be stored in attack_hit on line 14.

If you are getting errors, usual or not, giving us the full text of the errors will help us help you.
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply
#4
(Aug-06-2019, 07:35 PM)ThomasL Wrote: With regards to your first code snippet:
You don´t need the variable dice_roll as you don´t use it and why do you compare the input with an empty string?
What is the while-loop for if you break out of it immediately?
The for-loop can be simplified with a list comprehension.
import random
 
def attack_roll():
    input("Press any key to make your attack roll.")
    dice = [random.randint(1,6) for _ in range(3)]
    print(f"Your attack roll is: {dice}")

So part of what's required in the assignment is that I make use of 2 array's. Unfortunately loosing the array from the first part is against the guidelines of the assignment. The reason why the "while" is in place is based on what I've seen in some other places regarding dice rolling programs and looking over said work to help me in trying to figure out how to build mine. I'm a very visual & hands-on learner, and not that good at python.

Quote:With regards to your 3rd code snippet:
This is complete garbage: attack_hit = print() WHY?
This is pure nonsense: for y in range == input("How many damage dice will you roll (1 to 12)? ", int()):
Why damage_dice[y] in the print("Your damage dice roll is: ", damage_dice[y])?
And agin, why a while-loop if you break out of it immediately?
You need to do some more python learning, you are guessing what might be correct
and that´s not the way programming works.
def doing_damage():
    while True:
        attack_hit = print("You may only roll a maximum of 12 dice.")
        damage_dice = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        for y in range == input("How many damage dice will you roll (1 to 12)?  ", int()):
            damage_dice[y] = random.randint(1,6)
        print("Your damage dice roll is:  ", damage_dice[y])
        break

First and foremost, I appreciate help, not being talked down to. The course I am taking is an introduction, not some damn advanced course. I wrote the instructions I have to follow above. I said I am not good at this stuff. I came here for help because I don't understand this.

And I hate to break the news to you, but the learning process involves a lot of guesswork when you don't know how to do something!

If you want to help, then be helpful, what you've offered up is not helpful at all and has only served to irritate me.


(Aug-06-2019, 07:39 PM)ichabod801 Wrote:
(Aug-06-2019, 06:17 PM)jonstryder Wrote: No Pseudocode is entered, I typically enter that after doing the functioning code since the pseudocode doesn't do anything to make the program work.

Pseudocode does nothing to make the program work if you write it after you write the code. But if you write it before you write the code, it can help quite a bit. It's called planning, and when you are coding larger projects with a team, it's essential.

Your first bit of code can be simplified:

import random
 
def attack_roll():
    input("Press [ENTER] to make your attack roll.")
    dice = [0, 0, 0,]
    for x in range(3):
        dice[x] = random.randint(1,6)
    print("Your attack roll total is:", dice)

Thanks, I've followed this and made the changes. It still has the needed array too Big Grin .

I do need a loop in there, at least one, for the assignment to be accepted, in addition to a second array. I thought that a simple Yes/No loop would be acceptable for this. Would there be a better method of incorporating a simple loop?

The idea is that once you know what your "to hit" roll is, it stops you and asks if you need to roll damage. In a normal tabletop game, the Game Master is told the roll and they tell you if you hit/succeed. Thus if the roll didn't hit/succeed, you type no and go back up to roll again. But if it's yes, then you move on to picking the number of dice you roll for damage.

Anyway, with just the one change, I ran the program to test things out, here is what the output is.

"G:\College Files\Current Classes\CIS - 122 - Intro to Programing Logic\projects\venv\Scripts\python.exe" "G:/College Files/Current Classes/CIS - 122 - Intro to Programing Logic/projects/Lab5.py"
Press [ENTER] to make your attack roll.
Traceback (most recent call last):[/color]
Your attack roll total is: [6, 1, 2]
  File "G:/College Files/Current Classes/CIS - 122 - Intro to Programing Logic/projects/Lab5.py", line 38, in <module>
The total of the roll is:   9
    main()
  File "G:/College Files/Current Classes/CIS - 122 - Intro to Programing Logic/projects/Lab5.py", line 35, in main
    successful_attack(attack_hit)
UnboundLocalError: local variable 'attack_hit' referenced before assignment
I'll hammer away on getting my Yes/No to work next.
Reply
#5
(Aug-06-2019, 08:46 PM)jonstryder Wrote: I do need a loop in there, at least one, for the assignment to be accepted, in addition to a second array.

Okay, but I don't think your teacher is going to accept a loop that doesn't do anything and isn't needed. What about having them enter the number they need to hit? One loop to validate that input, and then automatically determine if they hit or not, tell them, and then if necessary ask for how many dice for damage, with another loop to validate that?
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply
#6
(Aug-06-2019, 10:13 PM)ichabod801 Wrote: Okay, but I don't think your teacher is going to accept a loop that doesn't do anything and isn't needed. What about having them enter the number they need to hit? One loop to validate that input, and then automatically determine if they hit or not, tell them, and then if necessary ask for how many dice for damage, with another loop to validate that?

Very true...I was hoping the yes/no would be sufficient, and would work (which it's not). Usually a Game Master doesn't tell you what you have to roll in order to hit a target, so I was hoping to avoid this and just let you answer "yes" you want to roll damage, or "no" you don't and just make the 3d6 roll again.

But given the fact that I can't make the Yes/No function work, I'll have to do something else.

So how would you suggest coming at this then? Start by entering the number needed to hit, the random number is rolled, totaled, then displays if you hit or not? If not you roll again, but if you do then it moves you onto the next module/function?
Reply
#7
(Aug-06-2019, 10:45 PM)jonstryder Wrote: Start by entering the number needed to hit, the random number is rolled, totaled, then displays if you hit or not? If not you roll again, but if you do then it moves you onto the next module/function?

I might just loop through what do you need to hit and how many damage dice. Like a helper for a DM running multiple monster attacks.
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply
#8
(Aug-06-2019, 10:57 PM)ichabod801 Wrote:
(Aug-06-2019, 10:45 PM)jonstryder Wrote: Start by entering the number needed to hit, the random number is rolled, totaled, then displays if you hit or not? If not you roll again, but if you do then it moves you onto the next module/function?
I might just loop through what do you need to hit and how many damage dice. Like a helper for a DM running multiple monster attacks.

Interesting, I was looking at it from the angle of the player, and not the Game Master. I'll see what I can do and then post it.
Reply
#9
(Aug-06-2019, 10:57 PM)ichabod801 Wrote: I might just loop through what do you need to hit and how many damage dice. Like a helper for a DM running multiple monster attacks.

Ok, I've written something up for the first part of this.

__author__ = 'me'

import random

print("")

def target_num():
    while True:
        score = int(input("Enter the Target Number for your 3d6 Attack Roll.  "))
        dice = [0, 0, 0]
        for x in range(3):
            dice[x] = random.randint(1, 6)
        if sum(dice) <= score:
            print("Dice results:  ", dice)
            print("Dice results totaled:  ", sum(dice))
            print("Your attack roll HITS!")
            return score
        elif sum(dice) >= score:
            print("Dice results:  ", dice)
            print("Dice results totaled:  ", sum(dice))
            print("The attack roll MISSES!")
            return score
        else:
            print("You must enter a number.")

def main():
        target_num()

main()
If I input a number, everything works fine. But when I tested inputting something besides a number I get an error.

Traceback (most recent call last):
  File "G:/College Files/Current Classes/CIS - 122 - Intro to Programing Logic/projects/Lab5.py", line 29, in <module>
    main()
  File "G:/College Files/Current Classes/CIS - 122 - Intro to Programing Logic/projects/Lab5.py", line 27, in main
    target_num()
  File "G:/College Files/Current Classes/CIS - 122 - Intro to Programing Logic/projects/Lab5.py", line 8, in target_num
    score = int(input("Enter the Target Number for your 3d6 Attack Roll.  "))
ValueError: invalid literal for int() with base 10: 'm'
Now I'm guessing that it won't loop back to the start since the code is incomplete as I need to add a second and maybe third part (the damage die roll) to the program. Am I right in this assessment?

But to move on to the next half, if the attack hits then it needs to then display the damage dice to be rolled, but if it misses then I need it to start the attack roll over again.

I'm going to try and work on this next part, with a mind toward a person inputting a number properly instead of accidentally entering a letter.
Reply
#10
The error you are getting is what the assignment talks about with validating user code. You need to validate the input before using it. I don't know what you have covered. Normally I would use try/except to validate, but you may not have gotten to that:

while True:
    value = input('enter number: ')
    try:
        value = int(value)
        break
    except ValueError:
        print('numbers only please')
If you haven't covered that, the isdigit method of strings will return True if the string only contains digits 0-9.

And yes, you need a loop in main to keep asking the questions. Also, you need to return the hit or miss status from target_num to main, and then use it to decide whether or not to roll for damage.
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Trouble with Loops in lab assignment jonstryder 6 3,353 Jul-28-2019, 06:40 PM
Last Post: ThomasL
  Array to get profit (school assignment) harryvandervelden 2 2,810 Nov-28-2017, 05:48 PM
Last Post: Larz60+

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020