Search code examples
lualua-tablelove2dminesweeper

How to initialize a table with tables in Lua?


A friend and I try to write a mine sweeper program in Lua using the Löve framework. So far the code needs to see if a box (a cell) is checked and then draw it. We are new to Lua, the program now has the flaw that it only works on the lower right box.

UPDATE: Looking at it now I see that the values of the initialized GameBoard all have the same value (i.e., GameBoard[1] till GameBoard[150] are all identical cells).

Here's the code:

conf.lua has some global variables defined:

function love.conf(t)

    -- Global variables.
    CELL_SIZE = 40
    NUM_ROWS = 15
    NUM_COLS = 10
    STATS_HEIGHT = 100
    AMOUNT_OF_CELLS = NUM_ROWS * NUM_COLS
    GRID_WIDTH = 400
    GRID_HEIGHT = 700

end

Here's the relevant failing code in main.lua (it goes wrong in the load method where the GameBoard is filled with Cells.

--  The Cell table is used for every individual square on 
--  the gameboard
Cell = {}

-- The Gameboard (150 Cell objects)
GameBoard = {}

--  The function new belongs to Cell and spawns a new object (a table)
--  with the same attributes as Cell.
function Cell:new(i, j)

--  each cell knows:
    --  its x- and y-coordinates.
    self.x_min = (i-1) * CELL_SIZE 
    self.x_max = (CELL_SIZE-1) + (i-1) * CELL_SIZE
    self.y_min = STATS_HEIGHT + (j-1) * CELL_SIZE 
    self.y_max = STATS_HEIGHT + (CELL_SIZE-1) + (j-1) * CELL_SIZE

    --  if it is a mine (determined with random number generator)
    isMine =  (math.random(1, 8) % 8 == 0) -- Roughly 0.15 (1/7) times true (is a mine)
    self.isMine = isMine

    --  do not check the mine initially
    self.checked = false

    --  return the cell object
    return self;

end


--  love.load is a love-function that is called once when the game
--  starts.
function love.load()

    -- The index of the cell on the GameBoard (ranging from 1 to 150)
    local index = 1

    --  Build a two dimensional table of Cell-objects
    for i = 1, NUM_COLS, 1 do
        for j = 1, NUM_ROWS, 1 do       
            GameBoard[ index ] = Cell:new( i, j )
            index = index + 1
        end
    end
end

The result is that all boxes have the values of the lower box with index 150 (the latest since NUM_ROWS * NUM_COLS = 150). All elements (Cells) of the table (Gameboard) have the same the x and y values set in the Cell:new method.

It would be appreciated if someone could tell us how to properly initialize and access a table of tables.


Solution

  • In the function Cell:new, self is the table Cell itself, so you are returning the same table every time.

    A simple fix is to create a new table instead:

    function Cell:new(i, j)
        local t = {}
    
        t.x_min = (i-1) * CELL_SIZE 
        --omit the rest
    
        return t;
    end
    

    For future improvement, you may be interested in another way, which implements prototype:

    function Cell:new(i, j)
        local o = {}
        setmetatable(o, self)
        self.__index = self
    
        self.x_min = (i-1) * CELL_SIZE 
        --omits rest
    
        return o;
    end
    

    Read PiL: Object-Oriented Programming for further information.