Issue with variable defining - python

When I execute the following code, I get the error "player_normal_defense is not defined". I get what the issue is but if I had to define the variable inside the Defense function, it would be totally pointless since the variable stores the initial defense value for further usage. How should I solve this?
import random
import sys
import os
import time
from Entity import *
class Battle():
def Attack(self, attacker, defender):
damage = attacker.atk - defender.dif
defender.hp -= damage
def Defense(self, owner, defending, entity_id):
defense_boost = 10
if defending:
owner.dif += defense_boost
elif not defending:
if entity_id == 1:
owner.dif = player_normal_defense
elif entity_id == 2:
owner.dif = enemy_normal_defense
def Turn_Generator(self, pl, en):
turns_list = []
speed_product = pl.speed / en.speed
first_speed_product = speed_product
if speed_product >= 1:
turns_list.append("P")
elif speed_product < 1:
turns_list.append("E")
while len(turns_list) < 100:
if speed_product >= 2:
turns_list.append("P")
turns_list.append("P")
speed_product = 0.6
elif speed_product < 2 and speed_product >= 1:
turns_list.append("P")
if first_speed_product <= 0.5:
speed_product = first_speed_product
else:
speed_product = 0.6
elif speed_product <= 0.5:
turns_list.append("E")
turns_list.append("E")
speed_product = 1
elif speed_product > 0.5 and speed_product < 1:
turns_list.append("E")
if first_speed_product >= 2:
speed_product = first_speed_product
else:
speed_product = 1
return turns_list
def Combat(self, player, enemy):
turn_counter = 1
player_normal_defense = player.dif
enemy_normal_defense = enemy.dif
fighting = True
while fighting:
print(f"Turn {turn_counter}")
turns = self.Turn_Generator(player, enemy)
for current_turn in turns:
print(f"""
======================
YOUR HPs: ENEMY HPs:
{player.hp} {enemy.hp}
======================""")
print(f"""
================
Current turn: {current_turn}
================
===========
Next turns:
{turns[1]}
{turns[2]}
{turns[3]}
{turns[4]}
===========
""")
if current_turn == "P":
choice = input("1. Attack\n2. Defend\n")
if choice == "1":
self.Attack(player, enemy)
self.Defense(player, False, 1)
elif choice == "2":
self.Defense(player, True, 1)
else:
print("Lost your chance!")
elif current_turn == "E":
enemy_choice = random.randint(1, 2)
if enemy_choice == 2:
print("He attacks you!")
self.Attack(enemy, player)
self.Defense(enemy, False, 2)
else:
print("He defends himself.")
self.Defense(enemy, True, 2)
time.sleep(3)
os.system("clear")
turns.pop(0)
if player.hp <= 0:
print("You died!")
sys.exit(0)
elif enemy.hp <= 0:
print("YOU WON!")
fighting = False
break
turn_counter += 1

When entity is defending, instead of running a Defence function to add a bonus to entitys Defence score only if it is true, I would just not run the Defence function when attacking. When entity is defending then you can run the Defense (Bonus) function as;
def Defending():
defence_boost = 10
in the decision check;
if choice == "2":
self.dif += Defending()
One issue I believe you will have with the code is that you are raising the entitys .dif stat with each occurrence of defending. This means that when this has cycled multiple times the base dif may be too high for any attackers damage to do anything to the opponents health.

Related

List index out of range in class

All code
import random
import time
class Enemy():
def __init__(self):
self.health = 100
self.power = random.randint(10,20)
def hit(self, player):
player.health -= self.power
class player():
def __init__(self):
self.health = 300
self.power = 50
def hit(self, Enemy):
Enemy.health -= self.power
player1 = player()
enemies = []
for i in range(5): # create 5 enemy
enemies.append(Enemy())
print("Play - Help - Quit")
action1 = input("Type 'hit' for enemies\n>>>> ")
while action1 != 'q':
print("---------------")
for i in range(len(enemies)):
print("#{}.enemy heatlh-->{}".format(i, enemies[i].health))
print("----------------")
random_enemy = random.randint(1, 5)
action = input(">>>> ")
if action == 'hit':
which = int(input("Which enemy? there are {} enemies\n>>>>".format(len(enemies))))
if enemies[which].health == 0:
enemies[which].health = 0
print("\nThis is a death enemy")
else:
player1.hit(enemies[which])
damage_enemy = random.randint(1,5)
if enemies[random_enemy].health == 0:
continue
else:
if damage_enemy == 1 or damage_enemy == 3 or damage_enemy == 4:
if enemies[which].health == 0 or enemies[which].health <= 0:
enemies[which].health = 0
print("{}. enemy death HP: {} ".format(which, enemies[which].health))
else:
enemies[random_enemy].hit(player1)
print("{}. enemy hit you {} damage, your HP: {} ".format(random_enemy,enemies[random_enemy].power,player1.health))
elif enemies[which].health != 0 or enemies[which].health >= 0:
print("{}. enemy HP: {} ".format(which, enemies[which].health))
elif action == 'q':
break
I get this error at random time, my list size is 5, enemies die and their healths are 0. They stay there, but for some reason sometimes I get this error.
#0.enemy heatlh-->100
#1.enemy heatlh-->100
#2.enemy heatlh-->0
#3.enemy heatlh-->0
#4.enemy heatlh-->100
if enemies[random_enemy].health == 0:
continue
The random.randint(1, 5) can return 5. Your list has 5 elements, but the indices are from 0 to 4.
P.S. Also, the minimum value that you get is 1. Not 0.

'NameError: name is not defined' when trying to modify a global variable

I'm having an issue when trying to modify a variable in my script with a function.
def damage(x):
""" This function will determine the amount of damage you will take """
""" hit_c is the chance the enemy has to hit you """
from random import randint
global User_HP
global Enemy_HP
hit_c = randint(1,5)
User_damage = randint(1,4)
if hit_c >= 2:
Enemy_HP -= User_damage
lcd_print(textscroll(f"You dealt {User_damage} damage!"))
lcd_clear()
lcd_print(textscroll(f"The enemy has {Enemy_HP} HP")
sleep(1)
elif hit_c == 1:
lcd_print("You missed!")
if Enemy_HP <= 0:
pass
else:
hit_c = randint(1,5)
Enemy_damage = randint(1,3)
if hit_c >= 2:
User_HP -= Enemy_damage
lcd_print(textscroll(f"You took {Enemy_damage} damage!"))
lcd_clear()
lcd_print(User_HP)
elif hit_c == 1:
lcd_print(textscroll("The enemy missed!"))
The function won't read the global variable Enemy_HP when I try to modify it in this line.
Enemy_HP -= User_damage
note, I have defined Enemy_HP = 10 at the start of the script.
Help is much appreciated!
Error -
File "D:\Desktop\Python Scripts\Lab Project\Lab_Project_Functions.py", line 41, in damage
Enemy_HP -= User_damage
NameError: name 'Enemy_HP' is not defined`
EDIT:
Here is the full code sorry for not including this earlier, I'm also importing several functions
from time import sleep
from random import randint
from operator import itemgetter
from engi1020.arduino import *
User_HP = 10
Enemy_HP = 10
wait_1 = True
def loading(wait_time):
if wait_1 == True:
sleep(1)
lcd_clear()
lcd_print('.')
sleep(1)
lcd_clear()
lcd_print('..')
sleep(1)
lcd_clear()
lcd_print('...')
sleep(1)
lcd_clear()
lcd_print('.')
sleep(1)
lcd_clear()
lcd_print('..')
sleep(1)
lcd_clear()
lcd_print('...')
sleep(1)
lcd_clear()
inventory = []
from Lab_Project_Functions import *
#Get some basic gameplay information
lcd_print("starting the game")
lcd_clear()
loading(wait_1)
lcd_print(textscroll("Hello!, What speed would you like the dialogue to play at? ('slow, normal, fast')"))
Dia_Spd = input()
if Dia_Spd == "slow":
DiaSpd = 4
elif Dia_Spd == "normal":
DiaSpd = 3
elif Dia_Spd == "fast":
DiaSpd = 2
elif Dia_Spd == "test":
DiaSpd = 0
lcd_clear()
lcd_print()
loading(wait_1)
'''
name = input("What is your name?")
class_ = "Knight"
sleep(1)
class_ = input("Which class is befitting you young adventurer?"
" A noble 'Knight'?"
" A Studious 'Wizard'?"
" Or a Mystifying 'Warlock'?")
'''
loading(wait_1)
#lcd_print(f"What ho {class_} {name}, welcome to the game!!")
lcd_print(textscroll("What ho brave knight, welcome to the game!!"))
sleep(DiaSpd)
lcd_clear()
lcd_print(textscroll("Let's start with a some basics"))
sleep(DiaSpd)
lcd_clear()
#Start by creating a basic combat system.
lcd_print(textscroll("An enemy approaches you! Learn to fight!"))
sleep(DiaSpd)
lcd_clear()
#Create more combat elements.
while User_HP > 0:
lcd_print(textscroll("Pick a fighting option."))
lcd_print("FIGHT--ITEM--DEF")
fight_option = input()
if fight_option == 'FIGHT' or 'fight' or 'Fight':
damage(1)
elif fight_option == 'ITEM' or 'item' or 'Item':
item_pickup(1)
else:
defend(1)
if Enemy_HP <= 0:
lcd_print(textscroll("THE ENEMY WAS SLAIN!"))
break
sleep(DiaSpd)
lcd_print(textscroll("Good job you're learning the basics!"))
sleep(DiaSpd)
lcd_print(textscroll("To reward you for your efforts, here is an item that the enemy dropped!"))
sleep(DiaSpd)
item_pickup(1)
#remember to redefine enemy hp before next fight
lcd_print(textscroll("Hi ho yee noble knight, welcome to your humble abode. You can perform all sorts of actions here."))
sleep(DiaSpd)
lcd_clear()
lcd_print(textscroll("What would you like to do?"))
sleep(DiaSpd)
lcd_clear()
lcd_print(textscroll("Look through inventory----Rest (Heal)----Go adventuring"))
home_option = input() #change this to accept input from button & joystick
while True:
if home_option == 1:
pass
if home_option == 2:
pass
if home_option == 3:
pass
the function imports are from here
from engi1020.arduino import *
#Looting // Item Pickup Function def item_pickup(enemy_num):
""" This Function will determine the items the user picks up """
'''
enemy_num is the variable deciding which enemy you are fighting
'''
from random import randint
rand_item = randint(1,4)
global inventory
if enemy_num == 1:
if rand_item <= 3:
inventory.append('IRON_SWORD')
print(textscroll("You picked up the IRON SWORD!"))
elif rand_item == 4:
inventory.append('STEELY_VENGANCE')
lcd_print(textscroll("You found a rare item! 'STEELY VENGANCE' was added to your inventory!"))
else:
'no item found'
if enemy_num == 2:
pass
#Combat Function def damage(x):
""" This function will determine the amount of damage you will take """
""" hit_c is the chance the enemy has to hit you """
from random import randint
global User_HP
global Enemy_HP
hit_c = randint(1,5)
User_damage = randint(1,4)
if hit_c >= 2:
Enemy_HP -= User_damage
lcd_print(textscroll(f"You dealt {User_damage} damage!"))
lcd_clear()
lcd_print(textscroll(f"The enemy has {Enemy_HP} HP")
sleep(1)
elif hit_c == 1:
lcd_print("You missed!")
if Enemy_HP <= 0:
pass
else:
hit_c = randint(1,5)
Enemy_damage = randint(1,3)
if hit_c >= 2:
User_HP -= Enemy_damage
lcd_print(textscroll(f"You took {Enemy_damage} damage!"))
lcd_clear()
lcd_print(User_HP)
elif hit_c == 1:
lcd_print(textscroll("The enemy missed!"))
#Item Select Function def item_select(item_number):
from operator import itemgetter
while True:
lcd_print(textscroll("What item would you like to use?"))
lcd_clear()
sleep(1)
lcd_print(textscroll("note you need to select items numerically, i.e. 0, 1, 2, 3,...,etc. "))
lcd_clear()
sleep(1)
lcd_print(textscroll(inventory))
item_choice = int(input())
lcd_clear()
lcd_print("Which item?:")
num_items = len(inventory)
if item_choice < num_items:
item = itemgetter(item_choice)(inventory)
if item == potion:
global User_HP
User_HP += 5
lcd_print(User_HP)
break
else:
lcd_print(textscroll("ERROR! ITEM CHOICE IS AN INVALID OPTION!"))
#Defend Function def defend(User):
Enemy_damage = randint(1,3)
lcd_print(textscroll(f"The user blocked {Enemy_damage} damage"))
#Text Scrolling Function def textscroll(text):
from time import sleep
i = 0
j = 15
while True:
lcd_print(text[i:j])
i += 1
j += 1
sleep(0.2)
lcd_clear()
if j >= len(text) + 15:
break
The error you have is because you didn't assign a value to it (even tho you said):
exception NameError: Raised when a local or global name is not found. This applies only to unqualified names. The associated value is an error message that includes the name that could not be found.
Source: https://docs.python.org/3/library/exceptions.html#bltin-exceptions
The problem in your code is that you are trying to access variables from one file without importing them.
Global variables only exist inside the file they are defined.
Just import them like they were functions:
import Enemy_HP

Calling a class function outside of the function it was declared

I'm trying to call a class function player.Decide() in another function where it wasn't declared. Im getting the error 'player is not defined. How would I go about fixing this?
def BattleLogic():
global enemy, enemy_race, name, level, strength, dexterity, cunning, enemy_speed, player_speed, type_speed
global move, turn, prefix
if enemy in ['deer']:
enemy_race = 'animal'
if enemy_race == 'animal':
chance = random.randint(1,1000)
if chance <= 10:
prefix = 'crippled'
elif chance > 10 and chance <= 50:
prefix = 'old'
elif chance >50 and chance <= 250:
prefix = 'young'
elif chance > 250 and chance <= 750:
prefix = None
elif chance > 750 and chance <= 950:
prefix = 'strong'
elif chance > 950 and chance <= 990:
prefix = 'alpha'
elif chance > 990 and chance <= 999:
prefix = 'possessed'
elif chance == 1000:
prefix = '*CONVERTED*'
else:
prefix = 'error'
opponent = Enemy(str(prefix),str(enemy),str(enemy_race))
player = Player(str(name),level,strength,dexterity,cunning)
player.Initiative()
opponent.Initiative()
if enemy_speed > player_speed:
move = 0
elif player_speed > enemy_speed:
move = 1
else:
move = random.randint(0,1)
turn = 0
Battle()
def Battle():
global turn, move, prefix, enemy, type_speed, enemy_title
if turn == 0:
print('\n\n')
if prefix == None:
enemy_title = enemy.capitalize()
else:
enemy_title = prefix.capitalize()+' '+enemy.capitalize()
SlowPrint('A '+enemy_title+' gets into position for battle',type_speed,0.5)
if move == 1:
SlowPrint(enemy_title+' makes the first move',type_speed,0.25)
else:
SlowPrint('You make the first move',type_speed,0.25)
if move == 0:
turn += 1
move = 1
player.Decide()
else:
turn += 1
move = 0
opponent.Decide()
Just pass a player object into the function. The you are free to use player.Decide().
The major problems with your coding, which is my personal opinion, is that you do not have the habit of passing something into the function, which as a result forces you to declare too many global variables.
A simple example (in your case, you want the object to be a player)
def Battle(obj):
return obj.Decide()

Python Simple American Football Simulator Not Running

Simple football simulation for my class project. I simplified a lot of the rules and aspects of the game, so everything isn't very accurate compared to an actual football game. However, When I try running my function, only the line of code which prints the name of the QB throwing to the receiver prints. For example when I run it only, "Jared Goff throws to Brandin Cooks for 33 yards!" shows up in the display. How can I get the whole function to run/print? Not sure where I went wrong.
import random
rams_qb = ["Jared Goff"]
patriots_qb = ["Tom Brady"]
rams_receivers = ["Cooper Kupp", "Brandin Cooks"]
patriots_receivers = ["Julian Edelman", "Josh Gordon"]
rams_score = 0
patriots_score = 0
quarter_time = 900
def remaining_time():
global quarter_time
global rams_score
global patriots_score
if quarter_time > 0:
if random.randint(0,100) < 50:
return rams_possesion()
else:
return patriots_possesion()
elif quarter_time == 0:
if rams_score > patriots_score:
print ("Rams Win!")
else:
print ("Patriots Win!")
def rams_possesion():
global quarter_time
global rams_score
rams_ball_position = 50
rams_downs = 1
if rams_ball_position == rams_ball_position + 10:
rams_downs = 1
else:
rams_downs += 1
if rams_ball_position == 100:
rams_score == rams_score + 6
print ("RAMS TOUCHDOWN!")
return rams_fieldgoal
if rams_downs <= 4:
rams_yardage_gained = random.randint(0,50)
print ((random.choice(rams_qb)),("throws to"),
(random.choice(rams_receivers)),("for"),(str(rams_yardage_gained)),
("yards!"))
rams_ball_position == rams_ball_position + rams_yardage_gained
quarter_time -= random.randint(0,30)
if rams_downs >= 5:
return patriots_possesion
def rams_fieldgoal():
global rams_score
if random.randint(0,100) < 83:
rams_score == rams_score + 1
print ("RAMS SCORE FIELDGOAL!")
else:
print ("RAMS MISS FIELDGOAL")
return patriots_possesion
def patriots_possesion():
global patriots_score
patriots_ball_position = 50
patriots_downs = 1
if patriots_ball_position == patriots_ball_position + 10:
patriots_downs = 1
else:
patriots_downs += 1
if patriots_ball_position == 100:
patriots_score == patriots_score + 6
print ("PATRIOTS TOUCHDOWN!")
return patriots_fieldgoal
if patriots_downs <= 4:
patriots_yardage_gained = random.randint(0,50)
print ((random.choice(patriots_qb)),("throws to"),
(random.choice(patriots_receivers)),("for"),(str(patriots_yardage_gained)),
("yards!"))
patriots_ball_position == patriots_ball_position +
patriots_yardage_gained
if patriots_downs >= 5:
return rams_possesion()
def patriots_fieldgoal():
global patriots_score
if random.randint(0,100) < 87:
patriots_score == patriots_score + 1
print ("PATRIOTS SCORE FIELDGOAL!")
else:
print ("PATRIOTS MISS FIELDGOAL")
return rams_possesion()
remaining_time()
My best guess here is that your comparisons are not taking into account the fact that the values can go over the target. For example, when checking yardage, you're checking for equality to 100, but you aren't guaranteeing that the value won't go over 100. You have a similar bug with checking if the quarter_time == 0 when it should be <= 0 to make sure it triggers.
I can't tell you if changing these comparisons will fix your program, but try these changes and comment how the behavior changes.

Python Class Setters Not Changing Variables

The closest thread I could find to my problem was this: Python setter does not change variable
It didn't really help, the volume and the channels are not changing at all. The first fucntion which is to "watch TV" works perfectly fine.
class TV(object):
def __init__(self, channel, volume):
self.__channel = channel
self.__volume = volume
def __str__(self):
out = ""
out += "You're on channel #" + str(self.__channel) + ", " + self.channelNetwork()
out += "\nVolume is currently at: " + str(self.__volume) + "/20"
return out
# a method that determines the name for each channel from 1-10
def channelNetwork(self):
c = self.__channel
if c == 1:
return "CBS"
elif c==2:
return "NBC"
elif c==3:
return "ABC"
elif c==4:
return "Fox"
elif c==5:
return "ESPN"
elif c==6:
return "PBS"
elif c==7:
return "CNN"
elif c==8:
return "Comedy Central"
elif c==9:
return "Cartoon Network"
elif c==10:
return "Nicklodeon"
# a volume slider that has a range from 0-20
def volumeSlider(self, newVolume):
v = self.__volume
if newVolume == "+":
v += 1
else:
v -= 1
if v < 0:
v = 0
if v > 20:
v = 20
def channelChanger(self, newChannel):
c = self.__channel
if newChannel == "+":
c += 1
else:
c -= 1
if c < 0:
c = 0
if c > 10:
c = 10
def main():
import random
randomChannel = random.randint(1,10)
randomVolume = random.randrange(21)
televsion = TV(randomChannel, randomVolume)
choice = None
while choice != "0":
print \
("""
TV Simulator
0 - Turn off TV
1 - Watch TV
2 - Change channel
3 - Change volume
""")
choice = input("Choice: ")
print()
# exit
if choice == "0":
print("Have a good day! :)")
elif choice == "1":
print("You relax on your couch and watch some TV")
print(televsion)
elif choice == "2":
newChannel = None
while newChannel not in ('+', '-'):
newChannel = input("\nPress '+' to go up a channel and press '-' to go down a channel: ")
televsion.channelChanger(newChannel)
elif choice == "3":
newVolume = None
while newVolume not in ('+', '-'):
newVolume = input("\nPress '+' to increase volume and press '-' to decrease volume: ")
televsion.volumeSlider(newVolume)
else:
print("\nSorry, but", choice, "isn't a valid choice.")
main()
input("\n\nPress enter to exit.")
The problem is, that when you do:
v = self.__volume
In:
def volumeSlider(self, newVolume):
v = self.__volume
if newVolume == "+":
v += 1
else:
v -= 1
if v < 0:
v = 0
if v > 20:
v = 20
Assigning to v won't affect self.__volume. You need to use self.__volume = 20 or whatever.
As an aside, don't use double-underscore name-mangling unless you actually need it. E.g. self.volume is fine.

Categories