This is the code.
#When I try to make the variable ‘enemy’ save globally, it says ‘Variable referenced before assignment.’, or something along those lines. How do I fix this?
#If you are going to suggest to make it all one function, I tried and it didn't work out. I am doing this so I can keep repeating the turn function until the player enters a vaild command.
#Player and enemy stat blocks. Order of stat blocks is: Health, Weapon, Weapon damage, Armor, and Armor type.
PC = [50, 'shortsword', 20, 'chain mail', 10]
goblin = [30, 'dagger', 15, 'leather', 5]
# Function for a single turn.
def turn(enemy):
turn1 = input('Your turn. What would you like to do? ').lower()
if turn1 != 'attack':
print('Invalid command.')
turn(enemy)
elif turn == 'attack':
global enemy
enemy[0] = enemy[0] - PC[2]
# Function for the entirety of combat.
def combat(enemy):
while enemy[0] > 0:
turn1 = input('Your turn. What would you like to do?')
turn(enemy)
combat(goblin)
Related
im a beginner programmer and im trying to make a simple blackjack game just for exercise in Python 3.10 using PyCharm CE but I wasn't able to solve a problem. The problem is my player_draw_card() function is not drawing a card. I wanted to put the whole code in case I miss something but I also highlighted the important parts (imo) with #'s.
import random
cards = [11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10] #extra 10's stands for J,Q,K and 11 is Ace
player_score = 0
computer_score = 0
player_cards = []
computer_cards = []
#############################################################
def player_draw_card():
index = random.randint(0, 12) # Selecting a random index from cards for player
player_cards.append(cards[index]) # Adding the selected 1 card to player_cards
#############################################################
def computer_draw_card():
index = random.randint(0, 12) # Selecting a random index from cards for computer
computer_cards.append(cards[index]) # Adding the selected 1 card to computer_cards
def calculate_player_score(): # Calculate player's score everytime it draws a card to prevent confusion when you have multiple Aces.
player_score = sum(player_cards)
if player_score > 21 and (11 in player_cards):
index_of_11 = player_cards.index(11)
player_cards[index_of_11] = 1
player_score = sum(player_cards)
def calculate_computer_score(): # Calculate computer's score everytime it draws a card to prevent confusion when you have multiple Aces.
computer_score = sum(computer_cards)
if computer_score > 21 and (11 in computer_cards):
index_of_11 = computer_cards.index(11)
computer_cards[index_of_11] = 1
computer_score = sum(computer_cards)
#####################################################################
def blackjack():
player_lost = False
player_score = 0
computer_score = 0
player_cards = []
computer_cards = []
player_draw_card() #################
player_draw_card() #################
######################################################################
#**Problem is not beyond here most likely, cause when I run it step by step**
#**player_draw_card() function didnt add anything.**
##########################################################################
print(f"Your cards: {player_cards}")
calculate_player_score()
#####################################
computer_draw_card()
print(f"Computer's first card: {computer_cards}")
#####################################
#**My computer_draw_card() is also not working btw but they build in same way so**
#**if we can fix the player_draw_card() function, we can fix the computer_draw_card() aswell**
#######################################
calculate_computer_score()
player_wants_more = True
while player_wants_more:
y_or_n = input("Type 'y' to get another card, type 'n' to pass:").lower()
if y_or_n == "n":
player_wants_more = False
if y_or_n == "y":
player_draw_card()
calculate_player_score()
if player_score > 21:
player_lost = True
player_wants_more = False
if player_lost == True:
print("You lost!\n")
restart = input("If you want to play again type 'y' if you want to finish the game type 'n'")
if restart == "y":
blackjack()
while computer_score < 17:
computer_draw_card()
calculate_computer_score()
if computer_score < player_score:
print("You win!\n")
elif player_score < computer_score:
print("You lose")
else:
print("It's a draw!")
y_or_n = input("Type 'y' if you want to play another game and 'n' if you dont.").lower()
if y_or_n == 'y':
blackjack()
else:
print("Bye")
blackjack() ############################### This is the only function that is called
########################################### Except the ones that are called in def's
I tried looking it step by step in pythontutor.com and it seems like """player_cards.append(cards[index]) # Adding the selected 1 card to player_cards""" line of code, doesn't add anything to player_cards
What seems strange to me though is, I tried a simpler version for drawing card with following.
cards = [11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10]
player_cards = []
import random
def player_draw_card():
index = random.randint(0, 12) # Selecting a random index from cards for player
player_cards.append(cards[index])
player_draw_card()
print(player_cards)
And it works, it adds a random number to the player_cards. What is the problem someone please help me.
Thanks in advance
You are defining the player_cards list twice. Once it is defined on line 7, and then again inside the blackjack() method on line 41.
What happens is that you are creating two differently scoped variables player_cards. When you're calling the player_draw_card() from the blackjack() method, the player_draw_card() doesn't know about the player_cards in your blackjack() method. It looks up the name player_cards in its own scope, then in its parent scope, where it is defined.
You can solve this in two ways:
Remove the player_cards declaration inside your blackjack() method. This will make all the methods use the global list.
Add a parameter to player_draw_card(player_cards: list[int]) method and pass the list from your blackjack() method. In this case you won't need the global list anymore. IMO this is over-complication for this code example.
Note: You have the same issue with the compiter_cards list.
I have a simple Python game where two players deal some damage to each other in turns until one player has 0 or less than 0 HP. I don't like how much I've repeated myself but I'm unsure how to fix this. I thought about using a list of players but then I'm unsure how to index the next player when it's their turn, without running into the list index out of range error.
If this kind of question is not allowed please let me know and I will remove it.
Below is my game logic to determine when a player has won. I may not have pasted in the exact code I have but it runs how it's expected locally.
def check_win_state(current_player):
if current_player.get_player_health() > 0:
return True
elif current_player.get_player_health() <= 0:
return False
def main():
player1 = player.Player("Me")
player2 = player.Player("You")
while True:
if check_win_state(player1):
take_turn(player1, player2)
else:
print(f"\n{player2.get_player_name()} ({player2.get_player_health()} HP) wins! {player1.get_player_name()} has {player1.get_player_health()} HP left.\n")
break
if check_win_state(player2):
take_turn(player2, player1)
else:
print(f"\n{player1.get_player_name()} ({player1.get_player_health()} HP) wins! {player2.get_player_name()} has {player2.get_player_health()} HP left.\n")
break
The easiest approach to reduce code duplication in situations like these is to use a secondary variable to hold the primary variable. Here, instead of having different code for player1 and player2, we instead have just one code, and use the variables current_player and opposing_player to hold player1 and player2, and swap with every iteration.
def main():
player1 = player.Player("Me")
player2 = player.Player("You")
current_player = player1
opposing_player = player2
while True:
if check_win_state(current_player):
take_turn(current_player, opposing_player)
else:
print(f"\n{opposing_player.get_player_name()} ({opposing_player.get_player_health()} HP) wins! {current_player.get_player_name()} has {current_player.get_player_health()} HP left.\n")
break
current_player, opposing_player = opposing_player, current_player
If you have more than two players, then a more extensible approach might be to have a list of players, and have an index rotate through the list with each iteration to specify which player is the 'current' one.
also, you can simplify check_win_state():
def check_win_state(current_player):
return current_player.get_player_health() > 0
because the check a > b returns a boolean anyway.
You can make the first function short using this logic:-
def check_win_state(current_player):
return current_player.get_player_health() > 0:
And now you can create another function to do the work of inside while loop
def work_in_while(pl, another_pl):
if check_win_state(pl):
take_turn(pl, another_pl)
else:
print(f"\n{another_pl.get_player_name()} ({another_pl.get_player_health()} HP) wins! {pl.get_player_name()} has {pl.get_player_health()} HP left.\n")
return "kill"
And use it like:-
while True:
if work_in_while(player1, player2) == "kill":
break
if work_in_while(player2, player1) == "kill":
break
There is module files as well but they work perfectly, the main problem is when you enter a module and it just printing out There is 'none' in here for every module. Additionally, if I wanted to change the fuel gain from 50 to randomly chose between 20,30,40 or 50.
The rest of the code works well but when the npc in a room is outputted it should say there is a 'workers' in here instead of just none for each module.
#Telium - Game
import random
#Global Variables
num_modules = 17 #Number of modules in the space station
module = 1 #Module of space station we are in
last_module = 0 #Last module we were in
possible_moves = [] #List of possible moves we can make
alive = True #Whether player is alive or not
won = False #Whether player has won
power = 100 #Amount of power the space station has
fuel = 500 #Amount of fuel the player has in flamethrower
locked = 0 #Module that has been locked by the player
queen = 0 #Location of queen alien
vent_shafts = [] #Location of ventilation shaft entrances
info_panels = [] #Location of info panels
workers = [] #Location of worker aliens
#procedure declarations
#This loads the global module
def load_module():
global module, possible_moves
possible_moves = get_modules_from(module)
output_module()
def get_modules_from(module):
moves = []
text_file = open("Charles_Darwin\module" + str(module) + ".txt", "r")
for counter in range(0,4):
move_read = text_file.readline()
move_read = int(move_read.strip())
if move_read != 0:
moves.append(move_read)
text_file.close()
return moves
def output_module():
global module
print()
print("--------------------------------------------------------------
-----------------------")
print()
print("You are in module",module)
print()
npc = spawn_npcs()
print("There is a ", npc ,"here")
def output_moves():
global possible_moves
print()
print("From here you can move to modules: | ",end='')
for move in possible_moves:
print(move,'| ',end='')
print()
def get_action():
global module, last_module, possible_moves, power
valid_action = False
while valid_action == False:
print("What do you want to do next ? (MOVE, SCANNER)")
action = input(">")
if action == "MOVE" or action.lower() == 'move' or action.lower()
== 'm' or action.higher() == 'M':
move = int(input("Enter the module to move to: "))
if move in possible_moves:
valid_action = True
last_module = module
module = move
#power is decreased by 1 for every move
power =- 1
else:
print("The module must be connected to the current
module.")
def spawn_npcs():
global num_modules, queen, vent_shaft, greedy_info_panels, workers
module_set = []
for counter in range(2,num_modules):
module_set.append(counter)
random.shuffle(module_set)
i = 0
queen = module_set[i]
for counter in range(0,3):
i=i+1
vent_shafts.append(module_set[i])
for counter in range(0,2):
i=i+1
info_panels.append(module_set[i])
for counter in range(0,3):
i=i+1
workers.append(module_set[i])
def check_vent_shafts():
global num_modules, module, vent_shafts, fuel
if module in vent_shafts:
print("There is a bank of fuel cells here.")
print("You load one into your flamethrower.")
fuel_gained = 50
print("Fuel was",fuel,"now reading:",fuel+fuel_gained)
fuel = fuel + fuel_gained
print("The doors suddenly lock shut.")
print("What is happening to the station?")
print("Our only escape is to climb into the ventilation shaft.")
print("We have no idea where we are going.")
print("We follow the passages and find ourselves sliding down.")
last_module = module
module = random.randint(1,num_modules)
load_module()
#Main Program starts here
#Menu options
print("ENTER 1 for instructions")
print("ENTER 2 to play")
print("ENTER 3 to quit")
menu = int(input("Please enter a number corresponding to what you want to
do: "))
if menu == 1:
instructions = input("Do you want to read the instructions(Y/N): ")
if instructions == "Y":
print("You, the player are trying to navigate around a space
station named the 'Charles Darwin' which contains many modules")
print("The aim of the game is to find a and trap the queen alien
called 'Telium' who is located somewhere randomly in the station, the
queen will try to escape to connectinhg modules so beware")
print("To win - you have to lock the queen in one of the modules
so she is trapped, you can kill her with a flamethrower, there is also
objects to help on the way so keep a look out")
spawn_npcs()
#Outputs where the queen, shafts, panels and workers are located
print("Queen alien is located in module:",queen)
print("Ventilation shafts are located in modules:",vent_shafts)
print("Information panels are located in modules:",info_panels)
print("Worker aliens are located in modules:",workers)
#when the players is alive, the module will load
while alive and not won:
load_module()
if won == False and alive == True:
output_moves()
get_action()
#if power is 0 then the user will die and the game will end
if power == 0:
print("You ran out of life support, you died")
alive == False
#win message once you have trapped the queen or when you run out of life
support
if won == True:
print("The queen is trapped and you burn it to death with your
flamethrower.")
print("Game over. You win!")
if alive == False:
print("The station has run out of power. Unable to sustain life
support, you die.")
check_vent_shafts()
First the easy part. You can randomly get 20, 30, 40 or 50 by using random.randint like this:
random.randint(2, 5) * 10
The harder part:
As you discussed with #Random Davis in the comments, you want to assign the npcs to random modules and then print which one you encounter.
To append three random (possibly repeating) modules, use
for _ in range(0,3):
vent_shafts.append(random.choice(module_set))
Using global variables (and the global keyword) is generally considered bad practice as it can cause sideeffects due to other parts of the program modifying a variable you wouldn't expect it to / forgot about. Try to use them as function parameters where needed and return the results
queen, vent_shafts, info_panels, workers = spawn_npcs(5)
def spawn_npcs(num_modules):
module_set = []
for i in range(2, num_modules):
module_set.append(i)
for _ in range(0,3):
vent_shafts.append(random.choice(module_set))
for _ in range(0,2):
info_panels.append(random.choice(module_set))
for _ in range(0,3):
workers.append(random.choice(module_set))
queen_module = module_set[0]
return queen_module, vent_shafts, info_panels, workers
I am currently coding a text based game for a class I'm taking. I want to have a function with nested functions so I don't have to re-write player options in every single room. Here is what I currently have:
#The loop:
while p_choice != 'quit': #begins room loop
#The Forest Clearing
while room == 'Forest Clearing':
avail_choices = ['north'] + avail_all
room_inv = [] #items in this room
room_desc = ("\nYou are in The Forest Clearing. To the north you see a large cave\n"
"with stone stairs leading down. There doesn\'t seem to be anything\n"
"you can do here...\n")
if p_choice == 'north':
print("\nYou step through the cave entrance and walk cautiously down the
stairs.\n"
"You find yourself in some sort of cavern, filled with an inky darkness. It is
far too\n"
"dark to see much, but nearby, you see a pile of rubbish with a flashlight
sitting on top.")
room = rooms[room][p_choice]
elif p_choice not in avail_choices:
print('You can\'t do that here!')
room = [room]
else:
all_rooms()
#Function I'm trying to call
def all_rooms():
def look():
if p_choice == 'look':
print(room_desc)
room = [room]
I want it to return to the loop after printing the room description. It prints the room description like I want, but then it crashes and I get the following error:
Traceback (most recent call last):
File "C:\Users\jwpru\Desktop\IT140-P1\TextBasedGame.py", line 136, in <module>
all_rooms()
File "C:\Users\jwpru\Desktop\IT140-P1\TextBasedGame.py", line 95, in all_rooms
look()
File "C:\Users\jwpru\Desktop\IT140-P1\TextBasedGame.py", line 72, in look
room = [room]
UnboundLocalError: local variable 'room' referenced before assignment
You are in The Forest Clearing. To the north you see a large cave
with stone stairs leading down. There doesn't seem to be anything
you can do here...
I've also tried:
def all_rooms():
def look():
if p_choice == 'look':
print(room_desc)
global room
and...
def all_rooms():
def look():
global room
if p_choice == 'look':
print(room_desc)
room = [room]
Not sure what to do here. Any help would be appreciated!
# Import Modules
from Dice import dice
d10 = dice(10,1)
d4 = dice(4,1)
# Assign Classes
class Player_Character:
def __init__(self, hp, maxhp, ac, THAC0, Surprise_Adjustment, Initiative_Adjustment):
self.hp = int(hp)
self.maxhp = int(maxhp)
self.ac = int(ac)
self.THAC0 = int(THAC0)
self.Surprise_Adjustment = int(Surprise_Adjustment)
self.Initiative_Adjustment = int(Initiative_Adjustment)
def attack(self, goblin):
Player_Character_Damage = d10.die_roll()
goblin.hp -= Player_Character_Damage
if (goblin.hp <= 0):
print("congratulations you killed the goblin")
def flee(self):
print("you run away ")
quit()
def heal(self, Player_Character):
Player_Character.hp += d10.die_roll()
if Player_Character.hp >= Player_Character.maxhp:
Player_Character.hp = Player_Character.maxhp
class goblin:
def __init__(self, hp, maxhp, ac, THAC0, Surprise_Adjustment, Initiative_Adjustment):
self.hp = int(hp)
self.maxhp = int(maxhp)
self.ac = int(ac)
self.THAC0 = int(THAC0)
self.Surprise_Adjustment = int(Surprise_Adjustment)
self.Initiative_Adjustment = int(Initiative_Adjustment)
def attack(self, Player_Character):
goblin_damage = d4.die_roll()
Player_Character.hp -= goblin_damage
if (Player_Character.hp <= 0):
print("oh dear you have died")
del Player_Character
MrHezy = Player_Character(10, 20, 10, 15, 0, 2)
def spawn_goblin(goblin):
G1 = goblin(5, 10, 8, 18, 0, 0)
return G1
goblin1 = spawn_goblin(goblin)
def battle(goblin1):
# user input
player_initiative_adjustment = MrHezy.Initiative_Adjustment
monster_initiative_adjustment = goblin1.Initiative_Adjustment
#define while loop for the battle
battle_not_over = 'yes'
while battle_not_over == 'yes':
#use random.randint(a,b) to generate player and monster base initiative
player_base_initiative = d10.die_roll()
monster_base_initiative = d10.die_roll()
#subtract the adjustment to get player and monster initiative
player_initiative = player_base_initiative - player_initiative_adjustment
monster_initiative = monster_base_initiative - monster_initiative_adjustment
#compare the initiatives and display the results
if (player_initiative < monster_initiative):
attack_flee_heal = input("congratulations you go first. Would you like to attack, flee, or heal?")
while attack_flee_heal != 'attack' or 'flee' or 'heal':
if attack_flee_heal == 'attack':
MrHezy.attack(goblin1)
elif attack_flee_heal == 'heal':
MrHezy.heal(MrHezy)
print("the goblin attacks")
goblin1.attack(MrHezy)
break
elif attack_flee_heal == 'flee':
MrHezy.flee()
break
else:
print("uhoh, the monsters go first, they attack!")
goblin1.attack(MrHezy)
attack_flee_heal = input("Would you like to attack, flee, or heal? ")
while attack_flee_heal != 'attack' or 'flee' or 'heal':
if attack_flee_heal == 'attack':
MrHezy.attack(goblin1)
elif attack_flee_heal == 'heal':
MrHezy.heal(MrHezy)
print("the goblin attacks")
goblin1.attack(MrHezy)
break
elif attack_flee_heal == 'flee':
MrHezy.flee()
break
#main game loop
while True:
spawn_goblin(goblin)
battle(goblin1)
This is a code for a battle simulator that ive been working on. it starts by importing a module that i made which consists of a class called 'dice' which I use for randomly generating numbers. Defining classes is next, with attributes including hp, maxhp, armor class, 'to hit armor class 0', surprise adjustment, and initiative adjustment, and methods including attack which allows you to attack the monsters, flee which exits the battle, and heal which gives your character more hit points. The program moves on to define the spawn_goblin() function which spawns a goblin (this works just fine for the first iteration of the loop). Then it moves on to the battle part which is pretty simple; all it does is check who goes first and then allows you to attack, or flee, or heal yourself. Please ignore the "heal" and "flee" methods, these are working just fine. The problem occurs when I attack the goblin. Instead of killing the goblin and spawning another it creates an infinite loop saying "congratulations you killed the goblin"
while (goblin.hp <= 0):
print("congratulations you killed the goblin")
I think this part of your code is wrong. The while should be if, since you only want to check if the goblin has died, and run some code once. Once the goblin's HP becomes lesser than or equal to 0, the print statement will loop forever since the expression goblin.hp <= 0 will always return True.
EDIT: Now where I think your code is wrong is here:
while attack_flee_heal != 'attack' or 'flee' or 'heal':
if attack_flee_heal == 'attack':
MrHezy.attack(goblin1)
elif attack_flee_heal == 'heal':
MrHezy.heal(MrHezy)
...
I think you have missed the break in the first if (if attack_flee_heal == 'attack'
Also, it would be more appropriate to use an if here rather than a while, since, as I mentioned above, you only want to check once.