Blitting images onto a tile that is part of a grid in pygame

# User-defined functions
def main():
    # initialize all pygame modules (some need initialization)
    pygame.init()
    # create a pygame display window
    pygame.display.set_mode((500, 400))
    # set the title of the display window
    pygame.display.set_caption('Memory')   
    # get the display surface
    w_surface = pygame.display.get_surface() 
    # create a game object
    game = Game(w_surface)

    # start the main game loop by calling the play method on the game
#object
    game.play() 
    # quit pygame and clean up the pygame window
    pygame.quit() 
# User-defined classes
class Game:
    # An object in this class represents a complete game.
    def __init__(self, surface):
      # Initialize a Game.
      # - self is the Game to initialize
      # - surface is the display window surface object

      self.surface = surface
      self.bg_color = pygame.Color('black')
      self.FPS = 60
      self.game_Clock = pygame.time.Clock()
      self.close_clicked = False
      self.continue_game = True

      Tile.set_surface(self.surface)              
      grid_size = 4
      self.create_grid(grid_size)
    def create_grid(self, grid_size):
      # Creates a grid of tiles that is grid_size x grid_size in size.

      self.grid = [ ]
      # this for loop creates each row in our grid     
      for row_num in range(grid_size):
          new_row = self.create_row(row_num, grid_size)
          self.grid.append(new_row)
    def create_row(self, row_num, size):
      # Create one row in a grid. Each row contains size Tiles. a
#row_num is
      # required for calculating the tile's x,y coordinates on screen
      #  -  row_num: the nth row of the grid being created
      #  -   size  : the number of tiles in the row 
      # returns the newly created row'
      image_1=pygame.image.load('image1.bmp')
      image_2=pygame.image.load('image2.bmp')
      image_3=pygame.image.load('image3.bmp')
      image_4=pygame.image.load('image4.bmp')
      image_5=pygame.image.load('image5.bmp')
      image_6=pygame.image.load('image6.bmp')
      image_7=pygame.image.load('image7.bmp')
      image_8=pygame.image.load('image8.bmp')
      pygame_image_surfaces=[]
      pygame_image_surfaces.append(image_1)
      pygame_image_surfaces.append(image_2)
      pygame_image_surfaces.append(image_3)
      pygame_image_surfaces.append(image_4)
      pygame_image_surfaces.append(image_5)
      pygame_image_surfaces.append(image_6)
      pygame_image_surfaces.append(image_7)
      pygame_image_surfaces.append(image_8)
      pygame_image_surfaces=pygame_image_surfaces+pygame_image_surfaces


      random.shuffle(pygame_image_surfaces)
      image_surfaces=pygame_image_surfaces      





      tile_height = self.surface.get_height() // size
      tile_width = 3/4*self.surface.get_width() // size
      one_row = [ ]
      for col_num in range(size):
          y = row_num * tile_height
          x = col_num * tile_width
          pos = (x,y)
          one_tile = Tile(pos, tile_width, tile_height)
          i=0
          content = image_surfaces[i]
          i+=1
          one_tile.set_content(content)
          one_row.append(one_tile)
      return one_row
    def play(self):
      # Play the game until the player presses the close box.
      # - self is the Game that should be continued or not.
      while not self.close_clicked:  # until player clicks close box
          # play frame
          self.handle_events()
          self.draw()

          if self.continue_game:
            self.update()
            self.decide_continue()
          self.game_Clock.tick(self.FPS) # run at most with FPS Frames
#Per Second 
    def handle_events(self):
      # Handle each user event by changing the game state
#appropriately.
      # - self is the Game whose events will be handled
      events = pygame.event.get()
      for event in events:
          if event.type == pygame.QUIT:
            self.close_clicked = True
          if event.type == pygame.MOUSEBUTTONDOWN:
            self.handle_mouse_click(event)
    def handle_mouse_click(self, event):
      # responds to one mouse click on screen; that means changing the
      # content of a tile if it is empty.
      print("Screen was clicked at " + str(event.pos))
    def draw(self):
      # Draw all game objects.
      # - self is the Game to draw
      self.surface.fill(self.bg_color) # clear the display surface
#first
      for row in self.grid:
          for tile in row:
            tile.draw()
      pygame.display.update() # make the updated surface appear on the
    def update(self):
      # Update the game objects for the next frame.
      # - self is the Game to update
      pass
    def decide_continue(self):
      # Check and remember if the game should continue
      # - self is the Game to check    
      return True
class Tile:
    # A tile represents one location on a grid. Tiles hold content

    # class attributes that are common to all tiles
    surface = None
    fg_color = pygame.Color("white")
    bg_color = pygame.Color("black")
    border_width = 3
    @classmethod
    def set_surface(cls, surface):
      # sets the class attribute, surface
      cls.surface = surface   
    def __init__(self, screen_position, width, height):
      # initialize one instance of our Tile class. Tiles represent
      # one 'position' in our  board.
      #  - self: the tile being initialized
      #  - screen_position: the [x, y] coordinates to draw the tile at
      #  - width: the width of the tile
      #  - height: the height of the tile
      self.screen_position = screen_position
      self.content = ''
      # create a rectangle defining our boundaries
      x, y = screen_position
      self.rect = pygame.Rect(x, y, width, height)
    def draw_content(self):
      image_1=pygame.image.load('image1.bmp')
      image_2=pygame.image.load('image2.bmp')
      image_3=pygame.image.load('image3.bmp')
      image_4=pygame.image.load('image4.bmp')
      image_5=pygame.image.load('image5.bmp')
      image_6=pygame.image.load('image6.bmp')
      image_7=pygame.image.load('image7.bmp')
      image_8=pygame.image.load('image8.bmp')
      pygame_image_surfaces=[]
      pygame_image_surfaces.append(image_1)
      pygame_image_surfaces.append(image_2)
      pygame_image_surfaces.append(image_3)
      pygame_image_surfaces.append(image_4)
      pygame_image_surfaces.append(image_5)
      pygame_image_surfaces.append(image_6)
      pygame_image_surfaces.append(image_7)
      pygame_image_surfaces.append(image_8)
      pygame_image_surfaces=pygame_image_surfaces+pygame_image_surfaces


      random.shuffle(pygame_image_surfaces)
      image_surfaces=pygame_image_surfaces
      for i in range(len(image_surfaces)):
          Tile.surface.blit(i)





      #Tile.surface.blit(text_img, text_pos)
    def draw(self):
      # draw the contents of a tile to its surface. 
      #  - self: the tile being drawn
      self.draw_content()
      pygame.draw.rect(Tile.surface, Tile.fg_color, self.rect,
Tile.border_width) 
    def set_content(self, new_content):

      #   - self: the tile whose content is being updated

      self.content = new_content
main()

Trying to create a memory game in pygame but I'm having problems trying to blit the images onto each individual tile and would like some help troubleshooting. What I'm trying to do is from the list of image files that are now surface objects, I would like to blit one onto each tile. For some reason though my logic is wrong. I'm not sure if this stuff should go in my game class or my tile class since its describing the tile rather than the game.

Tldr: don't know how to blit the images onto each tile from a list


Solution 1:

First of all, t he code which defines and loads the images, can be simplified a lot:

il = ['image' + str(i) + '.bmp' for i in range(1,9)]
pygame_image_surfaces = [pygame.image.load(os.path.join(path, name)) for name in imagenames]

The image which is associated to a Tile is stored in the instance attribute self.content of the Tile object. Use this attribute to draw the tile:

class Tile:

    # [...]

    def draw_content(self):
        image_rect = self.content.get_rect(center = self.rect.center)
        Tile.surface.blit(self.content, image_rect)

    def draw(self):
        # draw the contents of a tile to its surface. 
        #  - self: the tile being drawn
        self.draw_content()
        pygame.draw.rect(Tile.surface, Tile.fg_color, self.rect, Tile.border_width) 

    def set_content(self, new_content):
        #   - self: the tile whose content is being updated
        self.content = new_content

Create 1 random list of images. And use this list to set the images for the entire grid of tiles:

class Game:

    # [...]

    def create_grid(self, grid_size):
        # Creates a grid of tiles that is grid_size x grid_size in size.

        imgnames = ['image' + str(i) + '.bmp' for i in range(1,9)]
        image_surfaces = [pygame.image.load(os.path.join(path, name)) for name in imgnames]
        image_surfaces = image_surfaces + image_surfaces
        random.shuffle(image_surfaces)

        self.grid = []
        # this for loop creates each row in our grid  
        for row_num in range(grid_size):
            new_row = self.create_row(row_num, grid_size, image_surfaces)
            self.grid.append(new_row)

    def create_row(self, row_num, size, images):
        # Create one row in a grid. Each row contains size Tiles.
        # required for calculating the tile's x,y coordinates on screen
        #  -  row_num: the nth row of the grid being created
        #  -   size  : the number of tiles in the row 
        # returns the newly created row'

        tile_height = self.surface.get_height() // size
        tile_width = 3/4*self.surface.get_width() // size
        new_row = []
        for col_num in range(size):
              pos = (row_num * tile_height + 10, col_num * tile_width + 10)
              content = images[row_num*size + col_num]
              one_tile = Tile(pos, tile_width, tile_height)
              one_tile.set_content(content)
              new_row.append(one_tile)
        return new_row