5
\$\begingroup\$

I created this game in Python as a learning experience and was hoping for advice to make it better. I also used global and was hoping for good alternatives.

import random
import pickle
import os
enemy_count = 0
health_pot_count = 5
level_up_counter = 1
class Player:
 def __init__(self, name):
 self.name = name
 self.level = 1
 self.health = 20
 self.max_attack = 6
 self.min_attack = 2
 self.armour = 1
 def __repr__(self):
 return('Player({})'.format(self.name))
 def __str__(self):
 return('Name: {}, Level: {}, Health: {}, Max Attack: {}, Min Attack {}, Armour: {}'.format(self.name, self.level, self.health, self.max_attack, self.min_attack, self.armour))
 def level_up(self):
 global level_up_counter
 if level_up_counter == self.level:
 level_up_counter = 1
 self.level += 1
 self.max_attack += 3
 self.min_attack += 3
 self.armour += 2
 else: level_up_counter += 1
 def armour_up(self):
 self.armour += 1
 def weapon_up(self):
 self.max_attack += 1
class World:
 def __init__(self):
 self.isenemy = random.choice([True, True, False])
 def enter_room(self):
 if self.isenemy:
 fight()
 else:
 if random.choice([True, True, False]):
 treasure()
 else:
 print('The room is empty')
class Enemy:
 def __init__(self):
 attack_buff = random.randint(-2,4)
 self.health = 5 * pc.level + random.randint(-5,5)
 self.max_attack = 3 * pc.level + attack_buff
 self.min_attack = 2 * pc.level + attack_buff
 self.armour = pc.level * random.randint(1,2)
 def __str__(self):
 return(f'Enemy Health {self.health}') 
def save():
 save_var = [current_room, rooms, pc, enemy_count, health_pot_count, level_up_counter, pc.name, pc.level, pc.health, pc.max_attack, pc.min_attack, pc.armour]
 with open('save.pkl', 'wb') as save_pickle:
 pickle.dump(save_var, save_pickle)
def get_save():
 global current_room, rooms, pc, enemy_count, health_pot_count, level_up_counter
 with open('save.pkl', 'rb') as save_pickle:
 current_room, rooms, pc, enemy_count, health_pot_count, level_up_counter, pc.name, pc.level, pc.health, pc.max_attack, pc.min_attack, pc.armour = pickle.load(save_pickle)
def save_clear():
 try:
 os.remove(os.path.abspath('save.pkl'))
 except Exception:
 pass
def yn(promt):
 loop = True
 print (promt)
 while loop:
 yn_output = input("Y/N: ").lower()
 if yn_output == 'y':
 loop = False
 return True
 elif yn_output == 'n':
 loop = False
 return False
 else: print('Invalid input!')
def new_game():
 global current_room, rooms, pc, enemy_count, health_pot_count, level_up_counter 
 enemy_count = 0
 health_pot_count = 5
 level_up_counter = 1
 save_clear()
 name = input("What is the name of are brave adventurer: ")
 #pc stands for player character.
 pc = Player(name)
 current_room = 0
 rooms = ['start_room']
 start_room = World()
def start_up():
 print('Welcome to text dungeon')
 start_loop = True
 while start_loop:
 new_game_test = yn('Is this a new game.')
 if new_game_test == True:
 if yn('Are you sure, this will clear all saves.'):
 start_loop = False
 new_game()
 elif new_game_test == False:
 start_loop = False
 get_save()
def new_room(room, current_room):
 room.append(str(current_room) + '_room')
 room[current_room] = World() 
def fight():
 increment_enemy_count()
 print('Starting combat!')
 enemys = []
 enemys.append('{}_enemy'.format(enemy_count))
 enemys[0] = Enemy()
 combat = True
 while combat:
 space()
 print(pc)
 print('Enemy Stats- Health: {}, Max Attack: {}, Min Attack {}, Armour: {}'.format(enemys[0].health, enemys[0].max_attack, enemys[0].min_attack, enemys[0].armour))
 print('What is your move.')
 action_wait = True
 while action_wait:
 action = input('1 = attack, 2 = Use health potion: ')
 if action == '1':
 attack_damage = random.randint(pc.min_attack, pc.max_attack)
 if attack_damage < enemys[0].armour:
 print(f'You did 0 damage.')
 else:
 enemys[0].health = (int(enemys[0].health) + int(enemys[0].armour)) - attack_damage
 print(f'You did {int(attack_damage) - int(enemys[0].armour)} damage.')
 if enemys[0].health < 1:
 combat = False
 action_wait = False
 elif action == '2':
 if health_pot_count > 0:
 health_pot_use()
 action_wait = False
 else: 
 print('You have none.')
 else:
 print('Try again')
 attack_damage = random.randint(enemys[0].min_attack, enemys[0].max_attack)
 if attack_damage < pc.armour:
 print(f'You took 0 damage.')
 else:
 pc.health = int((pc.health) + int(pc.armour) - attack_damage)
 print(f'You took {int(attack_damage) - int(pc.armour)} damage.')
 if (pc.health < 1):
 combat = False
 death()
 print('You win')
 pc.level_up()
 treasure() 
def treasure():
 global health_pot_count
 loot = random.randint(1, 5)
 if loot == 1:
 print('You got a health potion!')
 health_pot_count += 1
 elif loot == 2:
 print('You got a better weapon!')
 pc.weapon_up()
 elif loot == 3:
 print('You got better armour!')
 pc.armour_up()
 else:
 print('No Loot')
def death():
 print('You lose')
 save_clear()
 main()
def increment_enemy_count():
 global enemy_count 
 enemy_count += 1
def health_pot_use():
 global health_pot_count
 health_pot_count -= 1
 health_back = pc.level * 2 + random.randint(-2, 6)
 pc.health += health_back
 print(f'You got {health_back} health.')
def space():
 print()
 print()
def main():
 global pc, current_room, play
 start_up()
 save()
 play = True
 while play:
 wait_for_action = True
 while wait_for_action:
 save_clear()
 save()
 space()
 print(str(pc))
 print('What do you want to do.')
 action = input("1 = continue, 2 = Use health potion: ")
 if action == '1':
 play = False
 current_room += 1
 new_room(rooms, current_room)
 rooms[current_room].enter_room()
 elif action == '2':
 play = False
 if health_pot_count > 0:
 health_pot_use()
 else: print('You have none.')
 else: print('Invalid action!')
if __name__ == '__main__':
 main()
asked Feb 26, 2019 at 3:14
\$\endgroup\$
0

1 Answer 1

3
\$\begingroup\$

Decision loops

Your implementation of a decision loop is... interesting to say the least. If you're using python-3.8, you can utilize the walrus operator. It's a way to assign variables within an expression. In this case, the while loop. Have a look:

def choice(prompt: str) -> bool: # replaced "yn" with "choice" #
 print(prompt)
 while decision := input("Y/N: ").lower():
 if decision in "yn":
 return decision == "y"
 print("Invalid input!")

Instead of just returning True or False, you can return the boolean expression that evaluates to a boolean. It's the same thing you're doing, but a lot simpler.

Type Hints

Using type hints help you and other people reading your code know what types of parameters are accepted and what types are returned by functions. If you look at the function above, you can see that prompt is a str, and the function returns a bool value.

Dealing with exceptions

def save_clear():
 try:
 os.remove(os.path.abspath('save.pkl'))
 except Exception:
 pass

Passing on an exception isn't a good idea. An Exception is raised, and you're essentially ignoring it. I would print an error message to the console, such as "ERROR: File not found!" or something related. Just to tell you whats wrong, instead of having an exception and not knowing what specifically is wrong. You should also try to catch specific exceptions if you can.

Consistency

You use three different ways to concatenate strings in your program. .format, f"" and +. Use one method and stick to it. I would recommend f"" because it allows you to directly include variables in your strings, rather than having to call a function (.format) to add them.

Globals

It's not recommended to use globals. They can have unseen consequences, increase the complexity of your program, and can lead to spaghetti code. I would try to find a way to write this program without using globals.

Boolean Comparison

Instead of

if new_game_test == True:

do this

if new_game_test:

new_game_test is a boolean value in itself, so you can just check that value.

answered Mar 26, 2020 at 20:47
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.