mirror of
				https://codeberg.org/1414codeforge/gear.git
				synced 2025-06-05 22:09:24 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			143 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			143 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| --- General stateless utility algorithms
 | |
| --
 | |
| -- @module gear.algo
 | |
| -- @copyright 2022 The DoubleFourteen Code Forge
 | |
| -- @author Lorenzo Cogotti
 | |
| 
 | |
| local floor = math.floor
 | |
| local min, max = math.min, math.max
 | |
| 
 | |
| local algo = {}
 | |
| 
 | |
| 
 | |
| --- Clamp x within range [a,b] (where b >= a).
 | |
| --
 | |
| -- @number x value to clamp.
 | |
| -- @number a interval lower bound (inclusive).
 | |
| -- @number b interval upper bound (includive).
 | |
| -- @treturn number clamped value.
 | |
| function algo.clamp(x, a, b) return min(max(x, a), b) end
 | |
| 
 | |
| --- Fast remove from array.
 | |
| --
 | |
| -- Replace 'array[i]' with last array's element and
 | |
| -- discard array's tail.
 | |
| --
 | |
| -- @tparam table array
 | |
| -- @int i
 | |
| function algo.removefast(array, i)
 | |
|     local n = #array
 | |
| 
 | |
|     array[i] = array[n]  -- NOP if i == n
 | |
|     array[n] = nil
 | |
| end
 | |
| 
 | |
| local function lt(a, b) return a < b end
 | |
| 
 | |
| local function _insertionsort(array, lo, hi, less)
 | |
|     for i = lo+1,hi do
 | |
|         local k = lo
 | |
|         local v = array[i]
 | |
| 
 | |
|         for j = i,lo+1,-1 do
 | |
|           local el = array[j-1]
 | |
|           if less(v, el) then
 | |
|               array[j] = el
 | |
|           else
 | |
|               k = j
 | |
|               break
 | |
|           end
 | |
|         end
 | |
|         array[k] = v
 | |
|     end
 | |
| end
 | |
| 
 | |
| --- Sort array using Insertion Sort - O(n^2).
 | |
| --
 | |
| -- Provides the most basic sorting algorithm around.
 | |
| -- Performs better than regular table.sort() for small arrays
 | |
| -- (~100 elements).
 | |
| --
 | |
| -- @tparam table array array to be sorted.
 | |
| -- @tparam[opt=operator <] function less comparison function, takes 2 arguments,
 | |
| --                                  returns true if its first argument is
 | |
| --                                  less than its second argument,
 | |
| --                                  false otherwise.
 | |
| function algo.insertionsort(array, less)
 | |
|     _insertionsort(array, 1, #array, less or lt)
 | |
| end
 | |
| 
 | |
| --- Binary search last element where
 | |
| --  what <= array[i] - also known as lower bound.
 | |
| --
 | |
| -- @tparam table array an array sorted according to the less function.
 | |
| -- @param what the comparison argument.
 | |
| -- @tparam[opt=operator <] function less sorting criterium, a function taking 2 arguments,
 | |
| --                                  returns true if the first argument
 | |
| --                                  is less than the second argument,
 | |
| --                                  false otherwise.
 | |
| --
 | |
| -- @treturn int the greatest index i, where what <= array[i].
 | |
| --              If no such element exists, it returns an out of bounds index
 | |
| --              such that array[i] == nil.
 | |
| function algo.bsearchl(array, what, less)
 | |
|     less = less or lt
 | |
| 
 | |
|     local lo, hi = 1, #array
 | |
|     local ofs, mid = -1, hi
 | |
| 
 | |
|     while mid > 0 do
 | |
|         mid = floor(hi / 2)
 | |
| 
 | |
|         -- array[lo+mid] <= what <-> what >= array[lo+mid]
 | |
|         --                       <-> not what < array[lo+mid]
 | |
|         if not less(what, array[lo+mid]) then
 | |
|             lo = lo + mid
 | |
|             ofs = 0  -- at least one element where array[lo+mid] <= what
 | |
|         end
 | |
| 
 | |
|         hi = hi - mid
 | |
|     end
 | |
| 
 | |
|     return lo + ofs
 | |
| end
 | |
| 
 | |
| --- Binary search first element where
 | |
| --  what >= array[i] - also known as upper bound.
 | |
| --
 | |
| -- @tparam table array an array sorted according to the less function.
 | |
| -- @param what the comparison argument.
 | |
| -- @tparam[opt=operator <] function less sorting criterium,
 | |
| --                                  a function taking 2 arguments,
 | |
| --                                  returns true if the first argument
 | |
| --                                  is less than the second argument,
 | |
| --                                  false otherwise.
 | |
| --
 | |
| -- @treturn int the smallest index i, where what >= array[i].
 | |
| --              If no such element exists, it returns an out of bounds index
 | |
| --              such that array[i] == nil.
 | |
| function algo.bsearchr(array, what, less)
 | |
|     less = less or lt
 | |
| 
 | |
|     local lo, hi = 1, #array
 | |
|     local ofs, mid = -1, hi
 | |
| 
 | |
|     while mid > 0 do
 | |
|         mid = floor(hi / 2)
 | |
| 
 | |
|         -- array[lo+mid] >= what <-> not array[lo+mid] < what
 | |
|         if not less(array[lo+mid], what) then
 | |
|             ofs = 0
 | |
|         else
 | |
|             lo = lo + mid
 | |
|             ofs = 1
 | |
|         end
 | |
| 
 | |
|         hi = hi - mid
 | |
|     end
 | |
| 
 | |
|     return lo + ofs
 | |
| end
 | |
| 
 | |
| return algo
 |