Page 1 of 1

Odd Table Math Dilemma

Posted: Sat Mar 21, 2015 3:39 am
by MicroMacro
So, as I've posted help about before, I am rewriting a level editor for my game. I'm working on placing (placing is done, actually) and now I need to work on deleting tiles. My code right now is a for loop that gets the length of the tiles table (where all the data is stored) and then draws that tile there. I want to use table.remove to delete a tile but.. (prepare for a bad explanation)

Say tiles has a length of ten. If I remove tile #5, tiles now has a length of 9, but still has tile #10. Problem is, this for loop will not reach that 10th tile, because it runs for only 9. How do I get it to accommodate for this? A variable?

I hope I explained it well enough for you to understand. Before, it would set the tile's ID to 0 (which was a blank image), but kept it's X and Y. Problem with this is then that tile is there forever, and eventually will slow the editor down if a large map is being built, and one needs to delete tiles.

Thanks!
-Eric

Re: Odd Table Math Dilemma

Posted: Sat Mar 21, 2015 3:58 am
by arampl
I wonder why do you need "id" field at all?
Your table "tiles" is a simple indexed array so "tile[tiles.id]" is the same as "tile".

EDIT: I'm little lost in your data structure... :)

Re: Odd Table Math Dilemma

Posted: Sat Mar 21, 2015 4:09 am
by MicroMacro
So, tiles is a table that holds all the data for my tiles.
tiles[1] holds all the information for tile #1.
It looks like this:
tiles[1].x = 10
tiles[1].y = 10
tiles[1].id = 1

So, if I have 10 tiles (1-10), and remove tile #5, I have tiles 1,2,3,4,6,7,8,9,10, which is 9 objects. That for loop only does "for i=1,#tiles do" (which would be 9). So, it would draw 1,2,3,4,6,7,8,9 (skips over the empty 5), but not for the 10 tile. How do I accommodate for that?

Re: Odd Table Math Dilemma

Posted: Sat Mar 21, 2015 4:13 am
by arampl
If you remove 5th element from t = {"1", "2", "3", "4", "5", "6", "7", "8"} (#t = 8) for example
then table becomes simply {"1", "2", "3", "4", "6", "7", "8"} with 7 elements so #t becomes = 7
Your for i = 1, #t loop will always reach all elements (if table contains only integer keys).
IMHO Problem is that you use "id" field, which of course becomes outdated after removing element.
IMHO tile[1].id = 1 is useless.

You can use other loop types (like "foreach" loop in other languages):

Code: Select all

-- indexed array (all keys are integers)
t = {}
t[1] = "Fire"
t[2] = "Water"
t[3] = "Air"
t[4] = "Earth"

-- hash table
t2 = {}
t2["fire"]	= "Fire"
t2["water"]	= "Water"
t2["air"]	= "Air"
t2["earth"]	= "Earth"

function show()

	print("\nsimple loop:\n")

	for i = 1, #t do
		print(i, t[i])
	end

	print("\nforeach with only integer keys:\n")

	for k, v in ipairs(t) do
		print(k, v)
	end

	print("\nforeach with non-integer keys:\n")

	for k, v in pairs(t2) do
		print(k, v)
	end
end

print("******************")

show()

table.remove(t, 2)
t2["water"] = nil

print('\n ********* AFTER REMOVING 2ND ELEMENT ("water") ********')

show()
OUTPUT:

******************

simple loop:

1 Fire
2 Water
3 Air
4 Earth

foreach with only integer keys:

1 Fire
2 Water
3 Air
4 Earth

foreach with non-integer keys:

water Water
fire Fire
earth Earth
air Air

********* AFTER REMOVING 2ND ELEMENT ("water") ********

simple loop:

1 Fire
2 Air
3 Earth

foreach with only integer keys:

1 Fire
2 Air
3 Earth

foreach with non-integer keys:

fire Fire
earth Earth
air Air

P.S. Table can be mixed with integer and non-integer keys (table with 2 parts).

Re: Odd Table Math Dilemma

Posted: Sat Mar 21, 2015 9:44 am
by micha
Hi Micromacro,

what you want to do can be achieved with table.remove.

Code: Select all

a = {'one','two','three','four'}
for i,v in ipairs(a) do
  print(v)
end -- prints one, two, three, four

table.remove(a,3) -- remove the third entry

for i,v in ipairs(a) do
  print(v)
end -- prints one, two, four
However, for tiles it is a good idea to use the index as coordinates directly. Instead of numbering tiles arbitrarily by the order they are created, number them by their coordinates. Here is an example of the idea:
This is what you have:

Code: Select all

tile[1].x = 3
tile[1].y = 4
tile[1].id = 7
Instead I suggest this kind of notation:

Code: Select all

tile[3][4] = 7
That way the memory structure resembles the spatial structure of the tiles. Image you have some coordinates and want to find out, what kind of tile there is. In you notation, you would need a for loop to check of all tiles and you have to compare the coordinates to the given ones. In my suggested way, you can immediately access the id of a tile at any position.
This was a very short explanation. If you need to know more, please ask.

Re: Odd Table Math Dilemma

Posted: Sat Mar 21, 2015 11:54 am
by s-ol
Sometimes keeping redundant data like the x and y values is reasonable. The storage of the id is what really makes no sense (to me).

The actual problem he has is the deletion in a loop over a same table. The easiest solution is this one:

Code: Select all

for i=#tbl,0,-1 do -- go back-to-front
  if shouldRemove(tbl[i]) then
    table.remove(tbl, i)
  end
end
You might even think about using a "set" type table to hold all types if the index was only there to access an item without a search:

Code: Select all

-- insertion:
local newTile = { x=15, y=46 }
tbl[newTile] = newTile

-- deletion:
tbl[sometile] = nil

-- iterarion:
for tile,_ in pairs(tbl) do
  tile:doSomething()
end

Re: Odd Table Math Dilemma

Posted: Sat Mar 21, 2015 12:35 pm
by MicroMacro
I completely forgot to tell you all that the ID is for the type of tile it is. I've got a bunch of different tile images that it goes through. Tile ID #1 is grass.

Woops. :\

Re: Odd Table Math Dilemma

Posted: Sat Mar 21, 2015 12:39 pm
by MicroMacro
Here's that for loop that's wrong:

Code: Select all

function editor.drawWorld()
	for i=1, #tiles do
		if tile[tiles[i].id] ~= nil then
			love.graphics.draw(tile[tiles[i].id],tiles[i].x,tiles[i].y)
		end
	end
end
Sorry about that.

Re: Odd Table Math Dilemma

Posted: Sat Mar 21, 2015 12:53 pm
by kikito
I would just create a new type of tile called "empty" or "void". Instead of "removing the earth tile" from position 6, replace it with an empty tile, doing something like tiles[6] = emptyTile. emptyTiles are like regular tiles, except that they don't do nothing when drawn, they don't collide with anything, etc.

Your world size remains the same all the time and you don't have to fight with indexes at all. As a bonus point, inserting tiles is also very easy, and you can start with a map with holes on it.