Odd Table Math Dilemma

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
MicroMacro
Citizen
Posts: 92
Joined: Fri May 30, 2014 2:30 am
Location: Boston, MA, USA
Contact:

Odd Table Math Dilemma

Post 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
https://github.com/ebernerd- where you can find all my work.
User avatar
arampl
Party member
Posts: 248
Joined: Mon Oct 20, 2014 3:26 pm

Re: Odd Table Math Dilemma

Post 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... :)
User avatar
MicroMacro
Citizen
Posts: 92
Joined: Fri May 30, 2014 2:30 am
Location: Boston, MA, USA
Contact:

Re: Odd Table Math Dilemma

Post 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?
https://github.com/ebernerd- where you can find all my work.
User avatar
arampl
Party member
Posts: 248
Joined: Mon Oct 20, 2014 3:26 pm

Re: Odd Table Math Dilemma

Post 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).
User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: Odd Table Math Dilemma

Post 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.
User avatar
s-ol
Party member
Posts: 1077
Joined: Mon Sep 15, 2014 7:41 pm
Location: Cologne, Germany
Contact:

Re: Odd Table Math Dilemma

Post 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

s-ol.nu /blog  -  p.s-ol.be /st8.lua  -  g.s-ol.be /gtglg /curcur

Code: Select all

print( type(love) )
if false then
  baby:hurt(me)
end
User avatar
MicroMacro
Citizen
Posts: 92
Joined: Fri May 30, 2014 2:30 am
Location: Boston, MA, USA
Contact:

Re: Odd Table Math Dilemma

Post 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. :\
https://github.com/ebernerd- where you can find all my work.
User avatar
MicroMacro
Citizen
Posts: 92
Joined: Fri May 30, 2014 2:30 am
Location: Boston, MA, USA
Contact:

Re: Odd Table Math Dilemma

Post 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.
https://github.com/ebernerd- where you can find all my work.
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: Odd Table Math Dilemma

Post 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.
When I write def I mean function.
Post Reply

Who is online

Users browsing this forum: No registered users and 48 guests