I haven't coded in python in a long time, since 2.7 came out. I am trying to make a simple tic tac toe game, but if I try to reference a attribute in TicTacToe object. It throws a run time exception saying that TicTacToe has no such attribute. Any ideas?
class TicTacToe(object):
def __init__(self):
'''
:return: TicTacToe object
'''
self.turn = 1
self.deckList = [Deck()]
self.player1 = Player()
self.player2 = Player()
def validateInput(self, num):
if type(num) is not int:
print('Not an integer 0-8')
return
elif num < 0 | num > 8:
print('Not between 0-8')
return
def getUserInput(self, turn):
if turn == 1:
choice = input('Player 1: Enter 0-8\n')
#turn = 2
elif turn == 2:
choice = input('Player 2: Enter 0-8\n')
#turn = 1
return choice
def startGame(self):
player1Name = input('Player 1: Enter your name\n')
player2Name = input('Player 2: Enter your name\n')
self.player1.Player.setName(player1Name)
self.player2.Player.setName(player2Name)
player1Mark = input('Player 1: Enter your mark\n')
player2Mark = input('Player 2: Enter your mark\n')
if player1Mark == player2Mark:
print('You both cannot have the same mark\n')
return
else:
self.player1.setMark(player1Mark)
self.player2.setMark(player2Mark)
while True: # Main loop
choice = self.getUserInput(self.turn)
Main
from TicTacToe import TicTacToe
if __name__ == '__main__':
game = TicTacToe
game.startGame(game)
pass
I have the other classes here, Player class and Deck(Board) class
import numpy as np
class Deck(object):
def __init__(self):
"""
:return: Deck
"""
board = np.matrix([-1,-1,-1],[-1,-1,-1],[-1,-1,-1])
player1Choices = []
player2Choices = []
def __str__(self):
return self.board
class Player(object):
def __init__(self):
"""
:return: A new Player
"""
name = None
mark = None
statistics = [0, 0, 0] # [Win, Tie, Lost]
def setName(self, name):
"""
:param name: Set name of player
"""
self.name = name
def setMark(self, mark):
"""
:param mark: Set mark of player
"""
self.mark = mark
def getScore(self):
"""
:return: Statistics of player
"""
score = ((self.statistics[0] * 2) + self.statistics[1] - self.statistics[2])
return score
def __str__(self):
"""
:return: String representation of values inside Player
"""
return "Name: " + self.name + "\nMark: " + self.mark + "\nScore: " + self.getScore() + "\n"
def __cmp__(self, player):
"""
:param: A Player
:return: Winner
"""
if self.getScore() > player.getScore():
return self
elif self.getScore() < player.getScore():
return player
else:
return None
game = TicTacToe
Constructors need parens (and optional arguments).
game = TicTacToe()
Related
I've recently been trying to make a Textadventure but I'm having a big problem with the idea of "moving" around a List (x_achses) with a List inside(y-achses) it (my father called it a matrix) and in the second list (y-achses) there are a bunch of random types of things like an enemy. In that "Matrix" I wanna move around and on certain fields it should activate the assigned class(here it should simply print the classes name).
I've tried using the index of the list and changing dependently but it didn't work, I've tried using the len() function and changing it dependently but nothing ever seems to be happening. No classes or anything seem to be called. I have no idea what to do.
import random
import secrets
class Character:
def __init__(self, hp, ad, name):
self.hp = hp
self.ad = ad
self.name = name
def get_hit(self, ad):
self.hp = self.hp - ad
if self.hp <= 0:
self.die()
def is_dead(self):
return self.hp <= 0
def die(self):
print(self.name + " died")
class Human_enemies(Character):
def __init__(self):
super().__init__(self, 10, 3, "Mermaids")
Human_enemies.enemie_amount = random.randint(1, 9)
print("Mermaids")
def enemie_amount(self):
enemie_amount = random.randint(1, 9)
enemies = []
for i in range(enemie_amount):
enemies.append(Human_enemies())
class Vessel:
def __init__(self, hp, ad, storage, name):
self.hp = hp
self.ad = ad
self.storage = storage
self.name = name
def get_hit(self, ad):
self.hp = self.hp - ad
if self.hp <= 0:
self.die()
def is_dead(self):
return self.hp <= 0
def die(self):
print(self.name + " died")
class Sloop_ship(Vessel):
def __init__(self):
super().__init__(self, 1000, 50-100, 0, "Sloop")
def type(self):
print("Sloop")
class Brigattine_ship(Vessel):
def __init__(self):
super().__init__(self, 2500, 70-110, 15, "Brig")
def type(self):
print("Brig")
class Galleon_ship(Vessel):
def __init__(self):
super().__init__(self, 5000, 150-200, 40, "Galleon")
def type(self):
print("Galleon")
class Shipwreck:
def __init__(self):
print("Shipwreck")
wanna_loot = input("Do you want to check the wreck for any loot or survivors?\n")
#TODO: Make this better, sth. like chance of death or sth.
class Fields:
def Rougethingi(self):
random1 = random.randint(0, 5)
if random1 == 0:
return Shipwreck
elif random1 == 1:
return Human_enemies
elif random1 == 2:
return Sloop_ship
elif random1 == 3:
return Brigattine_ship
elif random1 == 4:
return Galleon_ship
else:
return None
class Map():
def __init__(self, x, y):
self.rowsX = []
self.x = x
self.y = y
for i in range(x):
self.rowsY = []
for r in range(y):
self.rowsY.append(Fields.Rougethingi(self))
self.rowsX.append(self.rowsY)
def print_map(self):
for j in self.rowsX:
print("")
for f in self.rowsY:
if f == None:
print("0 ", end = "")
elif f != None:
print("1 ", end = "")
print("\n")
class Player(Character):
def __init__(self):
super().__init__(self, 100, 1, player_name)
def start(self):
self.player_x = 1
self.player_y = 1
n.rowsX[self.player_x].__init__()
n.rowsY[self.player_y].__init__()
def move_right(self):
self.player_x = self.player_x + 1
if self.player_x >= n.x or self.player_x >= n.x - n.x:
print("You can't go further right")
def move_left(self):
self.player_x = self.player_x - 1
if self.player_x >= n.x or self.player_x >= n.x - n.x:
print("You can't go further right")
def move_up(self):
self.player_y = self.player_y + 1
if self.player_y >= n.y or self.player_y >= n.y - n.y:
print("You can't go further right")
def move_down(self):
self.player_y = self.player_y - 1
if self.player_y >= n.y or self.player_y >= n.y - n.y:
print("You can't go further right")
def quit_game():
exit("And the mighty adventurer decided to rest for the day...")
def print_help():
utility = print("(help, save, load, map,)")
movement = print("(forward, backwards, starboard, port)")
utility
movement
def save():
#TODO: Make a save system
pass
def load():
#TODO: Make a load system
pass
if __name__ == "__main__":
player_name = input("What is thy title scalywag?\n")
n = Map(30, 30)
m = Player.start
print("You shall call us for 'help' to help you with your role of Captain\n")
#? This is the main input loop --------------------------------------v
while True:
cmd = input(">>>")
if cmd == "help":
print_help()
continue
elif cmd == "map":
n.print_map()
continue
elif cmd == "quit":
quit_game()
elif cmd == "save":
save()
continue
elif cmd == "load":
load()
continue
elif cmd == "forward":
Player.move_up
continue
elif cmd == "backwards":
Player.move_down
continue
elif cmd == "starboard":
Player.move_right
continue
elif cmd == "port":
Player.move_left
continue
else:
print("I dont understand that... \n")
continue
#? This is the main input loop --------------------------------------v
there a problem with add AI + r.radint(0, 99).
i want a user to input who to attack and if a user type in the wrong input then prompt invalid input and try again using while loop, if a user type in AI99 (for example) that in the list on a ai unit then it will break and continue the program.
i want to use this statement under the input ("who do you want attack?")
# Prompts the user who he/she wants to attack.
opponent_name_to_attack = input("Who do you want attack? ").upper()
Main:
import gameplayerteam
import gamechar
import random as r
import gamelogger
player_units = None # A GamePlayerTeam object which comprises of 3 Human players
ai_units = None # A GamePlayerTeam object which comprises of 3 AI players
ai_units_player_id = []
ai_character_class_list = ['warrior', 'tanker']
def main():
gamelogger.prepares_log_folder()
gamelogger.print_and_log_game_message("Welcome to battle game!")
setup_human_unit()
setup_ai()
game_is_over = False
player_turn_of_attack = 'human' # Possible values: 'human', 'ai'
previous_player = None
curr_player = None
opponent_player_team = None
while not game_is_over:
gamelogger.print_and_log_game_message("============= Human Unit =============")
for i in range(len(player_units.players)):
gamelogger.print_and_log_game_message(player_units.players[i])
gamelogger.print_and_log_game_message("======================================\n")
gamelogger.print_and_log_game_message("============= AI Unit ================")
for i in range(len(ai_units.players)):
gamelogger.print_and_log_game_message(ai_units.players[i])
gamelogger.print_and_log_game_message("======================================\n")
#print("Is Game Over? : " + str(game_is_over))
if player_turn_of_attack == 'human':
#Gets the current human player's GameCharacter object
curr_player = player_units.get_current_player()
gamelogger.print_and_log_game_message("Now the {0} is playing".format(curr_player.name))
# Prompts the user who he/she wants to attack.
opponent_name_to_attack = input("Who do you want attack? ").upper()
# Sets the current_player_id of the matching AI Player's name that the user input
ai_units.set_player_id(opponent_name_to_attack)
# Sets the predicted next (name of) AI player after current AI player's turn ends
ai_units.predict_next_player()
# Assigns the AI Team (GamePlayerTeam object) as the opponent_player_team
opponent_player_team = ai_units
# Let's search for the GameCharacter object with the same name as opponent_to_attack
opponent_to_attack = ai_units.get_player_by_name(opponent_name_to_attack)
# Update the player_turn_of_attack value to ai so that the next turn will be AI
player_turn_of_attack = 'ai'
else:
gamelogger.print_and_log_game_message("Now the AI is playing")
# Sets the predicted next (name of) human player after current human player's turn ends
player_units.predict_next_player()
# Update the opponent_name_to_attack with previous_player
opponent_name_to_attack = previous_player.name
# Assigns the Human Team (GamePlayerTeam object) as the opponent_player_team
opponent_player_team = player_units
# Let's search for the GameCharacter object with the same name as opponent_to_attack
opponent_to_attack = previous_player
# Update the player_turn_of_attack value to human so that the next turn will be human
player_turn_of_attack = 'human'
# Update the curr_player_id to the next human player id
#player_units.set_next_player_id()
gamelogger.print_and_log_game_message("Attacking " + opponent_name_to_attack)
curr_player.attack_target(opponent_to_attack)
curr_player.check_rank()
#opponent_player_team.set_next_player_id()
#Checks the opponent player's HP
if opponent_to_attack.hp <= 0:
#Removes this opponent_to_attack from the team
opponent_player_team.remove_player(opponent_to_attack)
opponent_player_team.set_next_player_id()
# The next player in the opponent team will be switched over as the
# opponent_to_attack as our previous opponent player has been disqualified
opponent_to_attack = opponent_player_team.get_current_player()
else:
# We will simply set the curr_player_id to the next (predicted) player
opponent_player_team.set_next_player_id()
# Update the value of curr_player and the previous_player
previous_player = curr_player
curr_player = opponent_to_attack
game_is_over = check_has_game_over()
gamelogger.print_and_log_game_message("===========================")
gamelogger.print_and_log_game_message("Game is over")
def setup_human_unit():
global player_units
player_units = gameplayerteam.GamePlayerTeam('human')
for i in range(3):
char_type = input("Enter Character class [warrior/tanker]: ")
char_name = input("Enter character name: ")
player_units.add_player(char_type, char_name)
def setup_ai():
global ai_units
#Creates a GamePlayerTeam object (with no players first)
ai_units = gameplayerteam.GamePlayerTeam('ai')
for ai_player_count in range(3):
ai_character_class_list.reverse()
random_num = r.choice(ai_character_class_list)
ai_units.add_player(random_num, 'AI'+ str(ai_player_count+r.randint(0, 99)))
#ai_units.append(gamechar.GameCharacter(random_num, 'AI'+ str(ai_player_count+1) ))
def check_has_game_over():
is_game_over = False
# In the entire game, there's only 1 player left (whether it is an AI or human)
if ai_units.check_are_all_players_defeated():
is_game_over = True
elif player_units.check_are_all_players_defeated():
is_game_over = True
else:
is_game_over = False
return is_game_over
main()
gameplayerteam:
import gamechar
class GamePlayerTeam:
def __init__(self, player_type):
self.players = []
self.type_of_player = player_type #Possible value: 'ai', 'human'
self.all_players_defeated = False #Keeping track whether all units in this team are defeated
self.curr_player_id = 0 # Up to the last index of the players list
self.next_player_name = ''
def add_player(self, char_type, char_name):
#Adding a particular unit / player to the team
self.players.append(gamechar.GameCharacter(char_type, char_name))
def remove_player(self, player_to_remove):
# Removes a particular GameCharacter object from the players list
self.players.remove(player_to_remove)
def remove_player_by_id(self, player_id_to_remove):
# Remarks: This method will only likely be used by a Human GameCharacter
# Removes a particular GameCharacter object from the players list with a matching
# player_id_to_remove value
self.players.pop(player_id_to_remove)
def get_player_by_id(self, input_player_id):
# Remarks: This method will only likely be used by a Human GameCharacter
# Returns a particular GameCharacter object from the players list using the provided
# input_player_id value
return self.players[input_player_id]
def set_player_id(self, player_name):
#Sets the id of the player with the matching name from the players list
index = 0
while index < len(self.players):
if self.players[index].name == player_name.upper():
# Targeted Player found, stops executing the loop immediately
break
# Increments index by 1 as target not yet found
index += 1
# Update the curr_player_id to the index that we found
self.curr_player_id = index
def get_player_by_name(self, input_player_name):
# Returns a particular GameCharacter object by searching the matching GameCharacter object
# with the same name as input_player_name through the players list
player = None
for i in range(len(self.players)):
if input_player_name.upper() == self.players[i].name:
player = self.players[i]
break
return player
def get_current_player(self):
# Let's first validate whether if our players list is empty or not
if len(self.players) == 0:
# Because our players list is empty, this function will just simply
# return an empty object
return None
else:
# Returns a particular GameCharacter object from the players list
return self.players[self.curr_player_id]
def predict_next_player(self):
# Looks for the next player, and then update the curr_player_id to the matching next player's id
if self.curr_player_id == len(self.players) - 1:
# Reset the human player id as 0 to be the next human player id
self.next_player_name = self.players[0].name
else:
self.next_player_name = self.players[self.curr_player_id + 1].name
def set_next_player_id(self):
index = 0
while index < len(self.players):
if self.players[index].name == self.next_player_name:
# Targeted Player found, stops executing the loop immediately
break
#Increments index by 1 as target not yet found
index += 1
#Update the curr_player_id to the index that we found
self.curr_player_id = index
def check_are_all_players_defeated(self):
if len(self.players) == 0:
self.all_players_defeated = True
else:
self.all_players_defeated = False
return self.all_players_defeated
gamechar:
import random as r
import gamelogger
class GameCharacter:
def __init__(self, char_type, char_name):
self.type = ""
self.name = char_name
self.hp = 100
self.attack = 0
self.defence = 0
self.xp = 0
self.rank = 1
self.coin = 0
if char_type == 'warrior':
self.setup_warrior()
elif char_type == 'tanker':
self.setup_tanker()
def setup_warrior(self):
self.type = 'warrior'
self.attack = r.randint(5, 20)
self.defence = r.randint(1, 10)
def setup_tanker(self):
self.type = 'tanker'
self.attack = r.randint(1, 10)
self.defence = r.randint(5, 15)
def attack_target(self, target):
damage = self.attack - target.defence + r.randint(-5, 10)
target.hp -= abs(damage)
self.xp += abs(damage)
target.xp += target.defence
target.xp = round(target.xp, 1)
self.coin += target.xp
if damage > 10:
target.xp *= 1.2
# Rounds off (up/down) target.xp to 1 decimal point if it has a value with 2
# or more decimal points
target.xp = round(target.xp, 1)
elif damage <= 0:
target.xp *= 1.5
# Rounds off (up/down) target.xp to 1 decimal point if it has a value with 2
# or more decimal points
target.xp = round(target.xp, 1)
gamelogger.print_and_log_game_message("******************************************")
gamelogger.print_and_log_game_message("[Game Message] {0} attacked {1} with damage {2}: +{2}EXP".format(self.name, target.name, round(abs(damage),1) ) )
# print("Damage to target: {0}".format(damage))
gamelogger.print_and_log_game_message("******************************************")
def check_rank(self):
if self.xp >= 100:
self.rank += 1 # Promote rank by 1
self.xp -= 100 # Reduce the xp by 100
gamelogger.print_and_log_game_message("{0} have been promoted to Rank {1} ".format(self.name, self.rank) )
def __str__(self):
text = "{} {}: HP:{}, ATK:{}, DEF:{}, EXP:{}, RANK: {}".format(self.type, self.name, self.hp, self.attack, self.defence, self.xp, self.rank)
return text
So I am creating a card game in python using classes. I got it all set up to the point where it should work. But when I ran it it just simply never stops running. I am not really sure how to make this code minimal and reproduceable, because I do not know where the issue is at.
Here is the code i have written.
It has to be in the play_uno() class object.
""" UNO Simulator """
import random
class card():
def __init__(self, value, color, wild):
'''
An UNO deck consists of 108 cards, of which there are 76 Number cards,
24 Action cards and 8 Wild cards. UNO cards have four color "suits",
which are red, yellow, blue and green.
'''
self.card_nums = ['0','1','2','3','4','5','6','7','8','9']
self.card_colors = ['red','blue','green','yellow']
self.spec_cards = ['draw2','reverse','skip']
self.wild_cards = ['wild','wild_draw_4']
if wild == False:
self.value = self.card_nums[value]
self.color = self.card_colors[color]
elif wild == 'special':
self.value = self.spec_cards[value]
self.color = self.card_colors[color]
elif wild == True:
self.value = self.wild_cards[value]
self.color = None
class generate_deck():
def __init__(self):
self.number_cards = self.get_num_cards()
self.special_cards = self.get_special_cards()
self.wild_cards = self.get_wild_cards()
self.cards = self.number_cards + self.special_cards + self.wild_cards
random.shuffle(self.cards)
def get_num_cards(self):
# only one zero per color
with_zeroes = [card(i,j,False) for i in range(10) for j in range(4)]
no_zeroes = [card(i,j,False) for i in range(1,10) for j in range(4)]
return no_zeroes + with_zeroes
def get_wild_cards(self):
wild_draw4s = [card(i,None,True) for i in range(2) for x in range(2)]
wilds = [card(i,None,True) for i in range(2) for x in range(2)]
return wilds + wild_draw4s
def get_special_cards(self):
return [card(i,j,'special') for i in range(3) for j in range(4) for x in range(2)]
class player():
def __init__(self, name):
self.wins = 0
self.name = name
self.cheater = False
self.cards = ''
self.turn = 0
self.uno = 0
class play_uno():
def __init__(self, num_players = 3, num_cheaters = 0, cards_per_player = 5):
# get started
self.rules = 'default'
self.status = 'ongoing'
self.deck = generate_deck().cards
self.played_cards = []
self.dro = 0
self.direction = 0
self.top_card = self.deck.pop() # random card as first card to play on
self.tot_turns = 0
# generate players, make cheaters later
self.players = [player('player' + str(i)) for i in range(num_players + num_cheaters)]
# give each player 7 cards to start
for _player_ in self.players:
_player_.cards = [self.draw_card() for i in range(cards_per_player)]
# start playing turns in order
# do not know how to reverse yet
"""
Right now it is endless for some reason.
"""
while self.status == 'ongoing':
for _player in self.players:
self.turn(_player)
def draw_card(self):
# draws random card from deck instead of card on top
if len(self.deck) == 0:
self.re_shuffle()
self.dro += 1
return self.deck.pop()
def re_shuffle(self):
self.deck = self.played_cards
random.shuffle(self.deck)
self.played_cards = []
return self.deck, self.played_cards
def play_card(self, player_cards, _card):
self.top_card = _card
return player_cards.remove(_card), self.played_cards.append(_card), self.top_card
def game_over(self, winner):
winner.wins += 1
self.game_status = 'over'
def turn(self, _player):
played = False
# check if someone played wild card last turn
if self.top_card.value in card(1,2,None).wild_cards:
self.top_card.color = random.choice(card.card_colors)
if self.top_card.value == 'wild_draw_4':
_player.cards += [self.draw_card() for i in range(4)]
self.tot_turns += 1
return _player
# check for special cards
elif self.top_card.value in card(1,2,None).spec_cards:
if self.top_card.value == 'draw2':
_player.cards += [self.draw_card() for i in range(4)]
self.tot_turns += 1
return _player
# for now we are treating reverse cards like skips
elif self.top_card.value == 'reverse' or self.top_card.value == 'skip':
played = True
self.tot_turns += 1
return _player
# If its a normal card, or regular wild
if played == False:
for _card in _player.cards:
if _card.color == self.top_card.color:
self.play_card(_player.cards, _card)
played = True
break
elif _card.value == self.top_card.value:
self.play_card(_player.cards, _card)
played = True
break
# if the player cannot play at all
# rn they just move on if they have to draw,
# cant play the card they just drew.
if played == False:
_player.cards += [self.draw_card()]
played = True
self.tot_turns += 1
# check if the player won or not
if len(_player.cards) == 0:
self.game_over(_player)
elif len(_player.cards) == 1:
_player.uno += 1
return _player.cards
In the function turn in the play_uno class you are checking for certain wild/special cards. If the value is reverse, for example, the function hits a return _player line which ends the execution of the function and the player is unable to play another card.
Move the return statements to the end of the function if you want to ensure the rest of the code is run.
I did not run the code, but I think you should test a player's number of cards before drawing again. Like this:
if len(_player.cards) == 0:
self.game_over(_player)
elif len(_player.cards) == 1:
_player.uno += 1
if played == False:
_player.cards += [self.draw_card()]
played = True
self.tot_turns += 1
Or are the rules of this game different? I sincerely don't remember them anymore.
The while loop at the end of play_uno's __init__ checks for status, which never changes.
The loop calls turn on each of players every iteration. You must change status somewhere or you must put an if ...: break in the while loop (e.g. if not _player.cards).
EDIT: It appears that you meant self.status instead of self.game_status, in game_over. Try changing game_status to status there.
This question already has an answer here:
NoneType object is not subscriptable
(1 answer)
Closed 2 years ago.
I'm trying to write code for a text based RPG by following along in a book called Make Your Own Python Text Adventure by Phillip Johnson. I am having trouble identifying where the error lies in my code. I've gone through it several times and can't seem to figure it out. I've tried fiddling with different things but so far it just gives different errors. I'll post my code and the Traceback.
Traceback (most recent call last):
File "C:\Users\Timothy Hall\Desktop\Yradel_Game\Yradel_Game5.py", line 99, in <module>
main()
File "C:\Users\Timothy Hall\Desktop\Yradel_Game\Yradel_Game5.py", line 31, in main
player = Player()
File "C:\Users\Timothy Hall\Desktop\Yradel_Game\player.py", line 11, in __init__
self.x = world.start_tile_location[0]
TypeError: 'NoneType' object is not subscriptable
Yradel_Game5.py
# this program is a text based rpg
#import the OrderedDict
from collections import OrderedDict
# import the player module
from player import Player
# import the world module
import world
def main():
# display Yradellian name examples
print("Some examples of female Yradellian names include Nelsi, Drew, Casey, Ilya, etc.")
print("Some examples of male Yradellian names include Toreth, Daren, Attel, Mayes, etc.")
# get the character name from the user
yesName = False
while yesName == False:
charName = input("What can I call you? ")
nameInput = input("Your name is, " + charName + "? Type Yes or No: ")
if nameInput == "Yes":
yesName = True
else:
print("Sorry...")
# call the parse world function
world.parse_world_dsl()
# create a player object
player = Player()
# display the welcome message
print()
player.say_hello(charName)
# display current inventory
print()
print("Here's your starting game Inventory:")
player.print_inventory()
while True:
# display the intro text for each tile
print()
room = world.tile_at(player.x, player.y)
print(room.intro_text())
# modify the player depending on the tile type
room.modify_player(player)
# get the action input from the user
print()
choose_action(room, player)
# create a funtion for available actions
def get_available_actions(room, player):
actions = OrderedDict()
print("Choose what to do...")
if player.inventory:
action_adder(actions, "i", player.print_inventory, "Print inventory")
if isinstance(room, world.TraderTile):
action_adder(actions, "t", player.trade, "Trade")
if isinstance(room, world.EnemyTile) and room.enemy.is_alive():
action_adder(actions, "a", player.attack, "Attack")
else:
if world.tile_at(room.x, room.y - 1):
action_adder(actions, "n", player.move_north, "Go North!")
if world.tile_at(room.x + 1, room.y):
action_adder(actions, "e", player.move_east, "Go East!")
if world.tile_at(room.x, room.y + 1):
action_adder(actions, "s", player.move_south, "Go South!")
if world.tile_at(room.x - 1, room.y):
action_adder(actions, "w", player.move_west, "Go West!")
if player.hp < 100:
action_adder(actions, "h", player.heal, "Heal")
return actions
# create the action adder function
def action_adder(action_dict, hotkey, action, name):
action_dict[hotkey.lower()] = action
action_dict[hotkey.upper()] = action
print("{}: {}".format(hotkey, name))
# create a function to utilize the action dictionary
def choose_action(room, player):
action = None
while not action:
available_actions = get_available_actions(room, player)
action_input = input("Action: (Type a letter) ")
action = available_actions.get(action_input)
if action:
action()
else:
print("That is invalid input.")
# call the main function
main()
world.py
# import the enemies module
import enemies
# import the npc module
import npc
# import the random module
import random
# create a parent class for the map tiles
class MapTile:
def __init__(self, x, y):
self.x = x
self.y = y
def intro_text(self):
raise NotImplementedError("Create a subclass instead!")
def modify_player(self, player):
pass
# create the tile subclasses
class StartTile(MapTile):
def intro_text(self):
return """You find yourself in a forest, sunlight trickling through the leaves overhead. Your feet crunch over the underbrush. You can see four paths through the trees.\n"""
class BoringTile(MapTile):
def intro_text(self):
return """The trees all look the same here...\n"""
class CityTile(MapTile):
def intro_text(self):
return """You made it out of the forest into a small town known as Burenburg. The people greet you warmly and you are filled with a sense of accomplishment.\n"""
class EnemyTile(MapTile):
# have enemies randomly appear
def __init__(self, x, y):
r = random.random()
if r < 0.50:
self.enemy = enemies.Wolf()
self.alive_text = "A lone Wolf approaches you baring its fangs."
self.dead_text = "The Wolf keels over, dead before you."
else:
self.enemy = enemies.Goblin()
self.alive_text = "A Goblin tries to steal your gold, you must defend yourself against his blade."
self.dead_text = "The Goblin sticks its tongue out at you as it falls over dead."
super().__init__(x, y)
# display their alive/dead message
def intro_text(self):
text = self.alive_text if self.enemy.is_alive() else self.dead_text
return text
# have enemies attack the player
def modify_player(self, player):
if self.enemy.is_alive():
player.hp = player.hp - self.enemy.damage
print("Enemy does {} damage. You have {} HP remaining.".format(self.enemy.damage, player.hp))
class TraderTile(MapTile):
def __init__(self, x, y):
self.trader = npc.Trader()
super().__init__(x, y)
# create a method to trade between a buyer and seller
def trade(self, buyer, seller):
for i, item in enumerate(seller.inventory, 1):
print("{}. {} - {} Gold".format(i, item.name, item.value))
while True:
user_input = input("Choose an item or press Q to exit: ")
if user_input in ["Q", "q"]:
return
else:
try:
choice = int(user_input)
to_swap = seller.inventory[choice - 1]
self.swap(seller, buyer, to_swap)
except ValueError:
print("Invalid choice!")
# create a method to swap items and gold between the buyer and seller
def swap(self, seller, buyer, item):
if item.value > buyer.gold:
print("That's too expensive")
return
seller.inventory.remove(item)
buyer.inventory.append(item)
seller.gold = seller.gold + item.value
buyer.gold = buyer.gold - item.value
print("Trade complete!")
# create a method to accept user input about who is the buyer and seller
def check_if_trade(self, player):
while True:
print("Would you like to (B)uy, (S)ell or (Q)uit?")
user_input = input()
if user_input in ["Q", "q"]:
return
elif user_input in ["B", "b"]:
print("Here's what's available to buy: ")
self.trade(buyer = player, seller = self.trader)
elif user_input in ["S", "s"]:
print("Here's what's available to sell: ")
self.trade(buyer = self.trader, seller = player)
else:
print("Invalid choice!")
# create intro text for this room
def intro_text(self):
return """A man in a brown robe awaits you, willing to trade."""
class GoldTile(MapTile):
def __init__(self, x, y):
self.gold = random.randint(1, 50)
self.gold_claimed = False
super().__init__(x, y)
def modify_player(self, player):
if not self.gold_claimed:
self.gold_claimed = True
player.gold = player.gold + self.gold
print("+{} Gold added.".format(self.gold))
def intro_text(self):
if self.gold_claimed:
return """Another clearing in the forest with nothing in it but cute animals and underbrush."""
else:
return """Someone must've dropped some gold! You pick it up."""
# create the basic world map
world_dsl = """
| |E|C|E| |
|B|B| |B| |
|T| |G|E|B|
|G| |E| |G|
|E|B|S|T|B|
| | |E| |G|
| | |G|B|E|
"""
# create a function to validate the dsl
def is_dsl_valid(dsl):
if dsl.count("|S|") != 1:
return False
if dsl.count("|C|") == 0:
return False
lines = dsl.splitlines()
lines = [l for l in lines if l]
pipe_counts = [line.count("|") for line in lines]
for count in pipe_counts:
if count != pipe_counts[0]:
return False
return True
# define a dictionary that maps dsl abreviations to tile types
tile_type_dict = {"C": CityTile,
"E": EnemyTile,
"S": StartTile,
"B": BoringTile,
"G": GoldTile,
"T": TraderTile,
" ": None}
world_map = []
start_tile_location = None
# create the function to parse the dsl
def parse_world_dsl():
if not is_dsl_valid(world_dsl):
raise SyntaxError("DSL is invalid!")
dsl_lines = world_dsl.splitlines()
dsl_lines = [x for x in dsl_lines if x]
# iterate over each line in the dsl
# instead of i, the variable y is used because we're working with an X-Y grid.
for y, dsl_row in enumerate(dsl_lines):
# create an object to store the tiles
row = []
# split the line into abbreviations using the "split" method
dsl_cells = dsl_row.split("|")
# the split method includes the beginning and end of the line
# so we need to remove those nonexistent cells
dsl_cells = [ c for c in dsl_cells if c]
# iterate over each cell in the dsl line
# instead of j, the variable x is used becuase we're working with an X-Y grid
for x, dsl_cell in enumerate(dsl_cells):
# look up the abbreviation in the dictionary
tile_type = tile_type_dict[dsl_cell]
# if the dictionary returned a valid type, create a new
# tile object, pass it the X-Y coordinates as required
# by the tile__init__(), and add it to the row object. If
# None was found in the dictionary, we just add None.
row.append(tile_type(x, y) if tile_type else None)
# add the whole row to the world_map
world_map.append(row)
# create a function that locates the tile at a specific coordinate
def tile_at(x, y):
if x < 0 or y < 0:
return None
try:
return world_map[y][x]
except IndexError:
return None
player.py
# import the items module
import items
# import the world module
import world
# create a class for Player
class Player:
# define the inventory
def __init__(self):
self.inventory = [items.Dagger(), items.BreadRoll(), items.Potion()]
self.x = world.start_tile_location[0]
self.y = world.start_tile_location[1]
self.hp = 100
self.gold = 100
# print the inventory and the best weapon
def print_inventory(self):
print("Inventory:")
for item in self.inventory:
print("* " + str(item))
print("Gold: {}".format(self.gold))
best_weapon = self.most_powerful_weapon()
print("Your best weapon is your {}".format(best_weapon))
# create a function to heal the player
def heal(self):
consumables = [item for item in self.inventory if isinstance(item, items.Consumable)]
if not consumables:
print("You don't have any items to heal you!")
return
for i, item in enumerate(consumables, 1):
print("Choose an item to use to heal: ")
print("{}. {}".format(i, item))
valid = False
while not valid:
choice = input("")
try:
to_eat = consumables[int(choice) - 1]
self.hp = min(100, self.hp + to_eat.healing_value)
self.inventory.remove(to_eat)
print("Current HP: {}".format(self.hp))
valid = True
except (ValueError, IndexError):
print("Invalid choice, try again.")
# welcome the user to the game
def say_hello(self, name):
print("Hello, " + name, ", welcome to the world of Yradel.")
# create a function to determine the best weapon
def most_powerful_weapon(self):
max_damage = 0
best_weapon = None
for item in self.inventory:
try:
if item.damage > max_damage:
best_weapon = item
max_damage = item.damage
except AttributeError:
pass
return best_weapon
# create functions to let the player move
def move(self, dx, dy):
self.x += dx
self.y += dy
def move_north(self):
self.move(dx = 0, dy = -1)
def move_east(self):
self.move(dx = 1, dy = 0)
def move_south(self):
self.move(dx = 0, dy = 1)
def move_west(self):
self.move(dx = -1, dy = 0)
# create a function to attack the enemy
def attack(self):
best_weapon = self.most_powerful_weapon()
room = world.tile_at(self.x, self.y)
enemy = room.enemy
print("You use {} against the {}!".format(best_weapon.name, enemy.name))
enemy.hp -= best_weapon.damage
if not enemy.is_alive():
print("You killed {}!".format(enemy.name))
else:
print("{} HP is {}.".format(enemy.name, enemy.hp))
# create a method to allow trade
def trade(self):
room = world.tile_at(self.x, self.y)
room.check_if_trade(self)
It looks like you forgot to set start_tile_location in this function:
start_tile_location = None
# create the function to parse the dsl
def parse_world_dsl():
if not is_dsl_valid(world_dsl):
raise SyntaxError("DSL is invalid!")
dsl_lines = world_dsl.splitlines()
dsl_lines = [x for x in dsl_lines if x]
# iterate over each line in the dsl
# instead of i, the variable y is used because we're working with an X-Y grid.
for y, dsl_row in enumerate(dsl_lines):
# create an object to store the tiles
row = []
# split the line into abbreviations using the "split" method
dsl_cells = dsl_row.split("|")
# the split method includes the beginning and end of the line
# so we need to remove those nonexistent cells
dsl_cells = [ c for c in dsl_cells if c]
# iterate over each cell in the dsl line
# instead of j, the variable x is used becuase we're working with an X-Y grid
for x, dsl_cell in enumerate(dsl_cells):
# look up the abbreviation in the dictionary
tile_type = tile_type_dict[dsl_cell]
# if the dictionary returned a valid type, create a new
# tile object, pass it the X-Y coordinates as required
# by the tile__init__(), and add it to the row object. If
# None was found in the dictionary, we just add None.
row.append(tile_type(x, y) if tile_type else None)
if "S" == dsl_cell:
start_tile_location = (x, y)
# add the whole row to the world_map
world_map.append(row)
I have been programming a piece of code to try and carry through a class from one function to another (the code is also broken in other ways but those aren't the important ones). The major problem if you define a class in the enter function it then gives the error:
exec("""print({}.Show())""".format(x))
File "<string>", line 1, in <module>
NameError: name (whatever I have called the class title) is not defined
in the tr function.
import pickle
import traceback
import sys
classtitles = []
class Customer(object):
def __init__(self):
try:
self.load()
print(self.customer)
except:
None
def init2(self,customer_name,home_address,telephone_number):
self.customer = customer_name
self.address = home_address
self.phone = telephone_number
print(self.customer)
classtitles.append(self.customer)
def carpet_amounts(self, carpet_type, grippers_bool):
self.type = carpet_type
self.grippers = grippers_bool
def price(self, size, perimeter):
self.size = size
self.perimeter = perimeter
self.price = 0
if self.type == "First":
self.price = float(5.99) * self.size
if self.type == "Monarch":
self.price = float(7.99) * self.size
if self.type == "Royal":
self.price = int(60) * self.size
price_add = float(22.5) * self.size
if self.grippers == True:
price_add += self.perimeter * float(1.10)
hours = 0
while size >= 16:
hours += 1
size -= 16
self.hours = hours
price_add += hours * 65
self.price += price_add
def Show(self):
print("show")
if self.grippers == True:
grips = "with"
else:
grips = "without"
return ("the size is {}m^2 and with a {} undercarpet and {} grippers, totalling more than {} hours of work is {}".format(self.size,self.type,grips,self.hours,self.price))
def save(self):
"""save class as self.name.txt"""
file = open('ClassSave.txt','wb')
file.write(pickle.dumps(self.__dict__))
file.close()
def load(self):
"""try load self.name.txt"""
file = open('ClassSave.txt','r')
datapickle = file.read()
file.close()
self.__dict__ = pickle.loads(dataPickle)
def loadf():
f = open('classnames.txt','r')
mylist = f.read().splitlines()
for x in mylist:
exec("""{} = Customer()""".format(mylist[0]))
customs()
def customs():
try1 = input("Would you like to 1. Enter a new customer. 2. View all the customers. 3. Delete an old customer")
if try1 == '1':
enter()
elif try1 == 'q':
sys.exit()
else:
tr()
def enter():
name = input("What is thr customers name (no space i.e. 'JoeBloggs')? ")
address = input("What is their address")
phonenumber = str("What is their phone number")
exec("""{} = Customer()""".format(name))
exec("""{}.init2("{}","{}","{}")""".format(name,name,address,phonenumber))
print(classtitles)
carpet_type = input("What type of carpet would they like ('First','Monarch','Royal')? ")
grips = str(input("Would they like grips (1 = yes, 2 = no)? "))
if grips == '1':
grips = True
else:
grips = False
exec("""{}.carpet_amounts("{}",{})""".format(name,carpet_type,grips))
size = int(input("What is the m^2 size of their carpet? "))
perimeter = int(input("What is the m perimeter of their carpet? "))
exec("""{}.price({},{})""".format(name,size,perimeter))
exec("print({}.Show())".format(name))
file2 = open('classnames.txt','w')
for x in classtitles:
file2.write(x)
file2.close()
exec("{}.save()".format(name))
customs()
def tr():
x = input("name")
print(x)
exec("""print({}.Show())""".format(x))
customs()
loadf()