I'm still on the drawing board, but have a first draft for the key generation (haven't run it yet, and have yet to start tackling the reverse direction, but it should be possible to decompose the sum into its 3 parts, and from there into the original parameters).
Basically the "new" logic is:
- Sum up all the indices in the feature shell rows prior to the current row.
- Sum up all the indices in the feature shells prior to the current one in the current row, taking feature shell processing direction into account, as well as whether it's a complete shell or a last, reduced size, one (and if going right to left the first shell is narrower than the rest).
- sum up all the indices in the currently processed feature shell, accounting for all the complications.
The key should be the sum of the three parts.
Unfortunately the observations don't help much, as the logic was fundamentally flawed in that it tried to generate indices based on the row length while inside a feature shell, which is plain wrong.
Edit: OK, I've finally managed to get a new version of the key/indices generation logic. Again, I haven't tested it against the real code, so it may still use an incorrect algorithm, although I'm reasonably confident it matches what I think it is.
function key_of (x, y, i, k)
local world_last_x = df.global.world.world_data.world_width - 1
local world_last_y = df.global.world.world_data.world_height - 1
local fs_y_offset = math.floor (y / 16) * 16
local y_offset
local fs_left = y % 32 < 16
local fs_x_offset
local x_offset
local x_tail = df.global.world.world_data.world_width % 16
local y_tail = df.global.world.world_data.world_height % 16
local key
local y_base
local x_base
local index
if fs_left then
fs_x_offset = math.floor (x / 16) * 16
x_offset = x - fs_x_offset
elseif world_last_x - x < x_tail then
fs_x_offset = 0
x_offset = world_last_x - x
else
fs_x_offset = math.floor ((world_last_x - x - x_tail) / 16) * 16 + x_tail
x_offset = (world_last_x - x) - fs_x_offset
end
if x % 2 == 0 then -- Assumes the X dimension is an uneven number, but the search doesn't work if it isn't...
y_offset = y % 16
elseif world_last_y - math.floor (y / 16) * 16 < 16 then
y_offset = y - world_last_y
else
y_offset = 15 - y % 16
end
-- All the tiles in the prior feature shell block rows.
--
y_base = fs_y_offset * df.global.world.world_data.world_width * 256
if y <= world_last_y - y_tail then
x_base = fs_x_offset * 16 * 256 -- All feature shells before this one in this row
else
x_base = fs_x_offset * y_tail * 256 -- All feature shells before this one in this row
end
if y <= world_last_y - y_tail then
index = i + k * 16 + x_offset * 16 * 256 + y_offset * 256
else
index = i + k * 16 + x_offset * y_tail * 256 + y_offset * 256
end
key = y_base + x_base + index
-- dfhack.println ("key_of:", x, y, i, k, key, y_base, x_base, index, fs_left, fs_x_offset, x_offset, fs_y_offset, y_offset)
return key
end
-------------------------------
function indices_of (key)
local world_last_x = df.global.world.world_data.world_width - 1
local world_last_y = df.global.world.world_data.world_height - 1
local x
local y
local i = key % 16
local k = math.floor ((key % 256) / 16)
local fs_y = math.floor (key / 256) % df.global.world.world_data.world_height
local fs_y_offset = math.floor (key / (df.global.world.world_data.world_width * 256 * 16)) * 16
local y_offset
local fs_left = (math.floor (key / (df.global.world.world_data.world_width * 256 * 16)) % 2) == 0
local x_tail = df.global.world.world_data.world_width % 16
local y_tail = df.global.world.world_data.world_height % 16
local y_base = math.floor (key / (df.global.world.world_data.world_width * 256 * 16)) * df.global.world.world_data.world_width * 256 * 16
local fs_x_offset
local x_offset
local x_base
local index
if fs_left then
if world_last_y - fs_y_offset >= 16 then
fs_x_offset = math.floor ((key - y_base) / 65536) * 16
x_base = fs_x_offset * 256 * 16
else
fs_x_offset = math.floor ((key - y_base) / (y_tail * 16 * 256)) * 16
x_base = fs_x_offset * 256 * y_tail
end
else
if world_last_y - fs_y_offset >= 16 then
if key - y_base < x_tail * 16 * 256 then
fs_x_offset = 0
x_base = 0
else
fs_x_offset = math.floor ((key - y_base - x_tail * 16 * 256) / 65536) * 16 + x_tail
x_base = fs_x_offset * 256 * 16
end
else
if key - y_base < x_tail * y_tail * 256 then
fs_x_offset = 0
x_base = 0
else
fs_x_offset = math.floor ((key - y_base - x_tail * y_tail * 256) / (16 * 256 * y_tail)) * 16 + x_tail
x_base = fs_x_offset * 256 * y_tail
end
end
end
index = key - y_base - x_base
if world_last_y - fs_y_offset >= 16 then
x_offset = math.floor (index / (16 * 256))
y_offset = math.floor ((index - x_offset * 16 * 256) / 256)
else
x_offset = math.floor (index / (y_tail * 256))
y_offset = math.floor ((index - x_offset * y_tail * 256) / 256)
end
x = fs_x_offset + x_offset
if x % 2 == 1 then -- Relies on the world having an odd X dimension number and the odd ones always are reversed, regardless of traversing left or right.
if world_last_y - fs_y_offset >= 16 then
y_offset = 15 - y_offset
else
y_offset = y_tail - 1 - y_offset
end
end
y = fs_y_offset + y_offset
if not fs_left then
x = world_last_x - x
end
-- dfhack.println ("indices_of:", key, fs_left, y_base, x_base, index, fs_x_offset, x_offset, fs_y_offset, y_offset, "=>", x, y, i, k)
return x, y, i, k
end
-------------------------------
function x ()
local x_res
local y_res
local i_res
local k_res
for x_index = 0, df.global.world.world_data.world_width - 1 do
dfhack.println (x_index)
for y = 0, df.global.world.world_data.world_height - 1 do
for k = 0, 15 do
for i = 0, 15 do
x_res, y_res, i_res, k_res = indices_of (key_of (x_index, y, i, k))
if x_index ~= x_res or
y ~= y_res or
i ~= i_res or
k ~= k_res then
dfhack.printerr (key_of (x_index, y, i, k), x_index, y, i, k, "vs", x_res, y_res, i_res, k_res)
end
end
end
end
end
end
x ()
P.S. The script contains a number of constant declarations within the functions. These constants ought to be declared outside of them.