def __init__(self, library_path, prompt_func=input, print_func=print): self.prompt_char = ">" self.library_path = library_path self.reset_game() self.interface = CommandLine(self, prompt_func, print_func) self.bag = Bag() self.level = None self.player = None self.player_in_room = None self.room = None for direction in ("north", "south", "east", "west"): while not self.add_direction_to_commands(direction): pass
9: ("Outpost", 3), 10: ("Outpost", 3), 11: ("Monastery", 2), 12: ("Monastery", 3), 13: ("Harbour", 4), 14: ("Harbour", 3), 15: ("Harbour", 4), 16: ("Outpost", 4), 17: ("Outpost", 3), 18: ("Harbour", 3), 19: ("Harbour", 4), 20: ("Harbour", 4), 21: ("Harbour", 4), 22: ("Harbour", 3), 23: ("Harbour", 4) } if fieldOfFame: location_pool[24] = ("Township", 4) location_pool[25] = ("Township", 3) location_pool[26] = ("Township", 4) return pool, location_pool pool, location_pool = raiders_config_menu() bag = Bag(pool) board = Board(location_pool, bag) board.report()
def setup_method(self, method): self.bag = Bag()
class TestBag: def setup_method(self, method): self.bag = Bag() def teardown_method(self, method): self.bag = None def bag_n_dump(self, name): item = Item(name) self.bag.add(item) return self.bag.dump() def test_check_if_bag_object(self): assert type(self.bag) is Bag def test_check_if_item_object(self): assert Item in Bag.__bases__ def test_check_if_name_description_can_be_assigned(self): self.bag.name = "The Bag" self.bag.description = "for carrying" assert self.bag.name == "The Bag" assert self.bag.description, "for carrying" def test_can_check_bag_to_see_if_empty(self): assert self.bag.is_empty() def test_can_return_item_count_when_empty(self): assert self.bag.item_count() == 0 def test_after_adding_item_bag_is_no_longer_empty(self): item = Item("rock") self.bag.add(item) assert not self.bag.is_empty() def test_can_add_item_to_bag(self): assert self.bag.item_count() == 0 item = Item("thing") self.bag.add(item) assert self.bag.item_count() == 1 def test_dumped_pile_has_count(self): pile = self.bag_n_dump("fuzz") assert len(pile) == 1 fuzz = pile["fuzz"] assert fuzz["count"] == 1 def test_dumped_pile_has_name(self): pile = self.bag_n_dump("cheese") cheese = pile["cheese"] assert cheese["name"] == "cheese" def test_dumped_pile_has_item(self): pile = self.bag_n_dump("Amulet of Wendor") amulet = pile["Amulet of Wendor"] item = amulet["item"] assert type(item) is Item def test_can_look_in_bag(self): stick = Item("stick") self.bag.add(stick) seen = self.bag.look() assert "1 stick" in seen def test_can_fund_how_many_of_an_item_are_in_bag(self): planet = Item("planet") self.bag.add(planet) self.bag.add(planet) assert 2 == self.bag.how_many("planet") def test_how_many_handles_no_items_of_type(self): assert self.bag.how_many("jabberwocky") == 0 def test_adding_multiple_of_the_same_item_increases_item_count(self): butter = Item("butter") self.bag.add(butter) self.bag.add(butter) assert 2 == self.bag.item_count() self.bag.add(butter) assert 3 == self.bag.item_count() def test_can_add_many(self): turtle = Item("turtle") self.bag.add_many(turtle, 5) assert 5 == self.bag.how_many("turtle") assert 5 == self.bag.item_count() def test_can_remove_an_item(self): self.bag.add(Item("cheezburger")) removed_count, item = self.bag.remove("cheezburger") assert 1 == removed_count assert "cheezburger" == item.name assert type(item) is Item assert 0 == self.bag.how_many("cheezburger") def test_cannot_remove_an_item_that_is_not_there(self): removed_count, item = self.bag.remove("Kaiser Soze") assert 0 == removed_count assert item == None assert 0 == self.bag.how_many("Kaiser Soze") def test_removed_items_behave_like_items_that_never_existed(self): self.bag.add(Item("smoke")) removed_count, item = self.bag.remove("smoke") assert 1 == removed_count removed_count, item = self.bag.remove("smoke") assert 0 == removed_count assert item == None assert 0 == self.bag.how_many("smoke") assert 0 == self.bag.item_count() def test_remove_many_items_from_bag_at_once(self): self.bag.add_many(Item("blind mouse"), 5) removed_count, item = self.bag.remove_many("blind mouse", 3) assert 3 == removed_count assert 2 == self.bag.how_many("blind mouse") assert "blind mouse" == item.name def test_remove_many_items_will_remove_only_as_many_as_exist(self): self.bag.add_many(Item("rhymes"), 5) removed_count, item = self.bag.remove_many("rhymes", 7) assert 5 == removed_count assert 0 == self.bag.how_many("rhymes") assert "rhymes" == item.name assert self.bag.isEmpty() def test_adding_multiple_of_the_same_item_increases_item_count(self): butter = Item("butter") self.bag.add(butter) self.bag.add(butter) assert 2 == self.bag.item_count() self.bag.add(butter) assert 3 == self.bag.item_count() def test_can_remove_an_item(self): self.bag.add(Item("cheezburger")) removed_count, item = self.bag.remove("cheezburger") assert 1 == removed_count assert "cheezburger" == item.name assert type(item) is Item assert 0 == self.bag.how_many("cheezburger") def test_cannot_remove_an_item_that_is_not_there(self): removed_count, item = self.bag.remove("Kaiser Soze") assert 0 == removed_count assert item == None assert 0 == self.bag.how_many("Kaiser Soze") def test_removed_items_behave_like_items_that_never_existed(self): self.bag.add(Item("smoke")) removed_count, item = self.bag.remove("smoke") assert 1 == removed_count removed_count, item = self.bag.remove("smoke") assert 0 == removed_count assert item == None assert 0 == self.bag.how_many("smoke") assert 0 == self.bag.item_count() def test_remove_many_items_from_bag_at_once(self): self.bag.add_many(Item("blind mouse"), 5) removed_count, item = self.bag.remove_many("blind mouse", 3) assert 3 == removed_count assert 2 == self.bag.how_many("blind mouse") assert "blind mouse" == item.name def test_remove_many_items_will_remove_only_as_many_as_exist(self): self.bag.add_many(Item("rhymes"), 5) removed_count, item = self.bag.remove_many("rhymes", 7) assert 5 == removed_count assert 0 == self.bag.how_many("rhymes") assert "rhymes" == item.name
class Engine: """This class ties it all together and might be viewed as something somewhat akin to a controller in an MVC framework. """ def __init__(self, library_path, prompt_func=input, print_func=print): self.prompt_char = ">" self.library_path = library_path self.reset_game() self.interface = CommandLine(self, prompt_func, print_func) self.bag = Bag() self.level = None self.player = None self.player_in_room = None self.room = None for direction in ("north", "south", "east", "west"): while not self.add_direction_to_commands(direction): pass # The heart of what we want to do within this while loop is contained within # The add_direction_to_commands function. We just want to keep calling it # until it returns True. def start(self): """Use this method to start the game""" player_name = self.interface.greet() self.player = Player(player_name) self.interface.display(initial_narration()) self.init_level() self.interface.display(self.level.draw_map()) def init_level(self): """Looks up the level information from file, loads it and inserts the player into the room. """ self.room = LevelLoader(self.library_path, self.room_file) self.level = self.room.enter(self.player, "entrance") self.player_in_room = True self.interface.display(self.room.room_description()) def reset_game(self): """Returns the game to its initial state""" self.room_file = "level_1.json" self.player_in_room = False def in_room(self): """Used to determine if the player is currently in a room""" if self.player == None: return False return self.player.in_room() def load_player(self, player): """Attribute setter for the player""" self.player = player def north(self): """Moves the player north if able""" if not self.level.can_go_north(self.player): self.interface.display("You cannot go north") else: for creature in self.level.get_move_ai(): if creature.coords == (self.player.coords[0], self.player.coords[1] + 1): self.attack(creature) break else: self.player.travel("n") def south(self): """Moves the player south if able""" if not self.level.can_go_south(self.player): self.interface.display("You cannot go south") else: for creature in self.level.get_move_ai(): if creature.coords == (self.player.coords[0], self.player.coords[1] - 1): self.attack(creature) break else: self.player.travel("s") def east(self): """Moves the player east if able""" if not self.level.can_go_east(self.player): self.interface.display("You cannot go east") else: for creature in self.level.get_move_ai(): if creature.coords == (self.player.coords[0] + 1, self.player.coords[1]): self.attack(creature) break else: self.player.travel("e") def west(self): """Moves the player west if able""" if not self.level.can_go_west(self.player): self.interface.display("You cannot go west") else: for creature in self.level.get_move_ai(): if creature.coords == (self.player.coords[0] - 1, self.player.coords[1]): self.attack(creature) break else: self.player.travel("w") def attack(self, enemy): dmg = self.player.weapon.damage self.interface.display("You attack the " + enemy.name + " for " + str(dmg) + " damage!") response = enemy.take_damage(dmg) enemy.set_target(self.player) if response: self.interface.display(response) for index, item in enumerate(self.level.contents): if item is enemy: self.level.remove(enemy.name) def exit(self): """Tests for exit conditions and exits the player if they are met The length of this method suggests that it is ripe for splitting these actions into separate methods """ can_exit = self.level.exit(self.player) if can_exit: self.display_exit_message() if not self.enter_next_level(): self.player_in_room = False self.interface.display_end_of_game() else: format_string = "Sorry, you are not at an exit of {0}." message = format_string.format(self.room.name) self.interface.display(message) return can_exit def display_exit_message(self): """Displays the level's exit text to the user if it exists""" if self.room.exit_text == None: self.interface.display("You have exited {0}".format( self.room.name)) elif self.room.exit_text == "final" and "bacon" in self.bag.items: self.interface.display(final_narration_win()) elif self.room.exit_text == "final" and "bacon" not in self.bag.items: self.interface.display(final_narration_lose()) else: self.interface.display(self.room.exit_text) def enter_next_level(self): """Transports the player to the next level or returns False if there is no next level """ next_level, has_next_level = self.room.enter_next_level(self.player) if has_next_level: self.level = next_level self.interface.display(self.room.room_description()) return True return False def item_count(self): """Displays the player's inventory""" self.interface.display(self.bag.look()) def coordinates(self): """Returns the x, y coordinates of the player""" coords = self.player.locate() message = "Your co-ordinates are: ({0},{1})".format( coords[0], coords[1]) self.interface.display(message) def vaccum_key_and_gold(self): """Automagically picks up gold and keys""" if self.pick_up_item("key"): self.interface.display("You picked up the key!") if self.pick_up_item("gold"): self.interface.display("You picked up the gold!") if self.pick_up_item("bacon"): self.interface.display("You picked up the bacon!") def vaccum_weapons(self): """Swiftly picks up Excalibur""" if self.pick_up_item("excalibur"): self.interface.display("Behold! The most power ever felt!") def pick_up_item(self, item): """Allows the player to pick up and item by removing an item from the room and placing it in their bag """ if self.level.get_by_name(item) != None: player_coord = self.player.locate() item_coord = self.level.get_by_name(item).locate() if player_coord == item_coord: self.bag.add(Item(item)) self.level.remove(item) return True return False def display_help(self): """Displays the help menu""" self.interface.display_help(self.in_room()) def invalid_command(self): """Displays a message that tells the user their command was invalid""" self.interface.display("Sorry that command is not valid.") self.interface.display( "Please type 'help' and press enter for a menu.") def main_loop(self): """This is the core game loop that cycles through the turns""" play = True self.start() while play: play = self.move_player() if self.in_room(): self.vaccum_key_and_gold() self.vaccum_weapons() play &= self.move_creatures() if play: self.interface.display(self.level.draw_map()) self.interface.display(self.player.show_health()) def move_player(self): """Gets the command from the player and moves (or quits)""" command = self.interface.prompt(self.prompt_char).lower() possible_commands = self.interface.current_commands(self.in_room()) if command == "q": return False else: if not self.execute_command(command, possible_commands): self.invalid_command() return True def execute_command(self, command, commands): """Executes the command if valid, returns false if invalid""" try: cmd_tuple = commands[command] cmd_tuple[0]() return True except KeyError: return False def move_creatures(self): """Moves the creatures in the room""" creatures = self.level.get_move_ai() for creature in creatures: target_tile = next_tile(creature.coords, creature.target) if target_tile == self.player.coords: dmg = creature.weapon.damage self.interface.display("You were attacked by the " + creature.name + " for " + str(dmg) + " damage!") response = self.player.take_damage(dmg) if response: self.interface.display(response) return False else: creature.move() return True def add_direction_to_commands(self, direction): if not hasattr(self, direction): self.interface.display("That is not a valid direction") return False response = self.interface.prompt( "Please choose a key to be your {} movement: ".format(direction)) if response in self.interface.command_mapping: self.interface.display("That key is already in use to {}".format( self.interface.command_mapping[response][1])) return False self.interface.command_mapping[response] = (getattr( self, direction), "move {}".format(direction), False) return True
def __init__(self, contents, size): self.size = size self.contents = contents self.bag = Bag()
class TestBag: def setup_method(self, method): self.bag = Bag() def teardown_method(self, method): self.bag = None def bag_n_dump(self, name): item = Item(name) self.bag.add(item) return self.bag.dump() def test_check_if_bag_object(self): assert type(self.bag) is Bag def test_check_if_item_object(self): assert Item in Bag.__bases__ def test_check_if_name_description_can_be_assigned(self): self.bag.name = "The Bag" self.bag.description = "for carrying" assert self.bag.name == "The Bag" assert self.bag.description, "for carrying" def test_can_check_bag_to_see_if_empty(self): assert self.bag.is_empty() def test_can_return_item_count_when_empty(self): assert self.bag.item_count() == 0 def test_after_adding_item_bag_is_no_longer_empty(self): item = Item("rock") self.bag.add(item) assert not self.bag.is_empty() def test_can_add_item_to_bag(self): assert self.bag.item_count() == 0 item = Item("thing") self.bag.add(item) assert self.bag.item_count() == 1 def test_dumped_pile_has_count(self): pile = self.bag_n_dump('fuzz') assert len(pile) == 1 fuzz = pile['fuzz'] assert fuzz["count"] == 1 def test_dumped_pile_has_name(self): pile = self.bag_n_dump('cheese') cheese = pile['cheese'] assert cheese["name"] == "cheese" def test_dumped_pile_has_item(self): pile = self.bag_n_dump('Amulet of Wendor') amulet = pile['Amulet of Wendor'] item = amulet['item'] assert type(item) is Item def test_can_look_in_bag(self): stick = Item("stick") self.bag.add(stick) seen = self.bag.look() assert "1 stick" in seen def test_can_fund_how_many_of_an_item_are_in_bag(self): planet = Item("planet") self.bag.add(planet) self.bag.add(planet) assert 2 == self.bag.how_many("planet") def test_how_many_handles_no_items_of_type(self): assert self.bag.how_many("jabberwocky") == 0 def test_adding_multiple_of_the_same_item_increases_item_count(self): butter = Item("butter") self.bag.add(butter) self.bag.add(butter) assert 2 == self.bag.item_count() self.bag.add(butter) assert 3 == self.bag.item_count() def test_can_add_many(self): turtle = Item("turtle") self.bag.add_many(turtle, 5) assert 5 == self.bag.how_many("turtle") assert 5 == self.bag.item_count() def test_can_remove_an_item(self): self.bag.add(Item("cheezburger")) removed_count, item = self.bag.remove("cheezburger") assert 1 == removed_count assert "cheezburger" == item.name assert type(item) is Item assert 0 == self.bag.how_many("cheezburger") def test_cannot_remove_an_item_that_is_not_there(self): removed_count, item = self.bag.remove("Kaiser Soze") assert 0 == removed_count assert item == None assert 0 == self.bag.how_many("Kaiser Soze") def test_removed_items_behave_like_items_that_never_existed(self): self.bag.add(Item("smoke")) removed_count, item = self.bag.remove("smoke") assert 1 == removed_count removed_count, item = self.bag.remove("smoke") assert 0 == removed_count assert item == None assert 0 == self.bag.how_many("smoke") assert 0 == self.bag.item_count() def test_remove_many_items_from_bag_at_once(self): self.bag.add_many(Item("blind mouse"), 5) removed_count, item = self.bag.remove_many("blind mouse", 3) assert 3 == removed_count assert 2 == self.bag.how_many("blind mouse") assert "blind mouse" == item.name def test_remove_many_items_will_remove_only_as_many_as_exist(self): self.bag.add_many(Item("rhymes"), 5) removed_count, item = self.bag.remove_many("rhymes", 7) assert 5 == removed_count assert 0 == self.bag.how_many("rhymes") assert "rhymes" == item.name assert self.bag.isEmpty() def test_adding_multiple_of_the_same_item_increases_item_count(self): butter = Item("butter") self.bag.add(butter) self.bag.add(butter) assert 2 == self.bag.item_count() self.bag.add(butter) assert 3 == self.bag.item_count() def test_can_remove_an_item(self): self.bag.add(Item("cheezburger")) removed_count, item = self.bag.remove("cheezburger") assert 1 == removed_count assert "cheezburger" == item.name assert type(item) is Item assert 0 == self.bag.how_many("cheezburger") def test_cannot_remove_an_item_that_is_not_there(self): removed_count, item = self.bag.remove("Kaiser Soze") assert 0 == removed_count assert item == None assert 0 == self.bag.how_many("Kaiser Soze") def test_removed_items_behave_like_items_that_never_existed(self): self.bag.add(Item("smoke")) removed_count, item = self.bag.remove("smoke") assert 1 == removed_count removed_count, item = self.bag.remove("smoke") assert 0 == removed_count assert item == None assert 0 == self.bag.how_many("smoke") assert 0 == self.bag.item_count() def test_remove_many_items_from_bag_at_once(self): self.bag.add_many(Item("blind mouse"), 5) removed_count, item = self.bag.remove_many("blind mouse", 3) assert 3 == removed_count assert 2 == self.bag.how_many("blind mouse") assert "blind mouse" == item.name def test_remove_many_items_will_remove_only_as_many_as_exist(self): self.bag.add_many(Item("rhymes"), 5) removed_count, item = self.bag.remove_many("rhymes", 7) assert 5 == removed_count assert 0 == self.bag.how_many("rhymes") assert "rhymes" == item.name
class Engine: """This class ties it all together and might be viewed as something somewhat akin to a controller in an MVC framework. """ def __init__(self, library_path, prompt_func=input, print_func=print): self.prompt_char = ">" self.library_path = library_path self.reset_game() self.interface = CommandLine(self, prompt_func, print_func) self.bag = Bag() self.level = None self.player = None self.player_in_room = None self.room = None for direction in ("north", "south", "east", "west"): while not self.add_direction_to_commands(direction): pass # The heart of what we want to do within this while loop is contained within # The add_direction_to_commands function. We just want to keep calling it # until it returns True. def start(self): """Use this method to start the game""" player_name = self.interface.greet() self.player = Player(player_name) self.interface.display(initial_narration()) self.init_level() self.interface.display(self.level.draw_map()) def init_level(self): """Looks up the level information from file, loads it and inserts the player into the room. """ self.room = LevelLoader(self.library_path, self.room_file) self.level = self.room.enter(self.player, "entrance") self.player_in_room = True self.interface.display(self.room.room_description()) def reset_game(self): """Returns the game to its initial state""" self.room_file = "level_1.json" self.player_in_room = False def in_room(self): """Used to determine if the player is currently in a room""" if self.player == None: return False return self.player.in_room() def load_player(self, player): """Attribute setter for the player""" self.player = player def north(self): """Moves the player north if able""" if not self.level.can_go_north(self.player): self.interface.display("You cannot go north") else: for creature in self.level.get_move_ai(): if creature.coords == (self.player.coords[0], self.player.coords[1] + 1): self.attack(creature) break else: self.player.travel("n") def south(self): """Moves the player south if able""" if not self.level.can_go_south(self.player): self.interface.display("You cannot go south") else: for creature in self.level.get_move_ai(): if creature.coords == (self.player.coords[0], self.player.coords[1] - 1): self.attack(creature) break else: self.player.travel("s") def east(self): """Moves the player east if able""" if not self.level.can_go_east(self.player): self.interface.display("You cannot go east") else: for creature in self.level.get_move_ai(): if creature.coords == (self.player.coords[0] + 1, self.player.coords[1]): self.attack(creature) break else: self.player.travel("e") def west(self): """Moves the player west if able""" if not self.level.can_go_west(self.player): self.interface.display("You cannot go west") else: for creature in self.level.get_move_ai(): if creature.coords == (self.player.coords[0] - 1, self.player.coords[1]): self.attack(creature) break else: self.player.travel("w") def attack(self, enemy): dmg = self.player.weapon.damage self.interface.display("You attack the " + enemy.name + " for " + str(dmg) + " damage!") response = enemy.take_damage(dmg) enemy.set_target(self.player) if response: self.interface.display(response) for index, item in enumerate(self.level.contents): if item is enemy: self.level.remove(enemy.name) def exit(self): """Tests for exit conditions and exits the player if they are met The length of this method suggests that it is ripe for splitting these actions into separate methods """ can_exit = self.level.exit(self.player) if can_exit: self.display_exit_message() if not self.enter_next_level(): self.player_in_room = False self.interface.display_end_of_game() else: format_string = "Sorry, you are not at an exit of {0}." message = format_string.format(self.room.name) self.interface.display(message) return can_exit def display_exit_message(self): """Displays the level's exit text to the user if it exists""" if self.room.exit_text == None: self.interface.display("You have exited {0}".format(self.room.name)) elif self.room.exit_text == "final" and "bacon" in self.bag.items: self.interface.display(final_narration_win()) elif self.room.exit_text == "final" and "bacon" not in self.bag.items: self.interface.display(final_narration_lose()) else: self.interface.display(self.room.exit_text) def enter_next_level(self): """Transports the player to the next level or returns False if there is no next level """ next_level, has_next_level = self.room.enter_next_level(self.player) if has_next_level: self.level = next_level self.interface.display(self.room.room_description()) return True return False def item_count(self): """Displays the player's inventory""" self.interface.display(self.bag.look()) def coordinates(self): """Returns the x, y coordinates of the player""" coords = self.player.locate() message = "Your co-ordinates are: ({0},{1})".format(coords[0], coords[1]) self.interface.display(message) def vaccum_key_and_gold(self): """Automagically picks up gold and keys""" if self.pick_up_item("key"): self.interface.display("You picked up the key!") if self.pick_up_item("gold"): self.interface.display("You picked up the gold!") if self.pick_up_item("bacon"): self.interface.display("You picked up the bacon!") def vaccum_weapons(self): """Swiftly picks up Excalibur""" if self.pick_up_item("excalibur"): self.interface.display("Behold! The most power ever felt!") def pick_up_item(self, item): """Allows the player to pick up and item by removing an item from the room and placing it in their bag """ if self.level.get_by_name(item) != None: player_coord = self.player.locate() item_coord = self.level.get_by_name(item).locate() if player_coord == item_coord: self.bag.add(Item(item)) self.level.remove(item) return True return False def display_help(self): """Displays the help menu""" self.interface.display_help(self.in_room()) def invalid_command(self): """Displays a message that tells the user their command was invalid""" self.interface.display("Sorry that command is not valid.") self.interface.display("Please type 'help' and press enter for a menu.") def main_loop(self): """This is the core game loop that cycles through the turns""" play = True self.start() while play: play = self.move_player() if self.in_room(): self.vaccum_key_and_gold() self.vaccum_weapons() play &= self.move_creatures() if play: self.interface.display(self.level.draw_map()) self.interface.display(self.player.show_health()) def move_player(self): """Gets the command from the player and moves (or quits)""" command = self.interface.prompt(self.prompt_char).lower() possible_commands = self.interface.current_commands(self.in_room()) if command == "q": return False else: if not self.execute_command(command, possible_commands): self.invalid_command() return True def execute_command(self, command, commands): """Executes the command if valid, returns false if invalid""" try: cmd_tuple = commands[command] cmd_tuple[0]() return True except KeyError: return False def move_creatures(self): """Moves the creatures in the room""" creatures = self.level.get_move_ai() for creature in creatures: target_tile = next_tile(creature.coords, creature.target) if target_tile == self.player.coords: dmg = creature.weapon.damage self.interface.display("You were attacked by the " + creature.name + " for " + str(dmg) + " damage!") response = self.player.take_damage(dmg) if response: self.interface.display(response) return False else: creature.move() return True def add_direction_to_commands(self, direction): if not hasattr(self, direction): self.interface.display("That is not a valid direction") return False response = self.interface.prompt("Please choose a key to be your {} movement: ".format(direction)) if response in self.interface.command_mapping: self.interface.display( "That key is already in use to {}".format(self.interface.command_mapping[response][1]) ) return False self.interface.command_mapping[response] = (getattr(self, direction), "move {}".format(direction), False) return True
def setUp(self): self.bag = Bag()
class InventoryBagTest(unittest.TestCase): def setUp(self): self.bag = Bag() def tearDown(self): self.bag = None def test_can_use_bag_to_hold_items_that_are_found(self): # Inara is curious to know if she is carrying any items. She checks her bag to see what is in her inventory self.assertIsNotNone(self.bag) # Her inventory bag is empty and contains no items self.assertTrue(self.bag.is_empty()) self.assertEqual(self.bag.item_count(), 0) # Inara sees a pile of rocks nearby and lacking any other items decides to put them into her bag. She puts one rock into her bag. Looking into her bag, it is no longer empty, she has one rock in it. rock = Item("rock") self.bag.add(rock) self.assertFalse(self.bag.is_empty()) self.assertEqual(self.bag.item_count(), 1) # note perhaps this should be checking for look() rather than dump() seen = self.bag.look() self.assertIn("1 rock", seen) # She puts two more rocks into her bag. Looking into her bag, she sees that it now contains 3 rocks self.bag.add(rock) another_rock = Item("rock") self.bag.add(another_rock) self.assertEqual(self.bag.item_count(), 3) seen = self.bag.look() self.assertIn("3 rock", seen) # Inara, happy to have something in her bag, starts on her adventure. Before long she stumbles on something in a dark shadow. Picking it up she sees that it is a shiny dagger. After putting it into her bag she checks her bag to ensure that it is safe inside. She now has 3 rocks and a dagger in her bag. dagger = Item("dagger") self.bag.add(dagger) seen = self.bag.look() self.assertIn("1 dagger", seen) def test_items_are_removed_from_bag(self): # Mary Poppins is summoned by the children to bring joy to their lives. She is holding a bag. It contains a hatrack, a carpet, two lollipops and 5 brooms. It also contains medicine, a teaspoon and a few spoonfulls of sugar. self.bag.add(Item("hatrack")) self.bag.add(Item("carpet")) self.bag.add(Item("Thing 1")) self.bag.add(Item("Thing 2")) self.bag.add(Item("Cat")) self.bag.add(Item("Hat")) self.bag.add(Item("lollipop")) self.bag.add(Item("lollipop")) self.bag.add(Item("lollipop")) self.bag.add_many(Item("lollipop"), 5) self.bag.add(Item("medicine")) self.bag.add(Item("teaspoon")) self.bag.add_many(Item("spoonful of sugar"), 3) # Her bag contains at least 14 items. total_items = self.bag.item_count() self.assertTrue(total_items >= 14) # Mary enters the unhappy home with a messy room and tells the kids to tidy up. The children don't want to tidy up so she starts searching through her bag. She removes a hatrack but puts it back hatrack_count = self.bag.how_many("hatrack") self.bag.remove("hatrack") self.assertEqual(hatrack_count - 1, self.bag.how_many("hatrack")) self.bag.add(Item("hatrack")) self.assertEqual(hatrack_count, self.bag.how_many("hatrack")) # Mary then removes the medicine. med_count, medicine = self.bag.remove("medicine") self.assertEqual(med_count, 1) self.assertIsInstance(medicine, Item) self.assertEqual(medicine.name, "medicine") # She tries to remove two teaspoons but only has one. # She removes the teaspoon teaspoon_count, teaspoon = self.bag.remove_many("teaspoon", 2) self.assertEqual(teaspoon_count, 1) self.assertEqual(self.bag.how_many("teaspoon"), 0) self.assertEqual(teaspoon.name, "teaspoon") # She removes one spoonful of sugar and begins to sing sugar_count, sugar = self.bag.remove("spoonful of sugar") self.assertEqual(1, sugar_count) # She removes another spoonful of sugar and continues to sing. sugar_count, sugar = self.bag.remove("spoonful of sugar") self.assertEqual(1, sugar_count) # She removes the third spoonful of sugar smiles to herself and takes her medicine. sugar_count, sugar = self.bag.remove("spoonful of sugar") self.assertEqual(1, sugar_count) # Mary now has 5 less items in her bag new_total_items = self.bag.item_count() self.assertEqual(5, total_items - new_total_items) # She returns the medicine and spoon to her bag and with at least 12 items in her bag continues with her work self.bag.add(teaspoon) self.bag.add(medicine) self.assertTrue(self.bag.item_count() >= 12) def test_items_are_dumped_into_a_pile(self): # Items can be dumped into a pile and sorted through # This is a remnant of my inital version implementation of the InventoryBagAddAndLookTestCase which has since been converted to the look function. Not sure if I should keep dump() # This may be useful in the future for saving the state of the bag rock = Item("rock") self.bag.add(rock) pile = self.bag.dump() item_list = pile.keys() self.assertEqual(len(item_list), 1) self.assertIn("rock", item_list) item = pile["rock"] self.assertEqual(item["name"], "rock") self.assertEqual(item["count"], 1)
class Engine: """This class ties it all together and might be viewed as something somewhat akin to a controller in an MVC framework. """ def __init__(self, library_path, prompt_func=input, print_func=print): self.prompt_char = ">" self.library_path = library_path self.reset_game() self.interface = CommandLine(self, prompt_func, print_func) self.bag = Bag() self.level = None self.player = None self.player_in_room = None self.room = None for direction in ("north", "south", "east", "west"): while not self.add_direction_to_commands(direction): pass # The heart of what we want to do within this while loop is contained within # The add_direction_to_commands function. We just want to keep calling it # until it returns True. def start(self): """Use this method to start the game""" player_name = self.interface.greet() self.player = Player(player_name) self.interface.display(initial_narration()) self.init_level() self.interface.display(self.level.draw_map()) def init_level(self): """Looks up the level information from file, loads it and inserts the player into the room. """ self.room = LevelLoader(self.library_path, self.room_file) self.level = self.room.enter(self.player, "entrance") self.player_in_room = True self.interface.display(self.room.room_description()) def reset_game(self): """Returns the game to its initial state""" self.room_file = "level_1.json" self.player_in_room = False def in_room(self): """Used to determine if the player is currently in a room""" if self.player == None: return False return self.player.in_room() def load_player(self, player): """Attribute setter for the player""" self.player = player def north(self): """Moves the player north if able""" if not self.level.can_go_north(self.player): self.interface.display("你不能向北走") else: for creature in self.level.get_move_ai(): if creature.coords == (self.player.coords[0], self.player.coords[1] + 1): self.attack(creature) break else: self.player.travel("n") def south(self): """Moves the player south if able""" if not self.level.can_go_south(self.player): self.interface.display("你不能向北走") else: for creature in self.level.get_move_ai(): if creature.coords == (self.player.coords[0], self.player.coords[1] - 1): self.attack(creature) break else: self.player.travel("s") def east(self): """Moves the player east if able""" if not self.level.can_go_east(self.player): self.interface.display("你不能向北东") else: for creature in self.level.get_move_ai(): if creature.coords == (self.player.coords[0] + 1, self.player.coords[1]): self.attack(creature) break else: self.player.travel("e") def west(self): """Moves the player west if able""" if not self.level.can_go_west(self.player): self.interface.display("你不能向西走") else: for creature in self.level.get_move_ai(): if creature.coords == (self.player.coords[0] - 1, self.player.coords[1]): self.attack(creature) break else: self.player.travel("w") def attack(self, enemy): if self.bag.how_many('spear') > 0: wep_dmg = Spear('1').dmg wep_dev = Spear('1').deviation elif self.bag.how_many('excalibur') > 0: wep_dmg = Excalibur('1').dmg wep_dev = Excalibur('1').deviation else: wep_dmg = 0 wep_dev = 0 dmg = self.player.weapon.damage + wep_dmg dev = self.player.deviation + wep_dev dmgdev = randint(dmg - dev, dmg + dev) self.interface.display("你攻击 " + enemy.name + " 并对它造成了 " + str(dmgdev) + " 点伤害!") response = enemy.take_damage(dmg) enemy.set_target(self.player) if response: self.interface.display(response) for index, item in enumerate(self.level.contents): if item is enemy: self.level.remove(enemy.name) def exit(self): """Tests for exit conditions and exits the player if they are met The length of this method suggests that it is ripe for splitting these actions into separate methods """ can_exit = self.level.exit(self.player) if can_exit: how_many_key = self.bag.how_many('key') if int(how_many_key) > 0: self.display_exit_message() self.player.exit() self.bag.remove('key') if not self.enter_next_level(): self.player_in_room = False self.interface.display_end_of_game() else: format_string = "对不起,你还没找到 {0} 的钥匙." message = format_string.format(self.room.name) self.interface.display(message) else: format_string = "对不起,你还没找到 {0} 的出口." message = format_string.format(self.room.name) self.interface.display(message) return can_exit def display_exit_message(self): """Displays the level's exit text to the user if it exists""" if self.room.exit_text == None: self.interface.display("You have exited {0}".format( self.room.name)) elif self.room.exit_text == "final" and "bacon" in self.bag.items: self.interface.display(final_narration_win()) elif self.room.exit_text == "final" and "bacon" not in self.bag.items: self.interface.display(final_narration_lose()) else: self.interface.display(self.room.exit_text) def enter_next_level(self): """Transports the player to the next level or returns False if there is no next level """ next_level, has_next_level = self.room.enter_next_level(self.player) if has_next_level: self.level = next_level self.interface.display(self.room.room_description()) return True return False def item_count(self): """Displays the player's inventory""" self.interface.display(self.bag.look()) def coordinates(self): """Returns the x, y coordinates of the player""" coords = self.player.locate() message = "你的坐标在: ({0},{1})".format(coords[0], coords[1]) self.interface.display(message) def vaccum_key_and_gold(self): """Automagically picks up gold and keys""" if self.pick_up_item("key"): self.interface.display("你捡起了钥匙!") if self.pick_up_item("gold"): self.interface.display("你捡起了黄金!") if self.pick_up_item("food"): self.interface.display("你吃了些食物,感觉恢复了一些体力(增加20点生命值)!") if self.pick_up_item("yao"): self.interface.display("你吃了些药,最大生命值增加20,赶紧去吃点食物补补身体吧!") def vaccum_weapons(self): """Swiftly picks up Excalibur""" if self.pick_up_item("excalibur"): self.interface.display("你拿起了神剑,感觉全身充满了力量!") if self.pick_up_item("spear"): self.interface.display("你拿起了神枪,感觉全身充满了力量!") def pick_up_item(self, item): """Allows the player to pick up and item by removing an item from the room and placing it in their bag """ if self.level.get_by_name(item) != None: player_coord = self.player.locate() item_coord = self.level.get_by_name(item).locate() if player_coord == item_coord: if item == "food": self.player.take_damage(-50) if self.player.calc_health() > self.player.maxph: self.player.take_damage(self.player.calc_health() - self.player.maxph) elif item == "yao": self.player.maxph += 20 else: self.bag.add(Item(item)) self.level.remove(item) return True return False def display_help(self): """Displays the help menu""" self.interface.display_help(self.in_room()) def invalid_command(self): """Displays a message that tells the user their command was invalid""" self.interface.display("命令不可用") self.interface.display("输入\"help\"可以查询命令.") def main_loop(self): """This is the core game loop that cycles through the turns""" play = True self.start() while play: play = self.move_player() if self.in_room(): self.vaccum_key_and_gold() self.vaccum_weapons() play &= self.move_creatures() if play: self.interface.display(self.level.draw_map()) self.interface.display(self.player.show_health()) def move_player(self): """Gets the command from the player and moves (or quits)""" command = self.interface.prompt(self.prompt_char).lower() possible_commands = self.interface.current_commands(self.in_room()) if command == "q": return False else: if not self.execute_command(command, possible_commands): self.invalid_command() return True def execute_command(self, command, commands): """Executes the command if valid, returns false if invalid""" try: cmd_tuple = commands[command] cmd_tuple[0]() return True except KeyError: return False def move_creatures(self): """Moves the creatures in the room""" creatures = self.level.get_move_ai() for creature in creatures: target_tile = next_tile(creature.coords, creature.target) if target_tile == self.player.coords: dmg = creature.weapon.damage dev = creature.deviation dmgdev = randint(dmg - dev, dmg + dev) self.interface.display("你被 " + creature.name + " 攻击,受到了 " + str(dmgdev) + " 点伤害!") response = self.player.take_damage(dmg) if response: self.interface.display(response) return False else: creature.move() return True def add_direction_to_commands(self, direction): if not hasattr(self, direction): self.interface.display("这不是一个正确的方向") return False #response = self.interface.prompt("请输入一个键作为你向 {} 移动的控制键: ".format(self.translate_direction(direction))) response = self.get_direction_key(direction) if response in self.interface.command_mapping: self.interface.display("这个键已经被用在 {} 上了".format( self.interface.command_mapping[response][1])) return False self.interface.command_mapping[response] = (getattr( self, direction), "向 {} 移动".format(self.translate_direction(direction)), False) return True def translate_direction(self, direction): return { 'north': '北(north)', 'south': '南(south)', 'east': '东(east)', 'west': '西(west)', }.get(direction, direction) def get_direction_key(self, direction): return { 'north': 'n', 'south': 's', 'east': 'e', 'west': 'w', }.get(direction, direction)