260 lines
8.5 KiB
Lua
260 lines
8.5 KiB
Lua
--[[
|
|
Copyright (c) 2014, Robert 'Bobby' Zenz
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
* Redistributions of source code must retain the above copyright notice, this
|
|
list of conditions and the following disclaimer.
|
|
|
|
* Redistributions in binary form must reproduce the above copyright notice,
|
|
this list of conditions and the following disclaimer in the documentation
|
|
and/or other materials provided with the distribution.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
--]]
|
|
|
|
|
|
--- Various utility functions for working with arrays. An array is sub-form of
|
|
-- a array, the array is simply indexed with numbers like this:
|
|
--
|
|
-- local array = { 1 = "a", 2 = "b", 3 = "c" }
|
|
-- local array = { "a", "b", "c" }
|
|
arrayutil = {}
|
|
|
|
|
|
--- Finds the next matching column.
|
|
--
|
|
-- @param array The 2D array to search.
|
|
-- @param start_index Optional. The index at which to start. Defaults to 1, or
|
|
-- if the direction is reversed, the number of columns in
|
|
-- the array.
|
|
-- @param matcher Optional. The function that is used to determine if the column
|
|
-- matches or not. Is expected to take one argument, the item,
|
|
-- and return a boolean. The column matches if any of its items
|
|
-- matches this condition. Defaults to not nil and not empty
|
|
-- string.
|
|
-- @param reverse Optional. If the array should be serched backwards. Defaults
|
|
-- to false.
|
|
-- @return The index of the matching column. -1 if none was found.
|
|
function arrayutil.next_matching_column(array, start_index, matcher, reverse)
|
|
matcher = matcher or function(item)
|
|
return item ~= nil and item ~= ""
|
|
end
|
|
|
|
local current_column = 0
|
|
|
|
if reverse and start_index == nil then
|
|
for row_index = 1, #array, 1 do
|
|
local row = array[row_index]
|
|
|
|
current_column = math.max(current_column, #row)
|
|
end
|
|
else
|
|
current_column = start_index or 1
|
|
end
|
|
|
|
local had_column = true
|
|
|
|
while had_column do
|
|
had_column = false
|
|
|
|
for row_index = 1, #array, 1 do
|
|
local row = array[row_index]
|
|
|
|
if current_column >= 1 and current_column <= #row then
|
|
had_column = true
|
|
|
|
if matcher(row[current_column]) then
|
|
return current_column
|
|
end
|
|
end
|
|
end
|
|
|
|
if reverse then
|
|
current_column = current_column - 1
|
|
else
|
|
current_column = current_column + 1
|
|
end
|
|
end
|
|
|
|
return -1
|
|
end
|
|
|
|
--- Finds the next matching row.
|
|
--
|
|
-- @param array The 2D array to search.
|
|
-- @param start_index Optional. The index at which to start. Defaults to 1, or
|
|
-- if the direction is reversed, the number of rows in
|
|
-- the array.
|
|
-- @param matcher Optional. The function that is used to determine if the row
|
|
-- matches or not. Is expected to take one argument, the item,
|
|
-- and return a boolean. The row matches if any of its items
|
|
-- matches this condition. Defaults to not nil and not empty
|
|
-- string.
|
|
-- @param reverse Optional. If the array should be serched backwards. Defaults
|
|
-- to false.
|
|
-- @return The index of the matching row. -1 if none was found.
|
|
function arrayutil.next_matching_row(array, start_index, matcher, reverse)
|
|
matcher = matcher or function(item)
|
|
return item ~= nil and item ~= ""
|
|
end
|
|
|
|
local to = #array
|
|
local step = 1
|
|
|
|
if reverse then
|
|
start_index = start_index or #array
|
|
to = 1
|
|
step = -1
|
|
else
|
|
start_index = start_index or 1
|
|
end
|
|
|
|
for row_index = start_index, to, step do
|
|
local row = array[row_index]
|
|
|
|
for column_index = 1, #row, 1 do
|
|
if matcher(row[column_index]) then
|
|
return row_index
|
|
end
|
|
end
|
|
end
|
|
|
|
return -1
|
|
end
|
|
|
|
--- Finds the previous matching column.
|
|
--
|
|
-- @param array The 2D array to search.
|
|
-- @param start_index Optional. The index at which to start. Defaults to
|
|
-- the number columns in the array.
|
|
-- @param matcher Optional. The function that is used to determine if the column
|
|
-- matches or not. Is expected to take one argument, the item,
|
|
-- and return a boolean. The column matches if any of its items
|
|
-- matches this condition. Defaults to not nil and not empty
|
|
-- string.
|
|
-- @return The index of the matching column. -1 if none was found.
|
|
function arrayutil.previous_matching_column(array, start_index, matcher)
|
|
return arrayutil.next_matching_column(array, start_index, matcher, true)
|
|
end
|
|
|
|
--- Finds the previous matching row.
|
|
--
|
|
-- @param array The 2D array to search.
|
|
-- @param start_index Optional. The index at which to start. Defaults to
|
|
-- the number rows in the array.
|
|
-- @param matcher Optional. The function that is used to determine if the row
|
|
-- matches or not. Is expected to take one argument, the item,
|
|
-- and return a boolean. The row matches if any of its items
|
|
-- matches this condition. Defaults to not nil and not empty
|
|
-- string.
|
|
-- @return The index of the matching row. -1 if none was found.
|
|
function arrayutil.previous_matching_row(array, start_index, matcher)
|
|
return arrayutil.next_matching_row(array, start_index, matcher, true)
|
|
end
|
|
|
|
--- Removes empty rows and columns at the beginning and the end of the given
|
|
-- array.
|
|
--
|
|
-- @param array The array.
|
|
-- @param is_empty Optional. The function used for determining if the item is
|
|
-- empty. By default nil and an empty string is considered
|
|
-- empty. Expected is a function that takes one item and returns
|
|
-- a boolean.
|
|
function arrayutil.reduce2d(array, is_empty)
|
|
local first_row = arrayutil.next_matching_row(array, nil, is_empty)
|
|
local last_row = arrayutil.previous_matching_row(array, nil, is_empty)
|
|
|
|
local first_column = arrayutil.next_matching_column(array, nil, is_empty)
|
|
local last_column = arrayutil.previous_matching_column(array, nil, is_empty)
|
|
|
|
if last_row == -1 then
|
|
last_row = first_row
|
|
end
|
|
|
|
if last_column == -1 then
|
|
last_column = first_column
|
|
end
|
|
|
|
local reduced = {}
|
|
|
|
if first_row ~= -1 and first_column ~= -1 then
|
|
for row_index = first_row, last_row, 1 do
|
|
local row = array[row_index]
|
|
local reduced_row = {}
|
|
|
|
for column_index = first_column, last_column, 1 do
|
|
reduced_row[column_index - first_column + 1] = row[column_index]
|
|
end
|
|
|
|
reduced[row_index - first_row + 1] = reduced_row
|
|
end
|
|
end
|
|
|
|
return reduced
|
|
end
|
|
|
|
--- Reindexes the given 2D array, swapping the two dimensions.
|
|
--
|
|
-- @param data The array to reindex.
|
|
-- @param new_x The new startpoint for the first dimension.
|
|
-- @param new_y The new startpoint for the second dimension.
|
|
-- @return The reindexed array.
|
|
function arrayutil.swapped_reindex2d(data, new_x, new_y)
|
|
local reindexed_data = {}
|
|
|
|
for old_x = 1, constants.block_size, 1 do
|
|
local index_x = new_x + old_x - 1
|
|
reindexed_data[index_x] = {}
|
|
|
|
for old_y = 1, constants.block_size, 1 do
|
|
local index_y = new_y + old_y - 1
|
|
|
|
reindexed_data[index_x][index_y] = data[old_y][old_x]
|
|
end
|
|
end
|
|
|
|
return reindexed_data
|
|
end
|
|
|
|
--- Reindexes the given 3d array, swapping the two dimensions.
|
|
--
|
|
-- @param data The array to reindex.
|
|
-- @param new_x The new startpoint for the first dimension.
|
|
-- @param new_y The new startpoint for the second dimension.
|
|
-- @param new_z The new startpoint for the third dimension.
|
|
-- @return The reindexed array.
|
|
function arrayutil.swapped_reindex3d(data, new_x, new_y, new_z)
|
|
local reindexed_data = {}
|
|
|
|
for old_x = 1, constants.block_size, 1 do
|
|
local index_x = new_x + old_x - 1
|
|
reindexed_data[index_x] = {}
|
|
|
|
for old_z = 1, constants.block_size, 1 do
|
|
local index_z = new_z + old_z - 1
|
|
reindexed_data[index_x][index_z] = {}
|
|
|
|
for old_y = 1, constants.block_size, 1 do
|
|
local index_y = new_y + old_y - 1
|
|
|
|
reindexed_data[index_x][index_z][index_y] = data[old_z][old_y][old_x]
|
|
end
|
|
end
|
|
end
|
|
|
|
return reindexed_data
|
|
end
|
|
|