Skip to content

Instantly share code, notes, and snippets.

@yoloroy
Created May 21, 2023 14:30
Show Gist options
  • Select an option

  • Save yoloroy/d8d6a1a2c3f933c8a10241045803bb40 to your computer and use it in GitHub Desktop.

Select an option

Save yoloroy/d8d6a1a2c3f933c8a10241045803bb40 to your computer and use it in GitHub Desktop.
lua class containing methods for functional data processing + small extension functions for std lua table library
--- table.insertAll
--- @generic T
--- @param a T[]
--- @param b T[]
function table.insertAll(a, b)
for _, v in pairs(b) do
table.insert(a, v)
end
end
--- table.contains
--- @generic T
--- @param array T[]
--- @param value T
function table.contains(array, value)
return table.indexOf(array, value) ~= nil
end
--- table.removeValue
--- @overload fun(array: T[], value: T)
--- @generic T
--- @param array T[]
--- @param value T
--- @param all boolean
function table.removeValue(array, value, all)
if all then
local index = table.indexOf(array, value)
while index ~= nil do
table.remove(array, index)
index = table.indexOf(array, value)
end
else
table.remove(array, table.indexOf(array, value))
end
end
--- table.indexOf
--- @generic T
--- @param array T[]
--- @param value T
function table.indexOf(array, value)
for i, v in ipairs(array) do
if v == value then
return i
end
end
return nil
end
--- table.intersects
--- @generic T
--- @param a T[]
--- @param b T[]
--- @return boolean true if a contains any of values from b
function table.isIntersects(a, b)
for _, v in ipairs(a) do
if table.indexOf(b, v) ~= nil then
return true
end
end
return false
end
--- keysOf
--- @param _table table
function table.keysOf(_table)
local result = {}
for k, _ in pairs(_table) do
table.insert(result, k)
end
return result
end
--- table.containsKey
--- @param a table
--- @param key
function table.containsKey(a, key)
return table.contains(table.keysOf(a), key)
end
--- AttackAI:tryAttack
--- @return boolean is attack has been performed
function AttackAI:tryAttack()
local currentTime = system.getTimer()
if self._lastHitTime + self._cooldownMillis > currentTime then return false end
local attackerXY = XY.of(self._attackerView)
local maxDistance2 = self._maxDistance * self._maxDistance
local affectedObjectsCount = #Iterable.ofChildren(self._gameLayer)
:filter(function(v) return v.tags ~= nil and table.contains(v.tags, Attackable.tag) end)
:filter(function(v) return table.isIntersects(v.tags, self._tagsToAttack) end)
:filter(function(v) return XY.of(v):squaredDistanceTo(attackerXY) <= maxDistance2 end)
:sortBy(function(v) return XY.of(v):squaredDistanceTo(attackerXY) end) -- NOTE: there is a possibility to optimize
:limit(self._maxAffectedObjectsCount)
:onEach(function(v) self._performAttack(XY.of(v)) end)
if affectedObjectsCount == 0 then return false end
self._lastHitTime = currentTime
return true
end
function Shadowing:onPlayerUpdateLocations()
for _, location in pairs(self._visibleLocations) do
self:_hideLocation(self._belongings[location] or {})
end
self._visibleLocations = Iterable:new(self._playerLocations)
:buildFlatMap(function(acc, location) table.insertAll(acc, self._roomsGraph[location]) end)
:append(self._playerLocations)
:onEach(function(location) self:_showLocation(self._belongings[location] or {}) end)
end
objects = Iterable.filter(objects, someCondition)
require "src.common.util.array"
--- @class Iterable : Array<V>
--- @generic V
Iterable = {}
Iterable.__index = Iterable
--- Iterable:new
--- @generic T
--- @param list T[]
--- @return Iterable
function Iterable:new(list)
--- @generic T
--- @type Iterable
local obj = { unpack(list) }
setmetatable(obj, self)
return obj
end
--- Iterable.ofRange
--- @generic T
--- @param first number
--- @param last number
--- @return Iterable
function Iterable.ofRange(first, last)
--- @generic T
--- @type Iterable
local obj = Iterable:new {}
for i = first, last do table.insert(obj, i) end
return obj
end
--- Iterable.ofCount
--- @generic T
--- @param n number
--- @return Iterable
function Iterable.ofCount(n)
return Iterable.ofRange(1, n)
end
--- Iterable:appended
--- @generic T
--- @param other T[]
--- @return Iterable
function Iterable:append(other)
--- @generic R
--- @type Iterable
local result = Iterable:new {}
for i, v in ipairs(self) do
result[i] = v
end
for i, v in ipairs(other) do
result[#self + i] = v
end
return result
end
--- Iterable:replace
--- @generic T
--- @overload Iterable:replace(predicate: fun(t: T): boolean, replacement: T): Iterable
--- @overload Iterable:replace(replacee: T, mapper: fun(t: T): T): Iterable
--- @overload Iterable:replace(replacee: T, replacement: T): Iterable
--- @param predicate fun(t: T): boolean
--- @param mapper fun(t: T): T
--- @return Iterable
function Iterable:replace(predicate, mapper)
if type(predicate) ~= "function" then
return self:replace(function(t) return t == predicate end, mapper)
end
if type(mapper) ~= "function" then
return self:replace(predicate, function(_) return mapper end)
end
return self:map(function(t) if predicate(t) then return mapper(t) else return t end end)
end
--- Iterable:map
--- @generic T
--- @generic R
--- @param func fun(t: T): R
--- @return Iterable
function Iterable:map(func)
--- @generic R
--- @type Iterable
local result = Iterable:new {}
for i, v in ipairs(self) do
result[i] = func(v)
end
return result
end
--- Iterable:buildFlatMap
--- @generic T
--- @generic R
--- @param func fun(accumulator: Iterable, t: T)
--- @return Iterable
function Iterable:buildFlatMap(func)
--- @generic R
--- @type Iterable
local result = Iterable:new {}
for _, v in ipairs(self) do
func(result, v)
end
return result
end
--- Iterable:flatten
--- @generic T
--- @return Iterable
function Iterable:flatten()
--- @generic R
--- @type Iterable
local result = Iterable:new {}
for _, v in ipairs(self) do
table.insertAll(result, v)
end
return result
end
--- Iterable:productWith
--- @generic T1
--- @generic T2
--- @param other T2[]
--- @return Iterable Pairs: { [1]: T1, [2]: T2 }[]
function Iterable:productWith(other)
--- @type Iterable
local result = Iterable:new {}
for _, v1 in ipairs(self) do
for _, v2 in ipairs(other) do
table.insert(result, { v1, v2 })
end
end
return result
end
--- Iterable:zip
--- @generic T1
--- @generic T2
--- @param other T2[]
--- @return Iterable
function Iterable:zip(other)
--- @type Iterable<table[]>
local result = Iterable:new {}
for i, v in ipairs(self) do
result[i] = { v, other[i] }
end
return result
end
--- Iterable:filter
--- @generic T
--- @param predicate fun(t: T): boolean
--- @return Iterable
function Iterable:filter(predicate)
--- @type Iterable
local result = Iterable:new {}
for _, t in ipairs(self) do
if predicate(t) then
table.insert(result, t)
end
end
return result
end
--- Iterable:sort
--- @generic T
--- @param comp fun(t1: T, t2: T): boolean
--- @return Iterable
function Iterable:sort(comp)
--- @type Iterable
local result = Iterable:new(self)
table.sort(result, comp)
return result
end
--- Iterable:sort
--- @generic T
--- @param map fun(t): 'comparable'
--- @return Iterable
function Iterable:sortBy(map)
--- @type Iterable
local result = Iterable:new(self)
table.sort(result, function(a, b) return map(a) < map(b) end)
return result
end
--- Iterable:limit
--- @generic T
--- @param count number
--- @return Iterable
function Iterable:limit(count)
--- @type Iterable
local result = Iterable:new {}
for i = 1, math.min(count, #self) do
table.insert(result, self[i])
end
return result
end
--- Iterable:onEach
--- @generic T
--- @param block fun(t: T)
--- @return Iterable
function Iterable:onEach(block)
for _, t in ipairs(self) do
block(t)
end
return self
end
--- Iterable:callAll
--- @vararg any[] args which will become parameters for all function that this list contains
--- @return Iterable
function Iterable:callAll(...)
for _, fun in ipairs(self) do
fun(unpack(arg))
end
return self
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment