How to Write a Text Adventure in Python Part 4: The Game Loop

This is an abbreviated version of the book Make Your Own Python Text Adventure.

The end is near, we’re almost ready to play the game! We’ll finish this series by implementing the game loop and receiving input from the human player.

The Game Loop

While some applications follow a discrete set of steps and terminate, a game typically just “keeps going”. The only way the program stops is if the player wins, loses, or quits. To handle this behavior, games usually run inside a loop. On each iteration, the game state is updated and input is received from the human player. In graphical games, the loop runs many times per second. Since we don’t need to continually refresh the player’s screen for a text game, our code will actually pause until the player provides input. Our game loop is going to reside in a new module

import world
from player import Player

def play():
    player = Player()
    while player.is_alive() and not player.victory:
        #Loop begins here

Before play begins, we load our world from the text file and create a new Player object. Next, we begin the loop. Note the two conditions we check: if the player is alive and if victory has not been achieved. For this game, the only way to lose is by dying. However, there isn’t any code yet that lets the player win. In my story, I want the player to escape the cave alive. If they do that, they win. To implement this behavior, we’re going to add a very simple room and place it into our world. Switch back to and add this class:

class LeaveCaveRoom(MapTile):
    def intro_text(self):
        return """
        You see a bright light in the distance...
        ... it grows as you get closer! It's sunlight!

        Victory is yours!

    def modify_player(self, player):
        player.victory = True

Don’t forget to include one of these rooms somewhere in your map.txt file. Now that the player can win, let’s finish the game loop.

def play():
    player = Player()
    #These lines load the starting room and display the text
    room = world.tile_exists(player.location_x, player.location_y)
    while player.is_alive() and not player.victory:
        room = world.tile_exists(player.location_x, player.location_y)
        # Check again since the room could have changed the player's state
        if player.is_alive() and not player.victory:
            print("Choose an action:\n")
            available_actions = room.available_actions()
            for action in available_actions:
            action_input = input('Action: ')
            for action in available_actions:
                if action_input == action.hotkey:
                    player.do_action(action, **action.kwargs)

The first thing the loop does is find out what room the player is in and then executes the behavior for that room. If the player is alive and they have not won after the behavior executes, we prompt the human player for input. This is done using the built-in input() function. If the human player provided a matching hotkey, then we execute the associated action using the do_action method.

The last thing we need to include is an instruction for Python to know that play() should run when running the file. Include these lines at the bottom of the module:

if __name__ == "__main__":

To run the program, navigate to the folder containing the adventuretutorial package in your console and run python adventuretutorial/ If you get warnings about packages, try setting your PYTHONPATH environment variable manually. Have fun!

Where to go from here

Congratulations! You now have a working text adventure game. With the information learned here, you should be able to quickly add your own custom items, enemies, and tiles. If you’re up for more of a challenge, here are some of the features included in Make Your Own Python Text Adventure:

  • An easier and more flexible way to build your world (no text files or reflection!)
  • A game economy where the player can buy and sell items
  • The ability for players to heal during and between fights
  • Difficulty settings to make the game harder or easier

Tagged on: , , , ,

92 thoughts on “How to Write a Text Adventure in Python Part 4: The Game Loop

  1. Damon Jenkins

    Hi Phillip. I have gone through the steps, and when I tried to launch, cmd said “Import Error: No module named ‘adventuretutorial’. I have Googled for a while to solve this but I couldn’t find anything. Would you be willing and/or able to help me out?

    1. Phillip

      Please see the section above:

      To run the program, navigate to the folder containing the adventuretutorial package in your console and run python adventuretutorial/ If you get warnings about packages, try setting your PYTHONPATH environment variable manually. Have fun!

      Happy programming!

      1. Joon0624

        if i try to run the programs its says it had an error. How do i fix this?

        Traceback (most recent call last):
        File "/", line 2, in 
        from player import Player
        File "/", line 44 
        if i damage > max_dmg:

        syntaxError: invalid syntax

  2. ian

    i have everything set up the same way it is in the final product, however when i try to run the program, it brings up an error and says that there is no module named adventuretutorial. It says the same thing when i try to run even the program that is provided at GitHub.
    How do i fix this?
    I am using windows 8 and python 2.7.9

    1. ian

      So i guess my problem is the same as the other persons, but my question is how do i set my PYTHONPATH environment variable manually? i know how to get to the add environment variables screen, but after that i am lost

  3. Bart

    AttributeError: ‘module’ object has no attribute ‘OgreRoom

    it throws an error at the first place in map.txt where i decided was gonna be a wall.
    GiantSpiderRoom FindDaggerRoom FindGoldRoom FindGoldRoom OgreRoom
    OgreRoom EmptyCavePath GiantRatRoom EmptyCavePath FindDaggerRoom

    that is the first 2 rows. i made a 12×5 grid in a spreadsheet and copy pasted. I even checked the map.txt on github and it throws an error the same way for that map.txt file.
    it reads the first line of rooms and throws an error when it tries to drop down to the 2nd row.
    I’m using Python 3x

  4. Mika

    Hello. My game now works, and I am trying to make a new action “run”. Main purpose of it is to run in random direction. So my code looks like this:
    def run(self):
    direction = random.randint(0,3)
    if direction == 0:
    elif direction == 1:
    elif direction == 2:
    elif direction == 3:
    and I didn’t forget to make a class. When I run the game, and I use my “run” command, nothing happens. It doesn’t give me error, it just continues, and asks me for another action.

  5. Jeff

    For some reason when I run the main loop, it doesn’t print the intro text to the starting room. If I move east then west it prints the intro text. Any suggestions for what’s missing?

  6. Chris

    Hi Phillip,
    Thank you for this series. I worked through this with the students in my Python class. Everything works great! However, when the game starts it shows the actions available but does not show the intro_text for the StartingRoom. Can you tell me if there is a simple way to fix this? Thank you!

    1. Phillip

      Hey, nice find! I’ve put in a fix for this on GitHub and in the post. Basically, we just manually print the intro text since the player isn’t going to “move into” that room at the beginning.

  7. Sinfulstyle

    Hey there, I’ve set everything up the way you described. but I’m getting an Error. No such file or directory: ‘resources/map.txt’. I’m running Ubuntu is that matters. I created the file exactly as you had in libre calc and copied everything minus the snake pit and changed the name of the CaveExit. Selected all, copied and pasted into a file I had made called map.txt, which is inside the resources folder, which is inside the game folder. It’s probably something stupid, I know, but I am quite new and would appreciate any help._world = {}

    def tile_exists(x, y):
    return world.get((x, y))

    def load_tiles():
    """Parses a file that describes the world space into the _world object"""
    with open('resources/map.txt', 'r') as f:
    rows = f.readlines()
    x_max = len(rows[0].split('\t')) # Assumes all rows contain the same number of tabs
    for y in range(len(rows)):
    cols = rows[y].split('\t')
    for x in range(x_max):
    tile_name = cols[x].replace('\n', '')
    world[(x, y)] = None if tile_name == '' else getattr(__import__('tiles'), tile_name)

    Full error:
    File “”, line 23, in
    File “”, line 5, in play
    File “/home/sinfulstyle/”, line 8, in load_tiles
    with open(‘resources/map.txt’, ‘r’) as f:
    FileNotFoundError: [Errno 2] No such file or directory: ‘resources/map.txt’

    1. Phillip

      Glad you could fix it. Another option is to execute your code from the project root folder. As per the post, “To run the program, navigate to the folder containing the adventuretutorial package in your console and run python adventuretutorial/”

      If you execute your code from a different location, you’ll need to adjust the path to the resources folder, as you did.

      Happy coding!

      1. Sinfulstyle

        Wow! You are fast and active. Thank you very much, sorry I didn’t really understand what you meant by that. I did read it all and manually typed everything so I’m working through a butt load of errors. Haha figured it’s good practice though. I know I saw the answer to this question earlier but I hadn’t gotten that far and I can’t seem to find a way to navigate previous comments. Anyways if you could help me with this error:
        File “/home/sinfulstyle/”, line 14, in load_tiles
        tile_name = cols[x].replace(‘\n’, ”)
        IndexError: list index out of range

        I’d be extremely grateful. I honestly have no idea where to start.

        1. Sinfulstyle

          again fixed that, i thought I had seen someone say something about not having the tabs the same, so I spaced out the rest of the text so it was all the same length on the x axis. Now I’m getting this:
          _world[(x, y)] = None if tile_name == ” else getattr(__import__(’tiles’), tile_name)(x, y)
          AttributeError: ‘module’ object has no attribute ‘

  8. Sinfulstyle

    For some reason I’m having a huge problem with the map.txt file. I either get list index is out of range or the module objects has no attribute. Can you elaborate on the text file creation? I’ve tried everything from making it in libre and copying it into a text file, making sure to keep all of the tabs are inserted. To copying your raw map.txt from github. Changed all of my rooms so they matched yours. Pulling hairs hear man. Haha.

      1. Jason

        I too am having the _world[(x, y)] = None if tile_name == โ€ else getattr(__import__(โ€™tilesโ€™), tile_name)(x, y)
        AttributeError: โ€˜moduleโ€™ object has no attribute โ€˜error. I read the answers on part 2, and still am not understanding. I tried copying and pasting the map.txt file, that didn’t work.
        I have played around with the file, in notepad, as well as open office spreadsheet, and everytime I try it, it just gives me that error, the only thing that has changed is the part where it says no attribute ” … the ” switches to whatever I have first in the text file.
        I am clueless….

        1. Phillip Johnson Post author

          There’s a difference between '('module' object has no attribute '') and '('module' object has no attribute 'OgreRoom'). The former has been discussed extensively in the comments of Part 2. If you’re getting the second error, then it is probably because Python cannot find all of your code at runtime. Make sure you are in the correct directory when you run the code and that you are running it from a terminal/command line. If all else fails, you may need to adjust your PYTHONPATH, but that’s probably the solution to another more systemic problem.

  9. Elli

    First of all, thank you for this great guide!

    I am having problem with my program at the moment. Game starts fine, but…

    You find yourself in a cave with a flickering torch on the wall.
    You can make out four paths, each equally as dark and foreboding.

    Choose an action:

    a: Move west
    i: View Inventory

    Only actions the player is offered in any room are “Move west” and “View Inventory” (I have set my movements on wasd: w is north, a is west, s is south, d is east, e is attack). I can only move west along the path: Starting Room -> Empty Room -> Giant Spider Room. Spider attacks the player on Spider Room, but still the only actions are “Move west” and “View Inventory” (no attack or flee). If I move west from Spider Room, I get errors, as there is not intended to be a room after Giant Spider Room in that direction. If I use “d” (east), Spider just attacks the player again.

    I have no clue why this is happening, or why “west” is the only option. I’m not sure what parts of my code to copy paste to show, even.

    This is what I have on my

    [Mod edit: Removed for brevity]

    and this is what I have on on class MapTile:

    class MapTile:
        def __init__(self, x, y):
            self.x = y
            self.y = y
        def intro_text(self):
            raise NotImplementedError()
        def modify_player(self, player):
            raise NotImplementedError()
        def adjacent_moves(self):
            """Returns all move actions for adjacent tiles."""
            moves = []
            if world.tile_exists(self.x + 1, self.y):
            if world.tile_exists(self.x - 1, self.y):
            if world.tile_exists(self.x, self.y - 1):
            if world.tile_exists(self.x, self.y + 1):
            return moves
        def available_actions(self):
            """Returns all of the available actions in this room."""
            moves = self.adjacent_moves()
            return moves
    1. Phillip

      Oh, wow, that’s a nasty bug! There’s a typo here:

      class MapTile:
          def __init__(self, x, y):
              self.x = y
              self.y = y

      You are setting both the x and y coordinates equal to the y-value. Change it to self.x = x and hopefully that fixes it!

      1. Elli

        Thank you, I completely missed that very silly typo there! Changing that one fixed the movement; all correct options are now presented in every room. Spiders are still unattackable (they cause damage, but player can just continue to the next room, no different options from regular rooms like attack or flee), but I’ll go through my code with a microscope and try to find the cause for that ๐Ÿ™‚ Must be similar “too obvious” typo that I have missed somewhere else.

        1. Elli

          Just wanted to give an update, sorry for spam – I found my last couple of typos. I had “def available_action(self):”, not “def available_actions(self):” under class EnemyRoom, which caused the code to always return self.adjacent_moves() and never give attack or flee options, d’oh. Code is working perfectly now! ๐Ÿ™‚ Thank you for the tutorial and quick help!

  10. Tommy Collinson

    I have completed and tried to to run the game and this “AttributeError: ‘Player’ object has no attribute ‘is_alive'”
    def play():
    player = Player()
    while player.is_alive() and not player.victory:

    That is the problem area, I have no idea what this is as i am extremely new to python

    1. Phillip

      It’s difficult to say what the problem is specifically, but I would review your Player class against what I have in Part 3 of the tutorial (or GitHub). It sounds like you may have just missed adding the is_alive function.

  11. Michael

    How would you go about adding an economy to the game? Any tips or codes I could try?
    I wouldn’t even know how to make it stored total amount gold rather than individual collected coins.
    Please help.

  12. Tommy Collinson

    Thank you for your help on my last question, but now I have another.
    I decide to add a way to regain health by eating food. I created a subclass in the item class and the code runs but when I run it instead of removing the food it adds more.
    def eat(self):
    best_food = None
    max_hp = 0
    for i in self.inventory:
    if isinstance(i, items.Food):
    if i.hp > max_hp:
    max_hp = i.hp
    best_food = i

    print("You eat an {} and gained {} Hp.".format(, best_food.hp))
    self.hp += best_food.hp
    print("Your HP is {}.".format(self.hp))
    best_food = [1] in self.inventory
    self.inventory[1] = ''

    e.g. when I pick up an apple I eat it then it get removed from the list but then 2 more apples appear.
    Please help.

  13. Valerie

    I apologize if this question has already been brought up, I looked back through all of the comments and I don’t think I saw it asked anywhere else. When I try and run from the terminal, I get the error from

    line 19, in __init__
    TypeError: super() takes at least 1 argument (0 given)

    My code for this part of the script in is:

    class Gold(Item):
         def __init__(self, amt):
              self.amt = amt
              #superclass constructor, always called by a subclass constructor
    		                    description="A round coin with {} stamped on the front.".format(str(self.amt)),

    Do I need to add arguments to super()? Thanks!

    1. Phillip

      This most likely means you are using version 2.x version of Python because the super() constructor was added in Python 3. There’s some more discussion of this error in the comments on the Intro post, if that helps. Happy coding!

    2. Chad Wilson

      It is relatively trivial to fix this up to work on Pything 2.x. Here is what I did.

      1. Search for all top level class definitions and change from from “class Name:” to “class Name(object):”. This is referred to using the new style of classes.

      2. Search for all super().__init__ constructor calls and change them to “super(CLASSNAME, self)__init__. For example in you should super(EnemyRoom, self).__init__(x, y) for the constructor in the EnemyRoom class.

      3. Search for all prints with formatting using {} formatters, and replace the empty {} with the proper indexes. Example. print “{0} HP is {1}.”.format(, enemy.hp)

      That should be everything

  14. Jason Walker

    Whenever i try and run the game via PyCharm(IDE i am using) i get the following error:

    C:\Python34\python.exe: can’t open file ‘C:/Users/JASON_PC/PycharmProjects/textadv/items’: [Errno 2] No such file or directory

  15. Chad Wilson

    I would like to work on this some more and commit my additions to your github, but I want to do this in python 2.x. How do you suggest I do that? By ‘do that’ I mean in github.

    1. Phillip Johnson Post author

      I would start by forking the project on GitHub and then make changes in your own repo. However, won’t be adding Python 2.x support into the main project since I encourage new learners to start with Python 3.x.

  16. Cassidy

    I don’t understand what’s going on with this! This is my FindSword code:

    class FindIronSwordRoom(LootRoom):
    def __init__(self, x, y):
    super().__init__(x, y, items.IronSword())

    def intro_text(self):
    return “””
    You find an small iron short sword on the ground.

    And then it gives me this error everytime I try to run it:

    TypeError: __init__() missing 4 required positional arguments: ‘name’, ‘description’, ‘value’, and ‘damage’

    It’s very frustrating! Please help!

  17. Kei


    I would also like to thank Philip for creating this tutorial and everyone else for asking excellent questions. It has helped me along the way. I have a version of this game that runs, but it crashes whenever I encounter an enemy, such as a troll (similar to Giant Spider). I am using Python 3.4 on OS X El Capitan (a Mac). This is the error message I get on IDLE:

    Traceback (most recent call last):
      File "/Users/KJ/Desktop/adv_game/", line 35, in 
      File "/Users/KJ/Desktop/adv_game/", line 30, in play
        player.do_action(action, **action.kwargs)
      File "/Users/KJ/Desktop/adv_game/", line 18, in do_action
      File "/Users/KJ/Desktop/adv_game/", line 39, in move_west
        self.move(dx=-1, dy=0)
      File "/Users/KJ/Desktop/adv_game/", line 27, in move
        print(world.tile_exists(self.location_x, self.location_y).intro_text())
      File "/Users/KJ/Desktop/adv_game/", line 136, in intro_text
        if self.enemy.is_alive():
    TypeError: is_alive() missing 1 required positional argument: 'self'

    If I go to line 136 of and modify it to is_alive(self), it simply gives me a different error once I restart the game and next encounter a troll. That error basically comes down to:

     File "/Users/KJ/Desktop/adv_game/", line 136, in intro_text
        if self.enemy.is_alive(self):
      File "/Users/KJ/Desktop/adv_game/", line 15, in is_alive
        return self.hp > 0
    AttributeError: 'TrollRoom' object has no attribute โ€˜hpโ€™

    My question is, what am I doing wrong in either the module or module? I think I am following the tutorial closely so I thought it should work.


    1. Phillip Johnson Post author

      The TypeError you referenced usually happens when you try to call a method on an object that has not been instantiated. In this example, it seems you are trying to call is_alive on a Troll. In the __init__() for TrollRoom is it possible that you have something like enemies.Troll instead of enemies.Troll()? If that doesn’t fix it, send me a link to your code and I can take a look.

      When you tried to fix the error, you fixed it by passing self into is_alive(). However, that’s not the correct solution because then you are trying to pass a TrollRoom object into the is_alive() method, which doesn’t make sense because a room cannot be alive or dead. That’s why you go the second error that the TrollRoom does not have HP.

  18. Kei

    You were exactly right about error! I had written enemies.Troll instead of enemies.Troll(), though I didn’t make the same mistake for the MinotaurRoom (which was based on the Ogre). Thank you!

  19. Kei

    I had one more question. Is there any way to add an AI component to the text adventure without adding hundreds of lines of code to make it effective? By “AI” I mean having the computer play against the human player, perhaps by using alpha beta search or minimax search. Right now it seems to be more like a one-player game.

    1. Phillip Johnson Post author

      Perhaps the easiest thing would be to improve the Enemy class so that it attacks intelligently. But to do that, the enemy would need to have its own set of possible moves like attack, heal, flee, use magic, etc. But “easiest” is relative, this would require a good deal of logic to be added to the Enemy class.

  20. Kei

    Thanks Philip! There’s another enhancement idea that I am trying to think of how to implement. How could I write a method to let the computer guide the player by telling him which move he should make next? So the computer should ask the player if he wants a suggestion, and if the player agrees then the computer suggest a move and makes it. It should keep doing this until it’s able to beat the game by exiting the cave. I’m thinking that it would involve implementing Minimax or alpha beta, but I’m not yet sure how to implement them in Python into this game.

    1. Phillip Johnson Post author

      It may be possible, but you’d have to do some significant restructuring of the code. Minimax requires some concept of “points” so you would need the game to assign point values to outcomes and then be able to play out different scenarios to determine which move resulted in the highest point value. If you’d like to learn more about Minimax, you might want to check out this post.

  21. Tom Nazir

    Hi Phillip,
    First of thanks a bunch for this tutorial – it’s superb!
    I am having a problem that whenever the player enters a room containing a weapon, the game throws back this error:

    Traceback (most recent call last):
    File “at/”, line 27, in
    File “at/”, line 12, in play
    File “C:\Users\Tom\Desktop\Python\escape from (insert name here)\Tom\at\tiles.
    py”, line 20, in modify_player
    raise NotImplementedError()

    What appears to be the problem?


    1. Phillip Johnson Post author

      The NotImplementedError is actually an exception that we put in place to make sure we don’t create base objects directly. It’s basically a check to make sure we don’t break our own rules. My guess is that your map is trying to create a MapTile object instead of something like LootRoom. Or perhaps you copy-pasted and forgot to change the modify_player() method. You might want to review Part 2 where I talk about this exception and how new tiles are created. Happy coding!

      1. Tom Nazir

        Hi Phillip,

        Everything is working now – basically my “LootRoom” class was giving (for want of a better word) its loot to something I had called “player” instead of the actual “the_player”. Silly me.

        Thanks for the snappy response!

  22. Pierre

    Hey, I am seeming have problems with my code in the Player Module

    actionmethod = getattr(self, action.method.__name__)
    IndentationError: expected an indented block

    How would i exactly be able to fix it??

    1. Phillip Johnson Post author

      Usually that means the line of code is not properly indented. Whitespace matters in Python, so you have to make sure that lines are indented the correct number of spaces. It also could mean that you have mixed spaces and tabs. Your text editor should have a “show all characters” feature that will make whitespace visible. Hope that helps!

      1. Pierre

        Thanks Philip

        One more question. When the code is completed, there seems to be a certain problem with the code. It comes up with this.

        Traceback (most recent call last):
        File “/Users/pierre/Desktop/AdventureTime/”, line 23, in
        File “/Users/pierre/Desktop/AdventureTime/”, line 5, in play
        File “/Users/pierre/Desktop/AdventureTime/”, line 14, in load_tiles
        tile_name = cols[x].replace(‘\n’, ”) # Windows users may need to replace ‘\r\n’
        IndexError: list index out of range
        [Finished in 0.131s]

        Can I please get some help. Thanks for the help!


  23. Ross

    When I run the code I get the error:

    Traceback (most recent call last):
    File “”, line 23, in
    File “”, line 7, in play
    File “/home/ross/Desktop/TextAdv/”, line 18, in load_tiles
    _world[(x, y)] = None if tile_name == ” else getattr(__import__(’tiles’), tile_name)(x, y)
    TypeError: emptyCorridorEW() takes 1 positional argument but 2 were given

    Any idea what I could be doing wrong?



    1. Ross

      Never mind, I had defined my tile as a function rather than a class (d’oh). I’m now getting this problem though –

      Traceback (most recent call last):
      File “”, line 23, in
      File “”, line 10, in play
      AttributeError: ‘NoneType’ object has no attribute ‘intro_text’

      Any idea what could cause that?

  24. Teun

    First of all thank you very much for making this tutorial, I learned a lot!

    I do have one problem, after a lot of work I managed to make the game work(sadly without some small features I wanted to implement in it) only, it’s not printing the return text after you “beat” a room! It seems to be getting overwritten by the def attack in, because that’s all I’m seeing after an enemy is dead. Because in it should return the text in the else statement if the self.enemy.isalive = false, correct?

    Thank you for your answer!

  25. Alfie Atkinson

    how do i fix this?? i’ve checked and there scouldn’t even be an indented block there, should there?

    Traceback (most recent call last):
    File “C:\Users\Alfie\Desktop\Python\Programs\RPG\”, line 26, in
    File “C:\Users\Alfie\Desktop\Python\Programs\RPG\”, line 5, in play
    File “C:\Users\Alfie\Desktop\Python\Programs\RPG\”, line 16, in load_tiles
    _world[(x, y)] = None if tile_name == ” else getattr(__import__(’tiles’), tile_name)(x, y)
    File “C:\Users\Alfie\Desktop\Python\Programs\RPG\”, line 9
    raise NotImplementedError()
    IndentationError: expected an indented block

    1. Alfie Atkinson

      This is my code for that section

      import items, enemies, actions, world
      class MapTile:
          def __init__(self, x, y):
              self.x = x
              self.y = y
      	def intro_text(self):
          	raise NotImplementedError()
      	def modify_player(self, player):
          	raise NotImplementedError()
  26. EthanKelly

    This is a great tutorial! I have had trouble with a section dealing with location_x and location_y
    I run, and it gives me this:

    Traceback (most recent call last):
    File “”, line 30, in
    File “”, line 11, in play
    room = world.tile_exists(player.location_x, player.location_y)
    AttributeError: ‘Player’ object has no attribute ‘location_x’

    My code for

    room = world.tile_exists(player.location_x, player.location_y)

    and my code for Player()

    class Player():
    def __init__(self):
    self,inventory = [items.Shoe(15), items.SuperStick()]
    self.hp = 50
    self.location_x, self.location_y = world.starting_position
    self.victory = False

    I hope you can help me!

  27. blueninja516

    Hello, I was trying to figure this out on my own and I know its a few days after, but I tried the code, and whenever I try and run it, I get

    Traceback (most recent call last):
      File "C:\Users\Andrew\Desktop\Text_Adventure\", line 29, in 
      File "C:\Users\Andrew\Desktop\Text_Adventure\", line 4, in play
      File "C:\Users\Andrew\Desktop\Text_Adventure\", line 5, in load_tiles
        with open('map.txt', 'r') as f:
    FileNotFoundError: [Errno 2] No such file or directory: 'map.txt'
    I have this code for
    _world = {}
    starting_position = (0,0)
    def load_tiles():
    	"""Parses a file that describes the world space into the _world object"""
    	with open('map.txt', 'r') as f:
    		rows = f.readlines()
    	x_max = len(rows[0].split('\t')) #Assumes all rows contain the same number of tabs
    	for y in range(len(rows)):
    		cols = rows[y].split('\t')
    		for x in range(x_max):
    			tile_name = cols[x]/replace('\r\n', '') # Windows users may need to replace '\r\n'
    			if tile_name == 'StartingRoom':
    				global starting_position
    				starting_position = (x, y)
    			_world[(x, y)] = None if tile_name == '' else getattr(__import__('tiles'), tile_name)(x, y)
    def tile_exists(x, y):
    	return _world.get((x,y))

    I don’t know what I did wrong and any help would be useful at this point.

    1. Phillip Johnson Post author

      It’s a little difficult to tell because you didn’t follow the same directory structure as the tutorial. What’s your directory structure (the tree command will give you a nice print out)? How are you running the game?

      1. blueninja516

        Sorry, I got that part working. I just had a few things named differently apparently. And I’m running it in the command line, it just stopped giving me errors so I’m just waiting for it to start up.

  28. CB


    Your books great stuff.

    Just a tip for anyone else. I was getting the error:

    AttributeError: ‘tuple’ object has no attribute ‘intro_text’

    and it was directly related to this code:

    world_map = [

    The actual reason for the error is I created the code in Excel thinking I could create maps and copy them across to my IDE. I’m using PyCharm.

    Excel must put a format onto the text, it does something very similar if you write SQL and use the TOAD application.

    So if you have written code somewhere else e.g. in another application and are copying and pasting it across to your IDE you might get errors and you don’t understand why.

  29. jake

    ok so i think what i did wrong was when you mentioned about making a new module i made a new file so all of my code is broken into different files how should i go about fixing this?

    I’ve always wanted to make a text based adventure game in python i managed to make one in school but instead of pressing a button to attack you would type it and then the program would choose from 1 to 5 and depending on the number depended on how you killed the enemy but sadly i couldn’t finish it, but now i have some spare time i would love to get this code up and running so i can make more progress on it.

    much appreciated.

  30. Kyle Hoffmann

    how do i make it so that when you enter a loot room it gives you the loot and when you leave and return to the loot room it says that the room is empty

  31. Yuvraj Walia

    Hey Phillip! I’m at my wits end! I have been working through your tutorial for a couple days now, but I’m stuck on the final step, getting it to run! I’ve been using the atom IDE and have written everything on it. that’s my files and how I’ve organized it, as well as the file with my test map. That’s the one thing I can’t get to work! I had everything else up and running, but i still get this error:

    Now i’m running this through the IDE through the run hotkey, is that a possiblity as to why it isn’t working? I went to IDLE and opened up and ran it there, still didn’t work. PLEASE HELP

    1. Phillip Johnson Post author

      Yes, it is likely that the IDE is causing problems. You can confirm this by running the game from the command line, as described in the tutorial. My guess would be that the IDE is running the code from inside the Declarations folder, which (correctly) does not contain map.txt. You could 1) change how the IDE runs the code (i.e. run it from TestGame as Declarations/, 2) move map.txt inside of Declarations, or 3) change the code to look for ‘../resources/map.txt’ using the os.path.join function.

      1. Yuvraj Walia

        Hi! I got the program working on my IDE, (Atom) but I can’t use the hotkeys to interact within the IDE so I moved onto my command prompt, but I get the previous error about not being able to find TestMap.txt! Any reason why that could be?

  32. Rebecca

    Hi Phillip! I bookmarked this tutorial a while ago when I was reading about game design. Today I stumbled on it again and wanted to say thanks for writing – and for continuing to reply to comments over 3 years later!

    It’s so common to see guides like this with years of unanswered comments. While I don’t feel that bloggers are obligated to reply to comments indefinitely, it can be discouraging when all the resources you can find on a particular topic appear abandoned/outdated. So I really admire your commitment to helping people learn. I imagine it gets frustrating answering the same questions repeatedly, but you always remain courteous and helpful.

    Anyway, thanks again for your work and I hope you have a relaxing holiday season this year ๐Ÿ™‚

  33. Dave

    Hello Phillip.

    Thank you for putting the tutorial together. I wrote a similar program back in the mid 80’s using IBM PC BASIC and a book I borrowed from a buddy of mine.
    That being said, I was considering purchasing your book but I’m concerned by the amount of jumping back and forth between files in this tutorial. I’m used to some sort of flowchart, pseudocode, etc to have a plan of attack.
    I went half way through part 3 without noticing that you changed between editing and Not really your fault, but just an example of how the hopping back and forth burned me.

    Does the book have more structured content?

    Also, I am confused by your choice to use tabs in the maps.txt file, instead of CSV or something since whitespace matters so much in Python.
    Was there any particular reason for that decision?


    1. Phillip Johnson Post author

      Hi Dave,

      The advantage of the book is that it is longer, so it is more guided. It also is geared towards complete beginners, so that way sway you one way or the other. There’s still switching back and forth between files because building and improving the game happens throughout the book. However, the source code for the book contains code for each chapter so you can check yourself as you go.

      I chose to use a simple format for the maps.txt file because it’s easy to create, read, and parse. CSV has additional challenges that I didn’t want to bog down the tutorial with.

      Hope that helps!

  34. RJ

    Hello Phillip,
    Got your book for Christmas and enjoying learning to code! I’m half way through chapter 12 and I keep getting this error when I try to test it:

    Traceback (most recent call last):
      File "C:\Users\jacks\Desktop\Python\Text Game\", line 2, in 
        import world
      File "C:\Users\jacks\Desktop\Python\Text Game\", line 65
        class VictoryTile(MapTile):
    SyntaxError: invalid syntax

    any thoughts? Thanks!

    1. Phillip Johnson Post author

      Hmm sometimes when you get a vague error like that, the problem in your code isn’t actually on that line, but the parser doesn’t detect a problem until that line. If I had to guess, it’s possible you have a bad character (like an extra space) somewhere, or you forgot a character (like a closing parenthesis) a few lines up.

      Did you take a look at the source code for the book on GitHub or Dropbox? Check there and if you can’t figure it out, post your code online (gist, pastebin, etc.) and I will take a closer look.

      1. RJ

        I went through the code from GitHub. Noticed several errors, especially in the I managed to correct them and now the game works! Thank you much! Can’t wait to finish coding!

  35. Waylon

    So everything else seems to be working fine for me. However when I walk in a room that adds loot into the players inventory, it adds it correctly, but it adds a second copy to my inventory when I leave the room. Also, if I’m standing in the room and I check my inventory, it adds another copy. I keep seem to figure out why and my code for the loot tiles is exactly like yours. Any idea of what might be happening???

    1. Waylon

      Actually, what is happening is when I type “i” to check my inventory, it is adding the loot a second time which doesnt make sense. This is my print_inventory action in the module:

          def print_inventory(self):
              for item in self.inventory:
                  print(item, '\n')
              print("Gold: " + str(

      (I came up with my own method of tracking gold. I made it a value like HP instead of an item like a weapon)

      1. Waylon

        It turns out the solution is simply finding a way to check if the player has already visited the room. I’ve tried a couple of ideas but I can’t seem to figure out. Can anyon give me a hand?

Leave a Reply

Your email address will not be published. Required fields are marked *