Same indexes in table?

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
FlashFire
Prole
Posts: 20
Joined: Thu Sep 11, 2014 12:44 am

Same indexes in table?

Post by FlashFire »

So I've been running into an error in my code, I've been calling json to convert a table into a string. The error I get is key 26 is both a number and string. So I look through the table that I supply json with and can't find any strings in it. Lua's type() function will return every index is a number.

So I decide to print off the whole table, which is a 2D map ( map[x][y] = value )

I used a for loop to print off each value.

But certain numbers are always on the list twice(Never beside each other though, such as:
number 40 number 26 Dirt
number 40 number 26 Dirt

Is the for loop not working correctly? Or is it actually listed twice in the table? Both are impossible?

Here is the code I'm running:

Code: Select all

function map:getIndexMap()
	local map = map:getMap()
	for xIndex,xValue in pairs(map) do
		for yIndex,yValue in pairs(xValue) do
			print(type(xIndex), xIndex,
				  type(yIndex), yIndex,
				  yValue)
		end
	end
end
Here is part of the output, every line with an x index of 30:

Code: Select all

number	30	number	0	Dirt
number	30	number	1	Dirt
number	30	number	2	Dirt
number	30	number	3	Dirt
number	30	number	4	Dirt
number	30	number	5	Dirt
number	30	number	6	Dirt
number	30	number	7	Dirt
number	30	number	8	Dirt
number	30	number	9	Dirt
number	30	number	10	Dirt
number	30	number	11	Dirt
number	30	number	12	Dirt
number	30	number	13	Dirt
number	30	number	14	Dirt
number	30	number	15	Dirt
number	30	number	16	Dirt
number	30	number	17	Dirt
number	30	number	18	Dirt
number	30	number	19	Dirt
number	30	number	20	Dirt
number	30	number	21	Dirt
number	30	number	22	Dirt
number	30	number	23	Dirt
number	30	number	24	Dirt
number	30	number	25	Dirt
number	30	number	26	Dirt
number	30	number	27	Dirt
number	30	number	28	Dirt
number	30	number	29	Dirt
number	30	number	30	Dirt
number	30	number	31	Dirt
number	30	number	32	Dirt
number	30	number	33	Dirt
number	30	number	34	Dirt
number	30	number	35	Dirt
number	30	number	36	Dirt
number	30	number	37	Dirt
number	30	number	38	Dirt
number	30	number	39	Dirt
number	30	number	40	Dirt
number	30	number	41	Dirt
number	30	number	42	DirtStone
number	30	number	43	DirtStone
number	30	number	44	DirtStone
number	30	number	45	DirtStone
number	30	number	46	Dirt
number	30	number	47	Dirt
number	30	number	48	Dirt
number	30	number	49	Dirt
number	30	number	50	Dirt
number	30	number	51	Stone
number	30	number	52	Stone
number	30	number	53	Stone
number	30	number	54	Stone
number	30	number	55	Stone
number	30	number	56	Stone
number	30	number	57	Stone
number	30	number	58	Stone
number	30	number	59	Stone
number	30	number	60	Stone
number	30	number	61	Stone
number	30	number	62	Stone
number	30	number	63	Stone
number	30	number	64	Stone
number	30	number	65	Stone
number	30	number	66	Stone
number	30	number	67	Stone
number	30	number	68	Stone
number	30	number	69	Stone
number	30	number	70	Stone
number	30	number	71	Stone
number	30	number	72	Stone
number	30	number	73	Stone
number	30	number	74	Stone
number	30	number	75	Stone
number	30	number	-2	Dirt
number	30	number	-11	Dirt
number	30	number	54	Dirt
number	30	number	-9	Dirt
number	30	number	26	Dirt
number	30	number	30	Dirt
number	30	number	-1	Dirt
number	30	number	53	Dirt
number	30	number	61	Dirt
number	30	number	52	Dirt
number	30	number	60	Dirt
number	30	number	27	Dirt
number	30	number	51	Dirt
number	30	number	-14	Dirt
number	30	number	-12	Dirt
number	30	number	-10	Dirt
number	30	number	58	Dirt
number	30	number	-8	Dirt
number	30	number	28	Dirt
number	30	number	-7	Dirt
number	30	number	32	Dirt
number	30	number	-6	Dirt
number	30	number	57	Dirt
number	30	number	-5	Dirt
number	30	number	-15	Dirt
number	30	number	63	Dirt
number	30	number	-4	Dirt
number	30	number	56	Dirt
number	30	number	62	Dirt
number	30	number	-13	Dirt
number	30	number	64	Dirt
number	30	number	31	Dirt
number	30	number	-3	Dirt
number	30	number	29	Dirt
number	30	number	-16	Grass
number	30	number	55	Dirt
number	30	number	59	Dirt
After y index 75, it starts doing almost random numbers, no idea why however.

You can find the full output at:
pastebin.com/2D4Q57h1
It is quiet lengthy though.
User avatar
I~=Spam
Party member
Posts: 206
Joined: Fri Dec 14, 2012 11:59 pm

Re: Same indexes in table?

Post by I~=Spam »

This isn't enough code to diagnose the problem because the problem is clearly somewhere else in your code not how you print the values... can you post a LOVE or something to that effect?
My Tox ID: 0F1FB9170B94694A90FBCF6C4DDBDB9F58A9E4CDD0B4267E50BF9CDD62A0F947E376C5482610
FlashFire
Prole
Posts: 20
Joined: Thu Sep 11, 2014 12:44 am

Re: Same indexes in table?

Post by FlashFire »

I am willing to post a LOVE file if needed, but what I want to know is how that is possible? As far as I know, the printing function should never have that output.

I would like to locate the error before trying to fix it.

Here are some major code parts

Code: Select all

function save.getData()
	--table containing all data needed to save, and a function to execute one
	local data = 
	{
		{ex = string.dump(function(x) stats.blockBroken = x    end), data = stats.blockBroken},
		{ex = string.dump(function(x) Camera.X = x             end), data = Camera.X},
		{ex = string.dump(function(x) Camera.Y = x             end), data = Camera.Y},
		{ex = string.dump(function(x) backpack.hotBar = x      end), data = backpack.hotBar},
		{ex = string.dump(function(x) backpack.items = x       end), data = backpack.items},
		{ex = string.dump(function(x) map:load(x)              end), data = map:getIndexMap()},
		{ex = string.dump(function(x) map:loadBackground(x)    end), data = map:getIndexBackground()},
		{ex = string.dump(function(x) --[[Do nothing]]         end), data = VERSION},
		{ex = string.dump(function(x) interface.loadAllData(x) end), data = interface.getAllData()}
	}
	return data
end

function save.saveFile(name,data)
	local data = save.getData()
	local file,error = love.filesystem.newFile(name,'w')
	for i,v in pairs(data) do
		print(i)
		--print('Saving: ' .. tostring(v))
		file:write(json:encode(v) .. '(~*$^')
	end
end
In this next code, if I set it to return an empty table it won't error.

Code: Select all

function map:getIndexMap()
	local map = map:getMap()
	local new = {}
	for xIndex,xValue in pairs(map) do
		for yIndex,yValue in pairs(xValue) do
			if not new[tonumber(xIndex)] then
				new[tonumber(xIndex)] = {}
			end
			print( type(xIndex),xIndex,type(yIndex),yIndex,yValue)
			if type(xIndex) == 'string' or type(yIndex) == 'string' then
				print('ERROR, found string in map.')
				print(xIndex,yIndex,yValue)
			end
			new[tonumber(xIndex)][tonumber(yIndex)] = 't'--data.itemInfo[yValue].index
		end
	end
	return new
end
I know the error appeared after creating the following piece of code:

Code: Select all

----------------
---chunk generation
----------------

chunk = {}
chunk.init = function()
	chunk.data = {}--chunks are 25x25
end

local blurTable = {1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9}

--set point of a fake map
function chunk.setPoint(x,y,value,map)
	if not map[x] then
		map[x] = {}
	end
	map[x][y] = value
end

--blur the map with a simple gaussian
function chunk.gaussian(map,pos,matrix)
	local tableSize = (#matrix)^.5
	local average = 0
	for x = 1,tableSize do
		for y = 0,tableSize-1 do
			local index = x+y
			local x = pos.X+x-(tableSize-1)/2
			local y = pos.Y+y-(tableSize-1)/2
			if map[x] and map[x][y] then
				average = average+map[x][y]*matrix[index]
			end
		end
	end
	map[pos.X][pos.Y] = average
end

--check 
function chunk.checkArea(map,pos)
	local value = false
	for i,v in pairs({Vector2.new(0,1),Vector2.new(0,-1),Vector2.new(1,0),Vector2.new(-1,0)}) do
		if map[v.X+pos.X] and map[v.X+pos.X][v.Y+pos.Y] == 1 then
			value = true
		end
	end
	return value
end


--Step the gaussain map, then convert to strings
function chunk.filterStep(map,oreValue,oreName)
	local resultMap = {}
	for xIndex,xValue in pairs(map) do
		resultMap[xIndex] = {}
		for yIndex,yValue in pairs(xValue) do
			if yValue > oreValue(yIndex) then --.66 then
				yValue = 1
			else
				yValue = 0
			end
			resultMap[xIndex][yIndex] = yValue
		end
	end
	for xIndex,xValue in pairs(resultMap) do
		for yIndex,yValue in pairs(xValue) do
			if yValue == 1 then
				if chunk.checkArea(resultMap,Vector2.new(xIndex,yIndex)) then
					resultMap[xIndex][yIndex] = oreName
				else
					resultMap[xIndex][yIndex] = ''
				end
			end
		end
	end
	return resultMap
end


--apply second arg to first arg only allowing allow arg
chunk.applyOre = function(first,second,allow)
	for xIndex,xValue in pairs(second) do
		for yIndex,yValue in pairs(xValue) do
			if yValue == allow then
				if not first[xIndex] then
					first[xIndex] = {}
				end
				first[xIndex][yIndex] = yValue
			end
		end
	end
	return first
end

--create a layer filled with block
chunk.createFakeLayer = function(block)
	layer = {}
	for x = 1,25 do
		layer[x] = {}
		for y = 1,25 do
			layer[x][y] = block
		end
	end
	return layer
end

function chunk.stepDirt(sound)
	for x = 1,25 do
		for y = 1,25 do
			if sound[x][y] >= .5 then
				sound[x][y] = 'Dirt'
			else
				sound[x][y] = 'Stone'
			end
		end
	end
	return sound
end

function chunk.dirtSound(id)
	--fill table with sound
	local sound = {}
	for x = 1,25 do
		for y = 1,25 do
			chunk.setPoint(x,y,random.range(0,100,x+id.X*25,y+id.Y*25,index)/100,sound)
		end
	end
	--linear thingy
	for y = 1,25 do
		for x = 1,25 do
			sound[x][y] = sound[x][y]*((25-y)/25)
		end
	end
	sound = chunk.stepDirt(sound)
	return sound
end

--dirt gen options
--start at 100, to 125
--2d sound, linear
---in dirt gen:
--copper
--make fire to smelt copper
--make clay smelter thingy


--Create chunk at x and y position for ores
chunk.createChunk = function(id,ores)
	if not chunk.data[id.X] then
		chunk.data[id.X] = {}
	end
	chunk.data[id.X][id.Y] = {}
	local chunkOres = {}
	chunkOres = chunk.applyOre(chunkOres,chunk.createFakeLayer('Stone'),'Stone')
	local index = 0
	if id.Y <= 2 then
		if id.Y == 2 then
			chunkOres = chunk.applyOre(chunkOres,chunk.dirtSound(id),'Dirt')
		else
			--create a new layer
			chunkOres = chunk.applyOre(chunkOres,chunk.createFakeLayer('Dirt'),'Dirt')
			--loop through all the dirt ores
			for oreIndex,oreValue in pairs(data.dirtOres) do
				index = index + 1

				local ore = {}
				for x = 1,25 do
					for y = 1,25 do
						chunk.setPoint(x,y,random.range(0,100,x+id.X*25,y+id.Y*25,index)/100,ore)
					end
				end

				for xIndex,xValue in pairs(ore) do
					for yIndex,v in pairs(xValue) do
						chunk.gaussian(ore,Vector2.new(xIndex,yIndex),blurTable)
						chunk.gaussian(ore,Vector2.new(xIndex,yIndex),blurTable)
						chunk.gaussian(ore,Vector2.new(xIndex,yIndex),blurTable)
						chunk.gaussian(ore,Vector2.new(xIndex,yIndex),blurTable)
					end
				end

				ore = chunk.filterStep(ore,oreValue.func,oreIndex)

				chunkOres = chunk.applyOre(chunkOres,ore,oreIndex)
			end
		end
	else
		--loop through all the ores
		for oreIndex,oreValue in pairs(ores) do
			index = index+1
			--create 2D map for the new ore
			local ore = {}
			--fill with white sound
			for x = 1,25 do
				for y = 1,25 do
					chunk.setPoint(x,y,random.range(0,100,x+id.X*25,y+id.Y*25,index)/100,ore)
				end
			end
			--blur the sound
			for xIndex,xValue in pairs(ore) do
				for yIndex,v in pairs(xValue) do
					chunk.gaussian(ore,Vector2.new(xIndex,yIndex),blurTable)
					chunk.gaussian(ore,Vector2.new(xIndex,yIndex),blurTable)
					chunk.gaussian(ore,Vector2.new(xIndex,yIndex),blurTable)
					chunk.gaussian(ore,Vector2.new(xIndex,yIndex),blurTable)
				end
			end
			--step sound
			ore = chunk.filterStep(ore,oreValue.func,oreIndex)
			--apply sound to chunk allowing oreIndex
			chunkOres = chunk.applyOre(chunkOres,ore,oreIndex)
		end
	end
	chunk.data[id.X][id.Y] = chunkOres
end

function chunk.checkChunk(x,y)
	local chunkX = x/25-x%25/25
	local chunkY = y/25-y%25/25
	--local posX = x%25+1
	--local posY = y%25+1

	if chunk.data[chunkX] == nil or chunk.data[chunkX][chunkY] == nil then
		print('Creating chunk:' .. chunkX .. ':' .. chunkY)
		chunk.createChunk(Vector2.new(chunkX,chunkY),data.ores)
		local chunk = chunk.data[chunkX][chunkY]
		for x = 1,25 do
			for y = 1,25 do
				if map.map[chunkX*25+x] == nil or map.map[chunkX*25+x][chunkY*25+y] == nil then
					map:setPoint(chunkX*25+x,chunkY*25+y,chunk[x][y])
					map:backgroundSetPoint(chunkX*25+x,chunkY*25+y,chunk[x][y])
				end
			end
		end
	end
end
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Same indexes in table?

Post by Robin »

FlashFire wrote:I am willing to post a LOVE file if needed, but what I want to know is how that is possible?
Well that's why we want you to post a .love. If something impossible happens, that generally means that one of your assumptions is wrong. Without seeing the whole .love, it's really hard for us to see what is really going on and then tell you.
Help us help you: attach a .love.
FlashFire
Prole
Posts: 20
Joined: Thu Sep 11, 2014 12:44 am

Re: Same indexes in table?

Post by FlashFire »

https://www.dropbox.com/s/76it2pddqsoza ... .love?dl=0

To simulate the problem dig down 10 blocks, and then exit the game, it should error.
User avatar
s-ol
Party member
Posts: 1077
Joined: Mon Sep 15, 2014 7:41 pm
Location: Cologne, Germany
Contact:

Re: Same indexes in table?

Post by s-ol »

print("40") and print(40) show the same output. This is the symptom, but the problem is somewhere else. Again, give us a .love and it will be much easier to help you.

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
FlashFire
Prole
Posts: 20
Joined: Thu Sep 11, 2014 12:44 am

Re: Same indexes in table?

Post by FlashFire »

S0lll0s wrote:print("40") and print(40) show the same output. This is the symptom, but the problem is somewhere else. Again, give us a .love and it will be much easier to help you.
That's why I did print(type(value),value), I know there is no difference visually when outputted. And no, it didn't ever print string.
User avatar
BlueWolf
Prole
Posts: 12
Joined: Fri May 29, 2015 7:55 pm

Re: Same indexes in table?

Post by BlueWolf »

From what I could tell, if you have any zeroes or negative numbers as keys in your table they will get converted to strings and added to table, that later on creates the JSON object. However if there are any duplicate number keys you'll get the error. However I have no idea why it fails on 26 when there are dozens duplicate number keys before that (I printed them from inside json.lua where they get checked for duplicates). From what I saw it should fail much sooner but for some reason it doesn't?

Here is piece of code that throws the error itself.

Code: Select all

for _, number_key in ipairs(number_keys) do
         local string_key = tostring(number_key)
         if map[string_key] == nil then
            table.insert(string_keys , string_key)
            map[string_key] = T[number_key]
         else
            self:onEncodeError("conflict converting table with mixed-type keys into a JSON object: key " .. number_key .. " exists both as a string and a number.", etc)
         end
If you print all the number keys you can see there are many many duplicates. Once the key is converted to string it is added to map table. When the same key comes up again the check for nil in map table should fail and produce the error. At least that's what I think code should do but I'm clearly wrong somewhere, cause when I checked for when key "5" was added it looked like there were bunch of duplicates, that didn't fire the nil check. I'm confused... :huh:
FlashFire
Prole
Posts: 20
Joined: Thu Sep 11, 2014 12:44 am

Re: Same indexes in table?

Post by FlashFire »

But how is any of the keys a string? I run the table I give it through the function:

Code: Select all

function map:getIndexMap()
	local map = map:getMap()
	local new = {}
	for xIndex,xValue in pairs(map) do
		for yIndex,yValue in pairs(xValue) do
			if not new[tonumber(xIndex)] then
				new[tonumber(xIndex)] = {}
			end
			print( type(xIndex),xIndex,type(yIndex),yIndex,yValue)
			if type(xIndex) == 'string' or type(yIndex) == 'string' then
				print('ERROR, found string in map.')
				print(xIndex,yIndex,yValue)
			end
			new[tonumber(xIndex)][tonumber(yIndex)] = data.itemInfo[yValue].index
		end
	end
	return new
end
Which can't find any strings in the table. Why are there strings in the table later?

Should I create a filter to remove any duplicate keys? But there shouldn't be any duplicate keys in the first place.
FlashFire
Prole
Posts: 20
Joined: Thu Sep 11, 2014 12:44 am

Re: Same indexes in table?

Post by FlashFire »

BlueWolf wrote:From what I could tell, if you have any zeroes or negative numbers as keys in your table they will get converted to strings and added to table, that later on creates the JSON object. However if there are any duplicate number keys you'll get the error. However I have no idea why it fails on 26 when there are dozens duplicate number keys before that (I printed them from inside json.lua where they get checked for duplicates). From what I saw it should fail much sooner but for some reason it doesn't?

Here is piece of code that throws the error itself.

Code: Select all

for _, number_key in ipairs(number_keys) do
         local string_key = tostring(number_key)
         if map[string_key] == nil then
            table.insert(string_keys , string_key)
            map[string_key] = T[number_key]
         else
            self:onEncodeError("conflict converting table with mixed-type keys into a JSON object: key " .. number_key .. " exists both as a string and a number.", etc)
         end
If you print all the number keys you can see there are many many duplicates. Once the key is converted to string it is added to map table. When the same key comes up again the check for nil in map table should fail and produce the error. At least that's what I think code should do but I'm clearly wrong somewhere, cause when I checked for when key "5" was added it looked like there were bunch of duplicates, that didn't fire the nil check. I'm confused... :huh:
Since JSON is recursive, it is possible that it printed the number 5 from a different table inside the entire table. Such as the key 5 exists at table[1][5] and also at table[2][5], so it can exist up to n times in table[1+n][5]. I don't know if that is the issue though.
Post Reply

Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 5 guests