## Best way to index out-of-bounds?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
milon
Citizen
Posts: 60
Joined: Thu Jan 18, 2018 9:14 pm

### Best way to index out-of-bounds?

I'm still pretty new to Lua, and I'm trying to wrap my head around best practices. I have a chunk of code that will occasionally index a 2D table with out-of-bounds values. If the 1st index is invalid, it crashes (fair enough since nil can't do anything with the 2nd index). I want the code to find the proper values for proper indices, and return nil for everything else. I'll add a bunch of error-checking if I need to, but that doesn't seem terribly elegant. I'm thinking metatables might be the answer here, but I'm not sure if this is considered best practice or not.

Here's my (functional!) reduced code:

Code: Select all

-- The goal is to be able to lookup ANY 2D index without tripping over an error

map = {w=10, h=10}
for x = 1, map.w do
map[x] = {}
for y = 1, map.h do
map[x][y] = love.math.random()
end
end

setmetatable(map, { __call = function(t, x, y) return x>0 and x<=t.w and y>0 and y<=t.h and t[x][y] or nil end })

print(map[2][5])
print(map[7][21])
--~ print(map[21][7])	-- THIS CRASHES
print(map(2,5))
print(map(7,21))
print(map(21,7))

Is this best practice? Why or why not? Is there any way to make it work with out-of-bounds [] references, or is __call() the only way to go? I don't really have a handle on metatables, by the way. I've been reading about them for days now, and I've just spent the last 2 hours getting this chunk of code to work.
Last edited by milon on Thu Mar 08, 2018 8:05 am, edited 1 time in total.

pgimeno
Party member
Posts: 1944
Joined: Sun Oct 18, 2015 2:58 pm
Location: Valencia, ES

### Re: Best way to index out-of-bounds?

Yes, you can make it work with the [] syntax:

Code: Select all

map = {w=10, h=10}
for x = 1, map.w do
map[x] = {}
for y = 1, map.h do
map[x][y] = love.math.random()
end
end

local dummy_table = {}

setmetatable(map, {__index = function(t, x)
if type(x) == "number" and x >= 1 and x <= rawget(t, "w") then
return rawget(t, x)
end
return dummy_table
end})

print(map[2][3])
print(map[7][21]) -- nil
print(map[21]) -- table xxx
print(map[21][7]) -- nil

The simplest approach is probably to use an accessor function which does the bounds checking, rather than a metatable.

Code: Select all

local function getmap(x, y)
if x < 1 or x > map.w or y < 1 or y > map.h then
return nil
end
return map[x][y]
end

I don't discuss best practices, since I see that as a "religious" topic.

raidho36
Party member
Posts: 1994
Joined: Mon Jun 17, 2013 12:00 pm

### Re: Best way to index out-of-bounds?

The best practice to go about out of bounds memory access is to make sure you never try to access out of bounds memory to start with. Fastest, too. It will take a bit of effort from you, but it's a best practice for a reason.

milon
Citizen
Posts: 60
Joined: Thu Jan 18, 2018 9:14 pm

### Re: Best way to index out-of-bounds?

Good answers, thank you both! I'll probably use an accessor function then, but thank you for the metatable info too. They're still strange and magical to me and this helps to demystify them a bit.

ivan
Party member
Posts: 1547
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

### Re: Best way to index out-of-bounds?

I'm with raidho on this one.
A common technique is to use 0-based indexing with modulus:

Code: Select all

local function getmap(x, y)
return map[x%map.w][y%map.h]
end

milon
Citizen
Posts: 60
Joined: Thu Jan 18, 2018 9:14 pm

### Re: Best way to index out-of-bounds?

Thanks, ivan. That's a pretty nice solution for wrapping. It's not what I want in this case, but I'll log it away for the future.

raidho36
Party member
Posts: 1994
Joined: Mon Jun 17, 2013 12:00 pm

### Re: Best way to index out-of-bounds?

Another common technique is to assert that index is within existing bounds. If your program is feeding invalid data to your functions, something is terribly wrong with it. That'd help debugging.

milon
Citizen
Posts: 60
Joined: Thu Jan 18, 2018 9:14 pm

### Re: Best way to index out-of-bounds?

It's not a bug, it's a feature! (Really!)
I'm working on a 2D RPG as a side hobby. Currently, I'm always drawing the player in the center of the screen and that means when I'm near the edge of a map, the graphics routine will try to look up an out-of-bounds region. Each map has a defined "default" tile to draw for the out-of-bounds areas. I made a helper function to handle the lookup and return the correct tile to draw. I may change this approach in the future, however, since the default-tile look isn't quite what I'm going for.

And yes, as soon as I have something worth showing I'll put up a .love file for everyone to play with / mock / etc.

tentus
Inner party member
Posts: 1060
Joined: Sun Oct 31, 2010 7:56 pm
Location: Appalachia
Contact:

### Re: Best way to index out-of-bounds?

In my last game I used the first tile of the map as a default, and drew a screen-sized spritebatch of it underneath the map, modulo'd to the same partial tile offset as the player. What this mean was that even we were looking over the edge of the map (or even if the map had partially transparent tiles in it), as long as the default tile was right I didn''t need to worry about seeing the background through. This made laying out compound tiles like dirt paths easier, and meant I could be a little looser with the player approaching the edges of the map.
Kurosuke needs beta testers

### Who is online

Users browsing this forum: artless, kinderalpha and 6 guests