Overall I don't think the code is that bad, considering what is the purpose; but if you want to expand your game I think the greatest issue is the data structure.
It'd be very easy to misplace some room or call it in a different way if you have to repeat yourself every time, so I suggest you to use a class to represent a Room:
class Room: name: str north: 'Room' east: 'Room' south: 'Room' west: 'Room' def __init__(self, name, north=None, east=None, south=None, west=None): self.name = name self.north = north self.east = east self.west = west self.south = south if north: north.south = self if east: east.west = self if south: south.north = self if west: west.east = self def go_to(self, direction): if direction in ['north','east','south','west']: return getattr(self, direction) else: return None def __str__(self): return self.name
I'm using types because is very helpful to find out problems before it's too late, in Python if you have a recursive type (like Room) you need to use the quotes, but it just a syntactic notation.
By default a room does not have any north,east,south,west Room (hence the =None
) but the important thing that happens in the __init__
is that when you add a room it automatically set the opposite direction. So if a room goes to another by east, the other room does the opposite by west. Thus we are reducing errors in directions. If this will not be the case for some room, you will be able to override that using another class (SelfLockingRoom
that closes all the other directions when you enter, for example).
The __str__
method is just to handle the display of the room to the room itself; at one point you could have more than just the name to display.
I'm adding also a go_to method, it is the room responsibility to decide where to go given the direction; in the future you could have a TrapRoom
that extends Room and in case of direction "East" will do nasty things, for example. The getattr
is just to avoid having to write if direction=='north': return self.north
but it would be the same and maybe even clearer.
Actually, if the game develops further, you may need more complex rules to decide what do to given a direction so probably you will need a House class:
class House: current_room: Room rooms: list[Room] # at the moment is not used but could be in the future? def __init__(self, current_room: Room, rooms: list[Room]): self.current_room = current_room self.rooms = rooms def go_to(self, direction): if next_room := self.current_room.go_to(direction): self.current_room = next_room return next_room
At the moment is not very useful, but I think it's going to be.
To initialize the house you just create the rooms:
house_rooms = [cellar := Room('Cellar'), library := Room('Library'), dining_room := Room('Dining Room'), gallery := Room('Gallery'), bedroom := Room('Bedroom', east=cellar), dungeon := Room('Dungeon', east=gallery), kitchen := Room('Kitchen', north=dining_room), great_hall := Room('Great Hall', south=bedroom, north=dungeon, west=library, east=kitchen)] house = House(current_room=great_hall, rooms=house_rooms)
(As you can see I'm not repeating names or directions)
The game loop is OK, we can collect some helpful methods, just in case you want to expand them in the future:
def prompt(text: str): print(text) def ask(text: str) -> str: return input(text).strip()
and this would be your game loop (I'm always lowering the direction so you can write East east or EAST).
commands = { "directions": ['north', 'south', 'east', 'west'], "quit": ['q', 'quit'] } def game_loop(): prompt(f"\nYou are in the {house.current_room}") command = ask('\nWhat direction do you want to go? ').lower() if command in commands["directions"]: if not house.go_to(command): prompt("You can't go that way.") elif command in commands["quit"]: return False else: prompt("I don't understand that command.") return True if __name__ == '__main__': while game_loop(): pass