119 lines
3.7 KiB
GDScript
119 lines
3.7 KiB
GDScript
###
|
|
### algorithmic utility
|
|
###
|
|
extends Object
|
|
|
|
class_name GDBAlgorithm
|
|
|
|
class __SortBy:
|
|
var prop_name := ""
|
|
var descending := false
|
|
|
|
func __sort(obj0, obj1):
|
|
var res = obj0.get(prop_name) < obj1.get(prop_name)
|
|
if descending:
|
|
return !res
|
|
return res
|
|
|
|
################
|
|
# public stuff #
|
|
################
|
|
func _init():
|
|
assert(0, "This class should not be instantiated.")
|
|
|
|
# Packs source code into a small script object, like a lambda in other languages.
|
|
# This function can then be called by calling the "eval" (or whatever you pass as
|
|
# fn_name) function of the object. This is especially useful for GDScript functions
|
|
# like "sort_custom" which take an object and a function as parameters.
|
|
#
|
|
# Example:
|
|
# var names := ["Bob", "Alice", "Elfriede"]
|
|
# names.sort_custom(GDBAlgorithm.lambda("return name0.substr(1) < name1.substr(1)", ["name0", "name1"]), "eval")
|
|
# print(names) # prints "[Elfriede, Alice, Bob]"
|
|
#
|
|
# @param source The source code of your lambda function.
|
|
# @param params A list of parameter names your function takes.
|
|
# @param fn_name The name of the resulting function, defaults to "eval".
|
|
# @returns An object containing the lambda function as fn_name.
|
|
static func lambda(source : String, params := [], fn_name := "eval") -> RefCounted:
|
|
var script := GDScript.new();
|
|
script.source_code = "tool\nextends Reference\nfunc {fn_name}({param_list}):\n\t{source}".format({
|
|
"source": source,
|
|
"param_list": ",".join(PackedStringArray(params)),
|
|
"fn_name": fn_name
|
|
})
|
|
var err : int = script.reload()
|
|
if err == OK:
|
|
return script.new()
|
|
else:
|
|
printerr("lambda: script compilation failed.")
|
|
return null
|
|
|
|
# Removes elements from a collection only if the specified condition is met.
|
|
# Takes either an object and a function name or a lambda and a parameter list
|
|
# as parameters.
|
|
#
|
|
# Example 1:
|
|
# func is_negative(num):
|
|
# return num < 0
|
|
#
|
|
# func remove_negatives(col):
|
|
# GDBAlgorithm.remove_if(col, self, "is_negative")
|
|
#
|
|
# Example 2:
|
|
# func remove_negatives2(col):
|
|
# GDBAlgorithm.remove_if(col, "num < 0", ["num"])
|
|
static func remove_if(collection, p0, p1 : Variant = null) -> int:
|
|
if p0 is String:
|
|
if p1 && !p1 is Array:
|
|
printerr("remove_if failed: invalid parameters")
|
|
return 0
|
|
var lmb := lambda(p0 as String, p1 if p1 is Array else [])
|
|
if !lmb:
|
|
return 0 # errors have already been printed
|
|
return __remove_if(collection, lmb, "eval")
|
|
elif !p0 is Object || !p1 is String:
|
|
printerr("remove_if failed: invalid parameters")
|
|
return 0
|
|
else:
|
|
return __remove_if(collection, p0, p1)
|
|
|
|
static func sort_by(arr : Array, prop_name : String, descending := false):
|
|
var comparator := __SortBy.new()
|
|
comparator.prop_name = prop_name
|
|
comparator.descending = descending
|
|
arr.sort_custom(comparator.__sort)
|
|
|
|
#################
|
|
# private stuff #
|
|
#################
|
|
static func __remove_if(collection, object : Object, predicate : String) -> int:
|
|
if collection is Array:
|
|
return __remove_if_array(collection, object, predicate)
|
|
elif collection is Dictionary:
|
|
return __remove_if_dict(collection, object, predicate)
|
|
else:
|
|
var values_to_remove := []
|
|
for ele in collection:
|
|
if object.call(predicate, ele):
|
|
values_to_remove.append(ele)
|
|
for ele in values_to_remove:
|
|
collection.erase(ele)
|
|
return values_to_remove.size()
|
|
|
|
static func __remove_if_array(array : Array, object : Object, predicate : String) -> int:
|
|
var removed := 0
|
|
for i in range(array.size() - 1, -1, -1):
|
|
if object.call(predicate, array[i]):
|
|
array.remove(i)
|
|
removed += 1
|
|
return removed
|
|
|
|
static func __remove_if_dict(dict : Dictionary, object : Object, predicate : String) -> int:
|
|
var removed := 0
|
|
for key in dict.keys():
|
|
if object.call(predicate, dict[key]):
|
|
dict.erase(key)
|
|
removed += 1
|
|
return removed
|