143 lines
4.9 KiB
GDScript
143 lines
4.9 KiB
GDScript
@tool
|
|
extends RefCounted
|
|
class_name SS2D_IndexTuple
|
|
|
|
## Provides utility functions for handling and storing indices of two related points using Vector2i.
|
|
##
|
|
## Index tuples are considered equal if their elements are equal, regardless of their order:
|
|
## T(X, Y) <=> T(Y, X).
|
|
##
|
|
## For effectively working with containers, helper functions for arrays and dictionaries are
|
|
## provided that implement the above behavior.
|
|
|
|
## Returns the second tuple element that does not equal the given value.
|
|
## Returns -1 if neither element matches.
|
|
static func get_other_value(t: Vector2i, value: int) -> int:
|
|
if t.x == value:
|
|
return t.y
|
|
elif t.y == value:
|
|
return t.x
|
|
return -1
|
|
|
|
|
|
## Returns whether two tuples are equal. Two tuples are considered equal when both contain the same values regardless of order.
|
|
static func are_equal(t1: Vector2i, t2: Vector2i) -> bool:
|
|
return t1 == t2 or t1 == flip_elements(t2)
|
|
|
|
|
|
## Returns true when the tuple contains the given value.
|
|
static func has(t: Vector2i, value: int) -> bool:
|
|
return t.x == value or t.y == value
|
|
|
|
|
|
## Searches for an equal tuple in the given array and returns the index or -1 if not found.
|
|
## Incorporates the equality behavior.
|
|
static func array_find(tuple_array: Array[Vector2i], t: Vector2i) -> int:
|
|
for i in tuple_array.size():
|
|
if are_equal(tuple_array[i], t):
|
|
return i
|
|
return -1
|
|
|
|
|
|
## Returns whether the given tuple exists in the given array.
|
|
## Incorporates the equality behavior.
|
|
static func array_has(tuple_array: Array[Vector2i], t: Vector2i) -> bool:
|
|
return array_find(tuple_array, t) != -1
|
|
|
|
|
|
## Returns a list indices to tuples that contain the given value.
|
|
static func array_find_partial(tuple_array: Array[Vector2i], value: int) -> PackedInt32Array:
|
|
var out := PackedInt32Array()
|
|
|
|
for i in tuple_array.size():
|
|
if tuple_array[i].x == value or tuple_array[i].y == value:
|
|
out.push_back(i)
|
|
|
|
return out
|
|
|
|
|
|
## Transform the tuple into a normalized representation (elements in ascending order).
|
|
## Same as sort_ascending() at the moment.
|
|
## Useful in more optimized use-cases where certain assumptions can be made if all tuples share a
|
|
## normalized representation.
|
|
static func normalize_tuple(tuple: Vector2i) -> Vector2i:
|
|
return sort_ascending(tuple)
|
|
|
|
|
|
## Returns a tuple with elements in ascending order.
|
|
static func sort_ascending(tuple: Vector2i) -> Vector2i:
|
|
if tuple.x <= tuple.y:
|
|
return tuple
|
|
return flip_elements(tuple)
|
|
|
|
|
|
|
|
## Returns a tuple with x and y components switched.
|
|
static func flip_elements(tuple: Vector2i) -> Vector2i:
|
|
return Vector2i(tuple.y, tuple.x)
|
|
|
|
|
|
## Validates the keys of a dictionary to be correct tuple values and converts all Arrays to
|
|
## corresponding Vector2i values.
|
|
## Optionally also validates that values are of the given type.
|
|
## Exists mostly for backwards compatibility to allow a seamless transition from Array to Vector2i tuples.
|
|
static func dict_validate(dict: Dictionary, value_type: Variant = null) -> void:
|
|
# TODO: Maybe don't use asserts but push_warning and return true if successful
|
|
for key: Variant in dict.keys():
|
|
var value: Variant = dict[key]
|
|
|
|
if value_type != null:
|
|
assert(is_instance_of(value, value_type), "Incorrect value type in dictionary: " + var_to_str(value))
|
|
|
|
if key is Array or key is PackedInt32Array or key is PackedInt64Array:
|
|
var converted := Vector2i(int(key[0]), int(key[1]))
|
|
dict.erase(key)
|
|
dict[converted] = value
|
|
else:
|
|
assert(key is Vector2i, "Invalid tuple representation: %s. Should be Vector2i." % var_to_str(key))
|
|
|
|
|
|
## Get the value in a dictionary with the given tuple as key or a default value if it does not exist.
|
|
## Incorporates the equality behavior.
|
|
static func dict_get(dict: Dictionary, tuple: Vector2i, default: Variant = null) -> Variant:
|
|
if dict.has(tuple):
|
|
return dict[tuple]
|
|
return dict.get(flip_elements(tuple), default)
|
|
|
|
|
|
static func dict_has(dict: Dictionary, tuple: Vector2i) -> bool:
|
|
return dict.has(tuple) or dict.has(flip_elements(tuple))
|
|
|
|
|
|
static func dict_set(dict: Dictionary, tuple: Vector2i, value: Variant) -> void:
|
|
dict[dict_get_key(dict, tuple)] = value
|
|
|
|
|
|
## Removes the given entry from the dictionary. Returns true if a corresponding key existed, otherwise false.
|
|
static func dict_erase(dict: Dictionary, tuple: Vector2i) -> bool:
|
|
return dict.erase(dict_get_key(dict, tuple))
|
|
|
|
|
|
## Checks if there is an existing key for the given tuple or its flipped variant and returns it.
|
|
## If a key does not exist, returns the tuple as it is.
|
|
## Usually this function does not need to be invoked manually, as helpers for dictionary and array access exist.
|
|
static func dict_get_key(dict: Dictionary, tuple: Vector2i) -> Vector2i:
|
|
if not dict.has(tuple):
|
|
var flipped := flip_elements(tuple)
|
|
|
|
if dict.has(flipped):
|
|
return flipped
|
|
|
|
return tuple
|
|
|
|
|
|
## Returns a list of all dictionary keys (tuples) that contain the given value.
|
|
static func dict_find_partial(dict: Dictionary, value: int) -> Array[Vector2i]:
|
|
var out: Array[Vector2i] = []
|
|
|
|
for t: Vector2i in dict.keys():
|
|
if t.x == value or t.y == value:
|
|
out.push_back(t)
|
|
|
|
return out
|