Created
December 22, 2016 20:53
-
-
Save smythp/caa6e5d8e41c33f136c202ea7907a60d to your computer and use it in GitHub Desktop.
Revisions
-
smythp created this gist
Dec 22, 2016 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,400 @@ # The Fortress of Peril # A very incomplete text adventure # Adapted from some code I wrote to # better learn OOP in Python. The # parser, entities, and loop would # normally be their own modules. # Only look/examine, move, and quit # commands have been implemented. # Requires Python 3 # import readline automatically allows for line # editing and command history with input() import readline debug = False class Room(object): # these are class-level indexes that keep track # of all the rooms that have been created index = [] name_index = {} loc_index = {} # instantiate object and add to class-level indexes def __init__(self, name, description, x, y, z=0, ): if name in Room.name_index: raise KeyError('That name is already in use for another room') if (x, y, z) in Room.loc_index: raise KeyError('That location is already in use for another room') self.contents = [] self.inhabitants = [] self.name = name self.description = description self.x, self.y, self.z = x, y, z # This gives the room a unique value associated with it # Don't need to increment because of how len() works self.index = len(Room.index) self.coordinates = x, y, z self.loc = x, y, z Room.index.append(self) Room.name_index[name] = self Room.loc_index[(x, y, z)] = self Mob.loc_index[self] = [] # return an object based on a query # can take name (str), loc (tuple, or index (int) def lookup(query): if isinstance(query, str): out = Room.name_index[query] return out if isinstance(query, int): out = Room.index[query] return out if isinstance(query, tuple): out = Room.loc_index[query] return out def __repr__(self): return "<%s: Room object located at x=%s, y=%s, z=%s,\ inhabitants=%s, contents=%s>" % (self.name, self.x, self.y, self.z, self.inhabitants, self.contents) def __str__(self): return "<Room: %s>" % self.name # class for creatures in the world, # including player class Mob(object): index = [] name_index = {} loc_index = {} def __init__(self, name, loc, description, inventory=[], health=10, ducats=0): self.name = name self.description = description self.loc = loc self.inventory = inventory self.health, self.ducats = health, ducats self.index = len(Mob.index) Mob.index.append(self) Mob.name_index[name] = self Mob.loc_index[loc].append(self) Mob.index.append(self) self.loc.inhabitants.append(self) # add name to nouns list for parser tokens['nouns'].append(self.name.upper()) # lets you look up an object using index (int), # location (tuple), or name (str) def lookup(query): if isinstance(query, str): out = Mob.name_index[query] return out if isinstance(query, int): out = Mob.index[query] return out if isinstance(query, tuple): out = Mob.loc_index[query] return out # return the room in a given direction def get_room_in_direction(self, direction): if direction not in valid_directions: raise LookupError('Not a valid direction') new_loc = get_direction_loc(self.loc.loc, direction) if new_loc not in Room.loc_index: return False else: return Room.loc_index[new_loc] def move(self, direction): intended_location = self.get_room_in_direction(direction) if intended_location: self.loc.inhabitants.remove(self) self.loc = intended_location self.loc.inhabitants.append(self) return intended_location else: return False def __repr__(self): return "<%s: Mob object located at %s,\ inventory=%s, ducats=%s, health=%s>" % (self.name, self.loc, self.inventory, self.ducats, self.health) def __str__(self): return "<Mob: %s>" % self.name valid_directions = ('NORTH', 'SOUTH', 'EAST', 'WEST', 'UP', 'DOWN', 'NORTHEAST', 'SOUTHEAST', 'NORTHWEST', 'SOUTHWEST',) def full_description(location): "Compile a full description of a location in the game, \ including mobs and objects." output_string = '\n' + player.loc.description + '\n' mob_list = player.loc.inhabitants if len(mob_list) == 1: mob_sighting = 'You see here %s.' % mob_list[0].description elif len(mob_list) == 2: mob_sighting = 'You see here %s and %s.' % (mob_list[0].description, mob_list[1].description) else: mob_sighting = 'You see here' for mob in mob_list[:-1]: mob_sighting += mob.description + ', ' mob_sighting += 'and ' + mob.description + '.' output_string += '\n' + mob_sighting + '\n' return output_string # takes location tuple and string for direction, i.e. "north" # returns new location def get_direction_loc(loc, direction): loc = list(loc) if direction == 'NORTH': modified_loc = loc[0], loc[1] + 1, loc[2] return modified_loc if direction == 'EAST': modified_loc = loc[0] + 1, loc[1], loc[2] return modified_loc if direction == 'SOUTH': modified_loc = loc[0], loc[1] - 1, loc[2] return modified_loc if direction == 'WEST': modified_loc = loc[0] - 1, loc[1], loc[2] return modified_loc if direction == 'UP': modified_loc = loc[0], loc[1], loc[2] + 1 return modified_loc if direction == 'DOWN': modified_loc = loc[0], loc[1], loc[2] - 1 return modified_loc # Lexicon for parser tokens = { 'directions': [ 'NORTH', 'SOUTH', 'EAST', 'WEST', ], 'verbs':[ 'QUIT', 'GO', 'L', 'LOOK', 'RUN', 'WALK', 'EAT', 'KILL', ], 'nouns': [ 'BEAR', 'PRINCESS', ], 'filler':[ 'THE', 'TO', 'AND', 'OF', 'A', 'AN',], } synonyms = { 'L': 'LOOK', 'SCRUTINIZE': 'LOOK', 'EXAMINE': 'LOOK', 'X': 'LOOK', 'N': 'NORTH', 'S': 'SOUTH', 'E': 'EAST', 'W': 'WEST', 'WALK': 'GO', 'MOVE': 'GO', 'RUN': 'GO', 'AMBLE': 'GO', } [token['nouns'].append(item.name) for item in Room.name_index] def check_token_type(token_list, type): "Grab the first token of a particular type from a list of tokens." for token in token_list: if token in tokens[type]: return token return False def replace_synonyms(token_list, synonyms): "Replace all words in a list of tokens with given synonyms." out_list = [] for token in token_list: if token in synonyms: out_list.append(synonyms[token]) else: out_list.append(token) return out_list def remove_filler_words(token_list, filler_list): "Compare token list with list of filler words and remove." for token in token_list: if token in filler_list: token_list.remove(token) return token_list def parse_input(input): output_dictionary = {} input = input.split() input = [token.upper() for token in input] input = replace_synonyms(input, synonyms) input = remove_filler_words(input, tokens['filler']) output_dictionary['verb'] = check_token_type(input, 'verbs') output_dictionary['noun'] = check_token_type(input, 'nouns') output_dictionary['direction'] = check_token_type(input, 'directions') return output_dictionary def command_execute(commands, player): if debug: print(commands) if commands['verb'] == 'QUIT': exit_prompt = input("Are you sure you want to quit the game? ") if exit_prompt.upper() == 'Y' or exit_prompt.upper() == 'YES': exit() if commands['direction'] and not commands['verb'] or commands['verb'] == 'GO': if player.move(commands['direction']): print('You move %s to the %s.' % ( commands['direction'].lower(), player.loc.name)) print(full_description(player.loc.description)) else: print("Sadly, you can't go %s from here." % commands['direction'].lower()) elif commands['verb'] == 'LOOK' and commands['noun']: print("You're looking at " + \ Mob.lookup(commands['noun'].lower()).description + '.') elif commands['verb'] and commands['direction'] and commands['verb'] == 'LOOK': print(entities.player.get_room_in_direction(commands['direction'])) elif commands['verb'] and commands['verb'] == 'LOOK': print(full_description(player.loc)) elif commands['verb'] and commands['verb'] == 'MAP': for location in entities.Room.index: print(location.name, str(location.loc)) else: pass tokens = { 'directions': [ 'NORTH', 'SOUTH', 'EAST', 'WEST', 'NORTHWEST', 'NORTHEAST', 'SOUTHEAST', 'SOUTHWEST', 'UP', 'DOWN', ], 'verbs':[ 'QUIT', 'GO', 'LOOK', ], 'nouns': [ 'SELF', ], 'filler':[ 'THE', 'TO', 'AND', 'OF', 'A', 'AN',], } synonyms = { 'L': 'LOOK', 'SCRUTINIZE': 'LOOK', 'EXAMINE': 'LOOK', 'X': 'LOOK', 'N': 'NORTH', 'S': 'SOUTH', 'E': 'EAST', 'NE': 'NORTHEAST', 'SE': 'SOUTHEAST', 'NW': 'NORTHWEST', 'SW': 'SOUTHWEST', 'W': 'WEST', 'U': 'UP', 'D': 'DOWN', 'WALK': 'GO', 'MOVE': 'GO', 'RUN': 'GO', 'MOVE': 'GO', 'YOURSELF': 'PLAYER', 'SELF': 'PLAYER', } gates = Room('gates', '''After weeks of difficult travel, you have arrived at the gates of the Fortress of Peril. Inside lies the Magical Dingus, the artifact required for your people's salvation...and your own. Adventurer, do you have the temerity to succeed where so many others have fallen? The entrance to the Fortress is to the north.''', 10, 10) antechamber = Room('antechamber', 'This drafty antechamber is filled with tapestries depicting the battles of yore.', 10, 11) player = Mob('player', Room.lookup('gates'), 'yourself') gatekeeper = Mob('gatekeeper', Room.lookup('gates'), "the Fortress's ghoulish gatekeeper") # print room description on game start print() print(full_description(player.loc.description)) # game loop if __name__ == '__main__': while 1: query = input('> ') commands = parse_input(query) command_execute(commands, player)