Answered step by step
Verified Expert Solution
Question
1 Approved Answer
This is in python, this is what I've done so far but I'm stuck on fixing it/having it work. It's a text adventure game. class
This is in python, this is what I've done so far but I'm stuck on fixing it/having it work. It's a text adventure game. class Item: def __init__(self, name, description, calories, weight): if name == '': raise ValueError('Name cannot be blank') if not isinstance(calories, int) or calories 1000: raise ValueError('Calories must be integer between 0 and 1000') if description == '': raise ValueError('Description cannot be blank') if not isinstance(weight, int) or weight 500: raise ValueError('Weight must be integer between 0 and 500') self.name = name self.description = description self.calories = calories self.weight = weight def __str__(self): return f'{self.name} - {self.weight} lb - {self.description}' bread = Item("Bread", "A loaf of fresh bread.", 200, 3) cheese = Item("Cheese", "A chunk of cheddar cheese.", 300, 2) apple = Item("Apple", "A red delicious apple.", 100, 1) chicken = Item("Chicken", "A roasted chicken leg.", 400, 4) sword = Item("Sword", "A rusty sword.", 0, 10) helmet = Item("Helmet", "A metal helmet.", 0, 5) amulet = Item("Amulet", "A golden amulet.", 0, 1) potion = Item("Potion", "A mysterious blue potion.", 0, 1) book = Item("Book", "It's filled with vast knowledge.", 0, 5) pen = Item("Pen", "A tool fro delicate writing", 0, 3) iron_ignot = Item("Iron Ignot", "Great for forging not for eating.", 0, 10) hammer = Item("Hammer", "The BlackSmith mighty tool!.", 0, 15) class NPC: def __init__(self, name, description, messages): self.name = name self.description = description self.messages = messages self.message_number = 0 def get_name(self): return self.name def get_description(self): return self.description def get_message(self): message = self.messages[self.message_number] self.message_number = (self.message_number + 1) % len(self.messages) return message def __str__(self): return self.name queen = NPC("Queen", "The regal queen of the castle.", ["Hello adventurer, what brings you to my castle?", "I hope you are enjoying your stay here.", "Please don't cause any trouble during your visit."]) king = NPC("King", "The mighty king of the castle.", ["Greetings adventurer, how may I assist you?", "I hope you find everything you need here.", "Remember to show respect to all the residents of the castle."]) guard = NPC("Guard", "A burly guard blocking your way.", ["Halt, who goes there?", "I need to see your business here.", "Move along now, there's nothing to see here."]) princess = NPC("Princess", "A beautiful princess.", ["Hello handsome, are you lost?", "Please do not wander too far, it can be dangerous.", "I hope you find what you are looking for."]) goblin = NPC("Goblin", "A hungry goblin.", ["Gimme food!", "More food!", "So hungry..."]) blacksmith = NPC("Blacksmith", "A man with great knowledge in forging", ["Hello! Would you like a sword?", "Well I don't have one","The darn goblin ate my materials!"]) class Location: def __init__(self, name, description): self.name = name self.description = description self.visited = False self.neighbors = {} self.npcs = [] self.items = [] def get_locations(self): return self.neighbors def add_location(self, direction, location): if direction == '': raise ValueError('Direction cannot be blank') if direction in self.neighbors: raise KeyError('Key already exists in dictionary') self.neighbors[direction] = location def add_npc(self, npc): self.npcs.append(npc) def get_npcs(self): return self.npcs def add_item(self, item): self.items.append(item) def get_items(self): return self.items def set_visited(self): self.visited = True def get_visited(self): return self.visited def __str__(self): return f'{self.name} - {self.description}' throne_room = Location("Throne Room", "The grand throne room of the castle where the king and queen reside. There are 2 large thrones at the end of the room.") throne_room.add_npc(queen) throne_room.add_npc(king) throne_room.add_item(bread) dining_hall = Location("Dining Hall", "A large hall filled with long tables and chairs. The smell of cooked food fills the air.") dining_hall.add_npc(guard) dining_hall.add_item(cheese) dining_hall.add_item(chicken) garden = Location("Garden", "A beautiful garden filled with colorful flowers and a fountain.") garden.add_npc(princess) garden.add_item(apple) armory = Location("Armory", "A room filled with weapons and armor.") armory.add_item(sword) armory.add_item(helmet) wizard_tower = Location("Wizard's Tower", "A tall tower filled with books and potions.") wizard_tower.add_item(amulet) wizard_tower.add_item(potion) goblin_room = Location("Goblin Room", "A small room with a goblin.") goblin_room.add_npc(goblin) throne_room = Location("Throne Room", "The grand throne room of the castle where the king and queen reside. There are 2 large thrones at the end of the room.") throne_room.add_npc(queen) throne_room.add_npc(king) throne_room.add_item(bread) dining_hall = Location("Dining Hall", "A large hall filled with long tables and chairs. The smell of cooked food fills the air.") dining_hall.add_npc(guard) dining_hall.add_item(cheese) dining_hall.add_item(chicken) garden = Location("Garden", "A beautiful garden filled with colorful flowers and a fountain.") garden.add_npc(princess) garden.add_item(apple) armory = Location("Armory", "A room filled with weapons and armor.") armory.add_item(sword) armory.add_item(helmet) wizard_tower = Location("Wizard's Tower", "A tall tower filled with books and potions.") wizard_tower.add_item(amulet) wizard_tower.add_item(potion) goblin_room = Location("Goblin Room", "A small room with a goblin.") goblin_room.add_npc(goblin) library = Location("Library", "A room filled with books and knowledge.") library.add_item(book) library.add_item(pen) blacksmith = Location("Blacksmith", "A room filled with fire, iron, and the sounds of hammering.") blacksmith.add_npc(blacksmith) blacksmith.add_item(iron_ignot) blacksmith.add_item(hammer) class Game: def __init__(self): self.commands = self.setup_commands() self.player_items = [] self.player_weight = 0 self.goblin_calories = 0 self.current_location = None def setup_commands(self) -> Dict[str, Callable]: commands = { 'help': self.show_help, 'go': self.move, 'pick up': self.pick_up, 'talk': self.talk, 'drop': self.drop, 'check inventory': self.check_inventory, 'check weight': self.check_weight, 'look': self.look, 'quit': self.quit } return commands def show_help(self): now = datetime.datetime.now() current_time = now.strftime("%Y-%m-%d %H:%M:%S") self.setup_commands() print(f"Current time: {current_time} he available commands are: " f"{', '.join(self.commands.keys())}") def look(self): if not self.player_location.visited: print(f"You are currently at the {self.player_location.name} {self.player_location.description}.") elif self.player_location.visited == True: print(f"You are back at the {self.player_location.name} {self.player_location.description}.") print('NPCs in this location:') for npc in self.player_location.npcs: print(npc) print('Items in this location:') for item in self.player_location.items: print(item) for direction, location in self.player_location.neighbors.items(): print(f"You can go: {direction}: {location.name}") def check_weight(self) -> None: total_weight = sum(i.weight for i in self._inventory) print(f"The total weight of the items in your inventory is {total_weight}") if total_weight > 30: print("You are carrying too much weight.") def update_weight(self, item): self.player_weight += item.weight def update_calories(self, item): self.goblin_calories += item.calories def pick_up(self, item): self.player_items.append(item) self.update_weight(item) self.update_calories(item) def check_inventory(self): if not self.player_inventory: return "Your inventory is empty." item_strings = [str(item) for item in self.player_inventory] return "Inventory: " + " ".join(item_strings) def drop(self, item): self.player_items.remove(item) self.player_weight -= item.weight self.elf_calories -= item.calories def move(self, location): self.current_location = location print(f"You are now in the {location.name}.") print(location.description) def talk(self, name): for npc in self.npcs: if npc.get_name().lower() == name.lower(): return npc.get_message() return "Invalid command" def give_food(item): global inventory, npcs, locations, current_location if item in inventory: inventory.remove(item) calories = items[item]["calories"] npcs["Goblin"]["calories"] += calories if calories == 0: print("The goblin takes your item, but it has no calories. Suddenly, you feel dizzy...") current_location = random.choice(list(locations.values())) print(f"You have been teleported to {current_location.name}.") else: print(f"You gave the goblin {item}, which has {calories} calories. The goblin now has {npcs['Goblin']['calories']} calories.") if npcs["Goblin"]['calories'] >= 500: npcs.pop("Goblin") print("The goblin is now full and has left the castle in peace.") else: print("You do not have that item in your inventory.") def play(self): print("A goblin is making a mess of the castle! It refuses to leave until it's belly is full!") self.show_help() while True: action = input("What will you like to do? ") if action in self.commands: self.commands[action]() else: print(f"Unknown action: {action}") def quit(self): pass
These are the instructions I'm trying to follow:
Item An Item represents objects the player may encounter along the way, and is an object that has a name, a description, the number of calories it can provide ( 0 if it isn't edible), and a weight. It must provide: - A constructor that can take a name, description, calories, and weight. - You must ensure the following: - the name variable cannot be blank. Raise a ValueError with an appropriate message if a blank string is passed in. - the calorie variable cannot be less than 0 or more than 1000 and must be an int. the description cannot be blank. - the weight must be an int and must be between 0 and 500 . - A __str_ method that returns a string representing the Item. The format should be NAME - X Ib - DESCRIPTION, i.e. Rusty Nail - 1lb - A rusty nail (I hope you've had a tetanus shot) The NPC class represents information about a character that can be in a Location. An NPC has a name, description, message number, and list of messages. Each time the player speaks to an NPC, the message number should increase by 1 , resulting in the next message in the list being printed the next time the player speaks to the character. The message number should go back to 0 after it goes past the length of the message list. The class must have: - a constructor that accepts a name and a description - - getters for name and description - a getter for a message that returns the current message (as indicated by message number), then changes the message number appropriately - a __str__(self) -> str method that returns only the name of the NPC Each Location represents a place on campus that may be visited. A location holds a name, a description, a bool that indicates if it has been yet visited, a dictionary of neighbors, a list of NPCs, and a list of items. The neighbors dictionary will have a key that is a direction, that refers to a Location as its value. For instance, if we have a Location called zumberg and another Location called kirkhoff, zumberg would have a dictionary entry "west" that holds kirkhoff. We then want kirkhoff to hold in its dictionary a key-value pair of "east" that refers to zumberg. If we want to have two locations attached such that the player can enter but not exit the way they came, we can merely leave the entry off one of the objects. For instance, we could have a portal Location that has a "through" key pointing to zumberg but no corresponding key-value pair in the zumberg neighbor dictionary. Location must implement: - a constructor that takes a name and description - a get_locations function that returns the neighbors dictionary - an add_location(self, direction: str, location: 'Location') > None method. This function will add the location into the dictionary with the provided direction string. If the string is blank, raise a ValueError. If the key already exists in the dictionary, raise a KeyError. - an add_npc(self, npc: NPC) method for adding an NPC to the Location's list, and a get_npcs(self) -> List[NPC] function that returns the list of NPCs. - an add_item(self, item: Item) method for adding an Item to the Location's NPC list, and a get_items(self) -> List[Item] method to return the Items. - a set_visited(self) -> None method that changes the visited variable to True. Once a location is visited, it can no longer be False. Also, include a get_visited(self) -> bool function for checking if the location has been visited. a __str_ method that returns the name and description formatted as NAME - DESCRIPTION The game takes place in a world of connected locations. The purpose of the game is to collect edible items and then bring them to the elf in the woods behind campus. The elf needs 500 calories of edible food before it will save GVSU. Each item can have 0 or more calories. If a player gives the elf something inedible (something with 0 calories), the elf will be displeased and will teleport the player to a random location in the world. The player can only carry 30 pounds at a time, so multiple trips to the elf may be needed. Once the elf has enough calories, it will save campus and the game will end. The Game class holds all the logic for a game instance. This class will hold several pieces of data. Make sure it has - a dictionary of commands - a list of Items the player currently has in their inventory - an int that holds the current weight the player is carrying - a list of Locations that exist in the world - a variable to hold the player's current location - an int to hold the number of calories the elf needs before it will save the campus - a bool to store whether the game is still in progress Game will adhere to the Command Pattern. Instead of having a loop body with a large number of if statements, for instance command = input("What is your command? ") if command == 'help': self._help() elif command == 'talk': self._talk() elif command == 'go': self.move() ... On and on ... elif command = 'quit': self.quit() We can instead create a data structure that maps commands to functions. Python makes this simple with dictionaries. We could for instance do something like this: self._commands ={ 'help': self.show_help, 'talk': self.talk, ... and so on ..., 'quit': self.quit \} In this example, the values of the dictionary (i.e. self._show_help, self.talk, and self.quit) are the names of functions. Note that we are not calling the functions by putting the parentheses after the name (we didn't type self.quit() for example); we are merely giving the name of the method. Now, our input loop can look something like command = input("What is your command? ") self._commands[command]() Notice here that we did use the parentheses to call the function. We can do this because Python supports first-class function. This simply means that a function can be used just like any other piece of data. For instance, we can store a function in a list or dictionary (as we did here), or we could pass a function as a parameter to another function. The Command Pattern allows us to abstract away all of the if statements. We merely call the function that corresponds with the typed command (if one exists). Note that we can check if the command is a key of our dictionary with the in keyword: if input in self._commands: ... do something ... The Game class will require the most code to be written. It needs - a constructor that takes no parameters (other than self). The constructor will set the commands dictionary equal to the return call from our setup_commands function. It will call the create_world method. It will then set default values for all other variables. Set the current location to a random location selected from the random_location method. a create_world(self) -> None method that creates all the Locations, Items, and NPCs in the game. This function can get messy, as it will have a lot of text for names and descriptions of objects. Remember that your code should not be more than 72 characters long (this is marked in PyCharm with a vertical line). If a line goes beyond that, you should separate it into more than one line. You can do this by splitting the string: kirkhoff_upstairs = Location("kirkhoff upstairs", "The student union. There are restaurants, a store, and places to congregate.") becomes kirkhoff_upstairs = Location("kirkhoff upstairs", "The student union. There are restaurants, a store, and " - "places to congregate.") This implicitly concatenates the two strings together, so formatting this way poses no issues. In this function you will need to add all Items and NPCs to the rooms in which they belong, as well as add each Location to the neighbors to which it needs to connect. Also, be sure to add each Location to the self._locations list. Because there will be so much setup code, you may wish to break the function into commented regions, wherein each region focuses on the creation and setup of a single Location. Your game needs at least 8 Locations. There is no requirement for how many Items and NPCs must be in each Location, but your game does need at least 10 Items and 5 NPCs. - a setup_commands(self) -> Dict[str, Callable] method. This method will create a new dictionary. The keys will be a command such as talk, give, go, etc. The values of the dictionary will be the names of the functions that should be called for each of those commands. Note that we can have more than one command per function; for instance, we could have both "?" and "help" correspond to a self.show_help method. Be sure this function returns the dictionary. - a random_location(self) Location method that selects a random Location from the locations list and returns that Location. - a play(self) -> None method. This is the core game loop. It should first print a message describing the game, then call the method to list all commands. Then, while the game is still in progress, it will loop. In the loop, we will prompt the user for a command. The user may enter multiple words in a prompt. We will split the user's input into a list of words. We can split on spaces with code tokens = user_response.split(). Once we have the tokens list, create a variable called command and set it equal to the first element in the list. Then, remove the first element with the del(tokens[0]) command. Then, use the code target = ' '.join(tokens) code to put the remaining tokens together. Thus, if the user enters talk ball of light then command will be equal to talk, and target will be ball of light We will then call the function from the commands dictionary by using this key. Pass target as a parameter to the called function. If the command does not exist in the dictionary print a message to the user telling them so. Once the loop ends (i.e. the in-progress variable is False), check if the elf got enough calories. If it did, print a success message and quit. Otherwise, print a failure message and quit. - a show_help(self) method that prints out a help message and all the commands from the command dictionary's keys. This method must also post the current time. You will need to read the datetime documentation to do this - https://docs.python.org/3/library/datetime.html. Print the time in a nicely formatted string, but you can decide if you wish to use 12 or 24 -hour time. - a talk(self, target) None method. This method will check if the provided NPC is in the current room. If it is, it will call the NPC's get_message method and print the resulting message. - a meet(self, target) -> None method. It will check if the NPC is in the room, and if it is will ask the NPC for its description and print it. - a take(self, target) -> None method. If the target item is in the room it will remove it from the room's inventory, add it to the user's inventory, and add the weight of the item to the user's carried weight. - a give(self, target) -> None method. Removes the target item (if it exists) from the user's inventory, adds it to the current location's inventory and decreases the user's carried weight. The function will then check if the current location is the woods. If it is, it will check if the item given was edible. If the item is edible, reduce the number of calories the item has from the total the elf needs. If the item was not edible, transport the player to a new location by setting the current location equal to the return from random_location. - a go(self, target) -> None method. Sets the current location's visited status to True. Checks if the player has over 30 weight; prints a message and returns if so. Otherwise, it checks if provided direction exists in the current location's neighbor dictionary. If so, sets the current location equal to the value from the dictionary. - a show_items(self, args: str = None) -> None method. This method doesn't need any parameters but has an args parameter so it can be called with the same syntax as the other commands. It should print all items the player is carrying, and the current amount of weight carried. - a look(self, args: str = None) -> None method. This method doesn't need parameters either but has args for the same reason as given above. This method will print the current location, a list of Items in the location or a message indicating there are none, a list of NPCs in the room or the message "You are alone.", and a list of directions in which the player can go. If a location has been visited previously, print the direction and the location. Otherwise, simply print the direction. - a quit(self, args: str = None) -> None method that prints a failure message and exits the game. - two additional command functions that you design and create. You could add teleportation, magic, etc
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started