Error message:
FE..
************ MISSING LINE ***************
file 1 line number: 2
missing line in file 2, no match for file 1 line:
'=================== ROUND 1 ===================\n'
*****************************************
F..
======================================================================
ERROR: test_combat_round (__main__.TestRPG)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_rpg.py", line 64, in test_combat_round
self.assertIsNone(combat_round(self.rich, self.thompson))
File "/Users/ajsmitty12/Desktop/ISTA130/rpg.py", line 124, in combat_round
player1.attack(player1, player2)
AttributeError: 'int' object has no attribute 'attack'
======================================================================
FAIL: test_attack (__main__.TestRPG)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_rpg.py", line 42, in test_attack
self.assertEqual(out, buf.getvalue())
AssertionError: 'Rich attacks Thompson!\n\tHits for 5 hit points!\n\tThompson h[24 chars]g.\n' != 'Rich attacks Thompson (HP: 10)!\n\tHits for 5 hit points!\n\tT[33 chars]g.\n'
- Rich attacks Thompson!
+ Rich attacks Thompson (HP: 10)!
? +++++++++
Hits for 5 hit points!
Thompson has 5 hit points remaining.
======================================================================
FAIL: test_main (__main__.TestRPG)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_rpg.py", line 117, in test_main
self.assertTrue(compare_files('rpg_main_out_correct.txt', out))
AssertionError: False is not true
----------------------------------------------------------------------
Ran 7 tests in 0.006s
FAILED (failures=2, errors=1)
Correctness score = 57.14285714285714%
Description:
-This program will simulate combate for a simple Role Playing Game (RPG).
- The game has a single type of character, the Fighter.
-Each inidividual Fighter has an integer value caled "hit points" that represents his/her current health (the amount of damage he/she can sustain before death)
-It will simulate combat between 2 Fighers.
-Combat is divided into rounds:
-During each round each combatant will make 1 attempt to stike the other.
-We will use random numbers to simulate rolling dice, the higher number attacks first, and the lower number goes 2nd if still alive.
-If there is a tie, the players will go at the same time, they will attack eachother at the same moment.
-During a simultaneous attack both Fighters will get to attack even if one (or both) if (are) killed during that round.
-The progam will use a random number to determine whether an attack attempt is successful or not.
-Each successful attack will inflict damage on the opponent.
-To simulate damage, we'll reduce the opponent's hit points by another random number
-When a Fighters hit points are reduced to 0 (or less than 0) that player is considered to be dead.
-Combat round continue until one(or both) combatants are dead.
'''
I am having a hard time figuring out how to call my instances for Fighter that I created within the class too my combat function, that is outside of the class.
I am also wondering if I am comparing player1 and player2's random numbers correctly. When messing around with it I tried using:
player1 = Fighter()
player2 = Fighter()
When doing this my error message would said that Fighter() > Fighter() are not comparable.
Lastly, not quite sure why my test_attack is failing.
My code (so far):
import random
class Fighter:
def __init__(self, name):
'''
-This is my initializer method, which takes 2 parameters:
-Self
-Name (a string, the name of a fighter)
-This method will set a name attribute to the value of the name parameter
-It will also set a hit_points attribute to 10 (all fighters begin life with 10 hit points).
'''
self.name = name
self.hit_points = 10
def __repr__(self):
'''
-This method takes 1 parameter, self.
-It returns a string showing the name and hit points of the instances in the following format:
Bonzo (HP: 9)
'''
result = str(self.name) + " (HP: " + str(self.hit_points) + ")"
return result
def take_damage(self, damage_amount):
'''
-This method takes 2 parameters:
-self (the Fighter instance that calls the method)
-damage_amount (an integer representing the number of hit points of damage that have just been inflicted on this Fighter):
-The method should first decrease the hit_points attribute by the damage_amount.
-Next, it should check to see if the Fighter has died from the damage:
-A hit_points value that is 0 or less indicates death, and will print a message like the following:
\tAlas, Bonzo has fallen!
-Otherwise, it will print a message like the following (in this example, the player had 5 hit points left over after damage)
\tBonzo has 5 hit points remaining.
-The method returns nothing.
'''
self.hit_points = self.hit_points - damage_amount
if self.hit_points <= 0:
print('\t' + 'Alas, ' + str(self.name) + ' has fallen!')
else:
print('\t' + str(self.name) + ' has ' + str(self.hit_points) + ' hit points remaining.')
def attack(self, other):
'''
-This method takes 2 parameters:
-self
-other (another Fighter instance being attacked by self)
-The method will print the name of the attacker and attacked in the following format:
Bonzo attacks Chubs!
-Next, determine whether the attack hits by generating a random integer between 1 and 20
-Use the randrange function from the random module to get this number.
-A number that is 12 or higher indicates a hit:
- For an attack that hits, generate a random number between 1 and 6(using random.randrange) to represent the amount of damage inflicted by the attack
***Do NOT use the from random import randrange sytanze (randrange works like range, not like randint (think about the upper bounds you choose)).
- Print the amount of damage inflicted like the following:
\tHits for 4 hit points!
-Invoke the take_damage method on the victim (i.e. on other), passing it the amount of damage inflicted.
-For an attack that misses, print the following message:
\tMisses!
-This method returns nothing.
'''
self.other = Fighter(self.name)
print(str(self.name) + ' attacks ' + str(other) + '!')
attack = random.randrange(1, 20)
if attack >= 12:
damage_amount = random.randrange(1, 6)
print('\t' + 'Hits for ' + str(damage_amount) + ' hit points!')
other.take_damage(damage_amount)
else:
print('\t' + 'Misses!')
def is_alive(self):
'''
-This method takes 1 parameter, self.
-It returns True if self has a positive number of points, False otherwise.
'''
if self.hit_points > 0:
return True
else:
return False
def combat_round(player1, player2):
'''
-This function takes 2 parameters:
-The 1st is an instance of Fighter.
-The 2nd is another instance of Fighter.
-It determines which of the 2 fighters attacks 1st for the round by generating a random interger (use randrange) between 1 and 6 for each fighter:
-if the numbers are equal:
-print the following message:
Simultaneous!
-Have each figher instance call his attack method on the other figher (the 1st figher in the argument list must attack first to make the test work correctly)
-if one number is larger:
-the fighter with the larger roll attacks 1st (by calling his attack method and passing it the figher being attacked).
-if the 2nd fighter survives the attack (call is_alive), he then attack the 1st.
-This function returns nothing.
'''
Fighter.name = player1
Fighter.name = player2
player1 = random.randrange(1, 6)
player2 = random.randrange(1, 6)
if player1 == player2:
print('Simultaneous!')
player1.attack(player2)
if player1 > player2:
player1.attack(player2)
if player2.is_alive() == True:
player2.attack(player1)
if player2 > player1:
player2.attack(player1)
if player1.is_alive() == True:
player1.attack(player2)
You class looks okay, but the combat_round function has some problems.
You were on the right track with player1 = Fighter() etc..
player1 = Fighter(name = 'Jeff')
player2 = Fighter(name = 'Bill')
But now you want to choose one to go first. You cant just compare them with >, <, == without customizing special methods like __eq__() because Python doesn't know which attribute to compare. How about setting an attribute then comparing it:
player1.speed = random.randrange(1,6)
player2.speed = random.randrange(1,6)
Now you can write tests like this:
if player1.speed == player2.speed:
print("Simultaneous!")
Also, if the function combat_round() takes instances of fighter, then you dont need to instantiate them inside the function. But, if the function takes strings that are the names of the fighters then you would do it like my example.
Related
I am encountering a strange error with a mini game I have created as part of a quiz application I am building to run in terminal. The mini game requires processes to run asynchronously, so I defined two coroutines to create it: one that prompts for input (using aioconsole.ainput(), an asynchronous input function) and one that executes a loop until input is entered. The mini game works fine on its own (included it in another program I made where it ran smoothly) and executes without error in the current application I am building, but after the mini game has executed, whenever I call the normal input() function, I receive an EOF error:
Traceback (most recent call last):
File "/Users/[...]/quiz_game.py", line 449, in <module>
quiz()
File "/Users/[...]/quiz_game.py", line 433, in quiz
prev_score = show_score(playerList,prev_score)
File "/Users/[...]/quiz_game.py", line 375, in show_score
input('Hit enter to continue.')
EOFError
I am 99.99% certain that the error has to do with some residual effect of executing the mini game's code, probably a residual effect of using aioconsole.ainput() because the code worked fine before I added the mini game into it, and distinct calls of input() in different locations within the overall code have triggered this error.
Here's the code of the mini game:
async def getInput():
global flag
flag = False
task = asyncio.create_task(loop())
await aioconsole.ainput()
flag = True
await task
return task.result()
async def loop():
count = 0
x = 20
while not flag:
count += 1
print('Hit enter at 20:' + '#' * (count % (x + 1)) + ' ' * (x - count %
(x + 1)),
end='\r')
await asyncio.sleep(0.1)
return count
def minigame():
print('\nScore 20 to get a powerup.')
for i in range(1,4):
print(f'---ATTEMPT {i}---')
result = asyncio.run(getInput()) % 21
print('Score:' + str(result))
if result == 20:
print('SUCCESS!!!')
time.sleep(2)
return
else:
print(
random.choice([
'I said 20, moron!', 'Can you not count?',
'Tut, tut, tut. Such a disappointment.'
]))
print('Try again\n')
print('FAIL. You have exhausted your 3 attempts.')
time.sleep(2)
Short Description of Mini Game:
The mini game displays an increasing number of hashtags until it hits twenty hashtags and then starts over at zero hashtags. If the user hits enter at exactly twenty hashtags, they win the game.
Anyways, any help that you could provide would be greatly appreciated!
I've implemented a memory game where the user has to sort numbers in his head while a timer of 5 sec is running.
Please see code below:
from random import randint
from threading import Timer
def timeout():
print("Time over\n#####################\n")
while True:
list = []
for i in range(5):
list.append(randint(1000, 10000))
t = Timer(5, timeout)
t.start()
print(list)
print('[ 1 , 2 , 3 , 4 , 5 ]')
solution = sorted(list)[2]
print('please select the 3rd largest number in this row (1-5):')
input_string = input()
selection = int(input_string)
if solution == list[selection - 1]:
print("Your guess is correct\n")
else:
print("Your guess is wrong\n")
t.join()
Here is the game interaction itself (please ignore the syntax highlighting):
USER#HOST:~/$ python3 memory_game.py
[8902, 8655, 1680, 6763, 4489]
[ 1 , 2 , 3 , 4 , 5 ]
please select the 3rd largest number in this row (1-5):
4
Your guess is correct
Time over
#####################
[5635, 3810, 1114, 5042, 1481]
[ 1 , 2 , 3 , 4 , 5 ]
please select the 3rd largest number in this row (1-5):
4
Your guess is wrong
Time over
#####################
[6111, 1430, 7999, 3352, 2742]
[ 1 , 2 , 3 , 4 , 5 ]
please select the 3rd largest number in this row (1-5):
23
Traceback (most recent call last):
File "memory_game.py", line 24, in <module>
if solution == list[selection - 1]:
IndexError: list index out of range
Time over
#####################
Can anybody help me with these things:
1. 'Time over' should only be written if the player needs more than 5 sec for the answer. If the player solves it in time the next challenge should appear silently.
2. If the player does not write any guess and presses 'Enter' the program terminates with error message:
Traceback (most recent call last):
File "memory_game.py", line 22, in
selection = int(input_string)
ValueError: invalid literal for int with base 10:''
3. If the player enters any random number the program quits with an 'Index out of range error' - I couldn't find out where to put try: except:
Any help would be appreciated - Thanks!
As for your questions:
You can accomplish that with t.cancel() (stop the timer and do not call the function) instead of t.join() (wait until the thread has finished; this will ALWAYS result in a timeout, of course)
(and 3.) These are basically the same -- put the query message and all input handling into a while loop, and break out of it once you know that the input is valid
...
As an extra, the "time over" message wasn't really doing anything useful (e.g. you could still enter a valid answer after the time over occurred. I "fixed" that in a brute force way by making the program exit if the timeout is hit. Instead of doing that, you can also use a global variable to store whether the timeout was hit or not and handle that in your input accordingly (make sure to make it threadsafe using e.g. a mutex).
In general, it might be easier to turn around the structure of the program -- let the main thread handle the timeout and verification of the input, let the thread only handle the input (this way, it's easy to kill the thread to stop the input from being handled).
Of course, using the select module, one could implement this even nicer without threads (have one pipe that gets written to by a thread/timer, and the standard input, then select both for reading and it will block until either user input or the timeout occurs).
And maybe someone will post a nice asyncio-based solution? ;)
Here's the modified solution (modifying only as little as possible to get it to work, one could refactor other parts to make it nicer in general):
import random
import threading
import os
def timeout():
print("Time over\n#####################\n")
# You can't use sys.exit() here, as this code is running in a thread
# See also: https://stackoverflow.com/a/905224/1047040
os._exit(0)
while True:
list = []
for i in range(5):
list.append(random.randint(1000, 10000))
t = threading.Timer(5, timeout)
t.start()
print(list)
print('[ 1 , 2 , 3 , 4 , 5 ]')
solution = sorted(list)[2]
while True:
try:
print('please select the 3rd largest number in this row (1-5):')
input_string = input()
selection = int(input_string)
chosen = list[selection - 1]
# If we arrive here, the input was valid, break out of the loop
break
except Exception as e:
# Tell the user that the input is wrong; feel free to remove "e"
# from the print output
print('Invalid input:', e)
if solution == chosen:
print("Your guess is correct\n")
else:
print("Your guess is wrong\n")
# Make sure to cancel the thread, otherwise guessing correct or wrong
# will block the CLI interface and still write "time out" at the end
t.cancel()
Here I created a module.
class Employee:
def __init__(self):
self.name = input("Enter your name: ")
self.account_number = int(input("Enter your account number: "))
def withdraw(self): # it receives values from for
if withdraw1 > current_balance:
print ("You have entered a wrong number: ")
else:
print ("The current balance is: ", current_balance - withdraw1)
import TASK2 # I am importing the module I created
c = TASK2.Employee()
def for(self):
c.withdraw1 = int(input("enter number: "))
c.current_balance = int(input("Enter the current balance: "))
d = method(c.withdraw) # here I am trying to pass the values to withdraw
print (d)
The problem I get is that although it asks for the values instead of giving me an answer it gives me None.
Here's my take on your code.
# TASK2.py
class Employee:
def __init__(self):
self.name = input("Enter your name: ")
self.account_number = int(input("Enter your account number: "))
# make sure you initialise your member variables!
self.withdraw_val = 0 # withdraw1 is ambiguous, so I use withdraw_val instead
self.current_balance = 0
# receives values from for ### no it doesn't, right now, it GIVES values TO your "for" function
def withdraw(self):
if self.withdraw_val > self.current_balance: # remember to use "self." to
# access members within the class
print ("You have entered a wrong number: ")
else:
# again, remember "self."
print ("The current balance is: ", self.current_balance - self.withdraw_val)
# TASK2sub.py
import TASK2
c = TASK2.Employee()
def for_employee(employee): # (1) don't use "self" outside a class
# it's contextually unconventional
# (2) "for" is a keyword in Python, don't use it for naming
# variables/functions, it'll mess things up
employee.withdraw_val = int(input("Enter value to withdraw: "))
employee.current_balance = int(input("Enter the current balance: "))
return employee.withdraw_val # not entirely sure what you want to return
# but you should definitely return something
# if you're going to assign it to some variable
d = for_employee(c.withdraw()) # "for_employee" function needs a return statement
# ".withdraw()" method should also require a return statement
print(d)
Note: I'll be referring to your original for function as for_employee from now on. Also note that I'm still hazy about what you're trying to accomplish and that there is most probably a more suitable name for it.
Since your original for_employee function didn't return anything, it returns None by default. (This explains the output you saw.)
I think you're misunderstanding how functions work in general. For example,
d = for_employee(c.withdraw())
print(d)
Your comment for the .withdraw() method is inaccurate.
"it receives values from for"
More accurately, c.withdraw() will first be computed, then whatever it returns is passed into the for_employee function as a parameter. Instead of "receiving values from", the withdraw method "gives values to" the for_employee function.
Something more reasonable would be
c.withdraw() # on a line by itself, since it doesn't return anything
d = for_employee(c) # pass the entire object, since you'll be using self.withdraw_val and whatnot
print(d)
Another issue is with conventional naming. This is what I get from the IDLE (with Python 3.7) when defining a function named for
>>> def for(a): return a
SyntaxError: invalid syntax
Again, for is a keyword in Python, don't use it for naming your variables, functions, or classes.
With self, it's less severe (but I could see that it's confusing you). self is more of a convention used in class methods. But for_employee isn't a class method. So conventionally speaking, the parameter shouldn't be named self.
(I find the code spaghetti-ish, it might benefit if you refactor the code by moving the for_employee method into the class itself. Then it would completely make sense to use self.)
Okay, trying to make a simple game of Guessing Numbers but I can't find the mistake in this code. Still pretty new to python so probably the reason why but I can't figure out what is wrong with it.
import random
from time import sleep
def start():
print("Welcome To The Guessing Game \n Try to guess the number I'm thinking of \n Good luck!")
selectRandomNumber()
guessCheck(number, numberInput=1)
def restart():
print("Creating new number ...")
sleep(1)
print("OK")
selectRandomNumber()
guessCheck(number,numberInput=1)
def selectRandomNumber():
number = random.randint(0,1000)
tries = 0
return
def tryAgain():
while True:
try:
again = int(input("Do you want to play again? y/n:"))
except ValueError:
print("Couldn't understand what you tried to say")
continue
if again == "y" or "yes":
print("Awesome! Lets go")
restart()
elif again == 'n' or "no":
print("Goodbye!")
break
else:
print("Not a valid option")
continue
def guessCheck(number,numberInput=1):
while True:
try:
numberInput = int(input("What number do you think it is?: "))
except ValueError:
print("Couldn't understand that. Try again")
continue
if numberInput > number:
print("Too high")
tries += 1
continue
elif numberInput < number:
print("Too low")
tries += 1
continue
elif numberInput == number:
print("Congrats! You got my number")
tryAgain()
number = selectRandomNumber()
print(number)
start()
Every time I try to run the program I keep getting the same mistake.
It tells me:
Traceback (most recent call last):
File "python", line 60, in <module>
start()
File "python", line 8, in start
guessCheck(number, numberInput)
NameError: name 'number' is not defined
Don't quite understand what that means.
Some help would be appreciated. Thanks!
* UPDATE *
Was able to fix the part about defining the variable but now new problem happened where when I try to run
Same code as before but added
guessCheck(number,numberInput=1)
and also added the variable number at the end
number = selectRandomNumber()
print(number)
start()
when I run it I get this
None # this is from `print(number)` so instead of getting a number here I'm getting `None`
Welcome To The Guessing Game
Try to guess the number I'm thinking of
Good luck!
What number do you think it is?:
The Traceback is telling you this:
We got to start().
start() called guessCheck().
We tried to pass two pieces of information to guessCheck(): the variable names number and numberInput.
We don't have those variables defined yet! numberInput doesn't get defined until once we've already started guessCheck(), and number isn't actually defined anywhere.
As Manoj pointed out in the comments, you probably want number to hold the output of selectRandomNumber(). So, instead of just calling selectRandomNumber() in start(), try number = selectRandomNumber() instead.
You can add a print(number) on the line right after that to make sure number has a value assigned to it.
Now number has a value, going into your call to guessCheck(). That still leaves numberInput undefined though. You can set a default value for function arguments like this:
guessCheck(number, numberInput=1)
That way, when guessCheck is called but numberInput hasn't been defined yet, it will automatically give it the value 1 until you set it explicitly.
You may encounter other issues with your code the way it is. My advice would be to start really simply - build up your game from each individual piece, and only put the pieces together when you're sure you have each one working. That may seem slower, but trying to go too fast will cause misunderstandings like this one.
I am trying to test each input then return that the number is cleared then do the math. For Example is a user inputs N instead of a number I want it to output that its not a number whereas if the user inputs 1 then I want it to move to the next function asking for a power then do the same thing and if that passes then goes to the final section which output the answer to the problem.
The program passes both the errors for the non number areas yet when it get to very last function it is telling me base nor power are defined.
Code is written in some Python2 and some Python3. All works fine though. I use python3 mostly.
[Test Picture/Error Msg][1]
# Below we are creating the recursive statement to do the math for us. We are calling Base and Power
# from the main function where the user Inputs the numbers.
def pow(base, power):
if power == 0:
return 1
if power == 1:
return base
else :
return base * pow(base, power - 1)
def determineBase():
while True:
try:
base = int(input ('Please Enter A Base: '))
except ValueError:
print("Please use whole numbers only. Not text nor decimals.")
continue
else:
return base
def determinePower():
while True:
try:
power = int(input ('Please Enter A Power: '))
except ValueError:
print("Please use whole numbers only. Not text nor decimals.")
continue
else:
return power
def main():
determineBase()
determinePower()
pow(base,power)
print("The answer to",base,"to the power of", power,"is", pow(base,power),".")
main()
def main():
determineBase()
determinePower()
pow(base,power)
Here, neither base nor power are defined. What you meant instead was to store the result from those function calls and pass those then:
def main():
base = determineBase()
power = determinePower()
pow(base, power)
The issue isn't inside the recursive function, it's inside your main function.
The problem is arising due to the fact that you are passing base as an argument to the pow() function without defining the variable base first (the same would subsequently be true for power).
In other words you need something along the lines of:
def main():
base = determineBase()
power = determinePower()
pow(base,power) #this line could probably be removed
print("The answer to",base,"to the power of", power,"is", pow(base,power),".")
As currently, you're not storing the values of these two functions.