Python - IndexError: string index out of range (Beginner)

11,534

y is getting up to len(MAP_HEIGHT) - 1 (because of the range call); MAP_HEIGHT = len(MAP_FILE); MAP_FILE is a list with six elements.

Thus y will take the values 0, 1, 2, 3, 4, 5. However, the string only has four values, so trying to access the fifth or sixth character will fail.

I think you've tangled map height and map width (it's indexed by [y][x] and you access it by [x][y]).

Share:
11,534
YAS
Author by

YAS

Updated on June 26, 2022

Comments

  • YAS
    YAS almost 2 years

    first of all, sorry if this is already answered I've looked through past Q's but no luck.

    My problem is: I've gone through the Python+libtcod tutorial on Roguebasin once and doing it again while making my own modifications.

    I'm trying to make a hardcoded map instead of a randomly generated one.

    The code so far will not show a window or anything I'm just running and hope it closes with no errors. BUT, I keep getting this:

    Traceback (most recent call last):
      File "superrogue.py", line 85, in <module>
        make_map()
      File "superrogue.py", line 68, in make_map
        if MAP_FILE[x][y] in TILE_NAMES:    #Find the tile's name---
    IndexError: string index out of range
    

    The whole "string index out of range" is what I've been beating my head against the wall all afternoon and evening.

    Here's the code so far:

    #---Imports-------------------------------------------------------------
    import libtcodpy as libtcod
    
    #---Program Labelings---------------------------------------------------
    TITLE = 'Roguetest'
    VERSION = '0.01a'
    
    #---Setup Variables-----------------------------------------------------
    SCREEN_WIDTH = 80
    SCREEN_HEIGHT = 50
    LIMIT_FPS = 20
    #MAP_FILE = open('Maps/Test.txt', 'r')
    #MAP_FILE = MAP_FILE.readlines()
    MAP_FILE = ['XXXX',
                'X==X',
                'X..X',
                'X..X',
                'X==X',
                'XXXX',
                ]
    MAP_WIDTH = len(MAP_FILE[0])
    print MAP_WIDTH
    MAP_HEIGHT = len(MAP_FILE)
    print MAP_HEIGHT
    
    
    #---Dictionaries--------------------------------------------------------------
    COLORS = {
                'dark_new' : libtcod.Color(255, 0, 255),
                'light_new' : libtcod.Color(255, 0, 255),
                'dark_pavement' : libtcod.Color(20, 20, 20),
                'light_pavement' : libtcod.Color(50, 50, 50),
                'dark_sidewalk' : libtcod.Color(80, 80, 80),
                'light_sidewalk' : libtcod.Color(120, 120, 120),
                'dark_wall' : libtcod.Color(100, 100, 100),
                'light_wall' : libtcod.Color(180, 180, 180)
                }
    
    TILE_NAMES = {
                    'X' : 'wall',
                    '.' : 'pavement',
                    '=' : 'sidewalk'
                    }
    
    #---Classes-------------------------------------------------------------
    class Tile:
        def __init__(self, name):
            self.name = name
            self.darkcolor = COLORS['dark_' + self.name]
            self.lightcolor = COLORS['light_' + self.name]
            self.blocks = False
            self.blocks_sight = False
            self.inside = False
    
    
    #---Functions-----------------------------------------------------------
    def make_map():
    
        map = [[ Tile(name='new')
            for x in range(MAP_WIDTH) ]
                for y in range(MAP_HEIGHT) ]
    
        for x in range(MAP_WIDTH):
            for y in range(MAP_HEIGHT):
                print (x, y)
                if MAP_FILE[x][y] in TILE_NAMES:    #Find the tile's name---
                    map[x][y].name = TILE_NAMES[MAP_FILE[x][y]]
    
                map[x][y].darkcolor = COLORS['dark_' + map[x][y].name]
                map[x][y].lightcolor = COLORS['light_' + map[x][y].name]
    
                if MAP_FILE[x][y] == 'X':   #The WALL tile------------------
                    map[x][y].blocked = True
                    map[x][y].block_sight = True
                elif MAP_FILE[x][y] == '.': #The PAVEMENT tile--------------
                    map[x][y].blocked = False
                    map[x][y].block_sight = False
                elif MAP_FILE[x][y] == '=': #The SIDEWALK tile--------------
                    map[x][y].block_sight = False
                    map[x][y].ped_walkable = True
    
    
    make_map()
    

    Thanks.

    • gfortune
      gfortune over 12 years
      This can't be your actual code. MAP_FILE has a , on the last line which would result in a syntax error. Also, what does your print of MAP_HEIGHT and MAP_WIDTH show along with the x,y printed right before the exception?
    • tzaman
      tzaman over 12 years
      Actually, trailing commas are legal in lists.
    • gfortune
      gfortune over 12 years
      Gah, sure enough. Must be SQL clouding my brain. Regardless, I'm pretty certain that's not the actual code he's running and it would be immensely useful to see the index and length numbers that he's printing.
    • Chris Morgan
      Chris Morgan over 12 years
      @gfortune: you could try running it... you'll need to blank out the libtcod.Color stuff if you don't have the libtcodpy module, but that's not hard. Or run it in your brain and you'll see why it's going wrong.
  • gfortune
    gfortune over 12 years
    Oh, sure enough. The way his map is setup, I think his list is indexing as map[y][x] instead of map[x][y]
  • Niall Byrne
    Niall Byrne over 12 years
    Good catch, x and y are swapped indeed.
  • YAS
    YAS over 12 years
    So, if I understand it right, the list looks like it is 4 wide and 6 high but is indexed as 6 wide and 4 high?
  • Chris Morgan
    Chris Morgan over 12 years
    @YAS: you're trying to access it as though it's 6 wide and 4 high. The structure is indexed first by height, then by width, whereas you are trying to access it the other way. If you switch the [x][y] to [y][x] (and swap the positions of the x and y loops for logic's sake and also, I think, to increase performance), it'll fix it.
  • gfortune
    gfortune over 12 years
    The outer portion of the list (map[i]) gives you rows. Picking a particular row (map[i]) is the same as picking the "y" coordinate. Once you've picked a row, the item inside the row is the column (map[i][j]) and picking a column corresponds to picking the "x" coordinate. Does that help?