[Extension] BetterArrays - 60 useful array blocks!

Attention: this post is so big that it broke Discourse’s 32k character limit, so I had to split it into two parts. Part 2 will be posted in the replies. Please don’t reply until you see part 2 posted below.

Hello everyone, it’s ya boy with another extension. Last time I said I’d return with a bigger extension, so here I am, after 3 weeks of pouring digital blood, sweat and tears into this extension. This is by far the biggest extension I’ve ever created - adding 60 blocks with ~1300 lines of extension code and nearly as many lines of testing code.

So, you can expect this not only to be my biggest, but also most polished extension, as it’s been thoroughly (questionable) tested.

Before going any further, it’s important to clarify a few things. Firstly, this extension does not add a new category to the block toolbar. It just adds new blocks to the default Arrays category. In JavaScript, you can find the methods in the arrays namespace.

So, without further ado, let’s jump into it.


Blocks

As you can see below, this extension adds two new groups to the Arrays category, “Checks” and “Mutual Operations” (they weren’t there before).

Create

The Create category contains blocks that create entirely new arrays from given values. BetterArrays adds 2 new blocks to it.

Repeat

The repeat method creates an array by repeating an element a given number of times. This behaviour is inspired by Python’s [item]*repeat syntax.

function repeat(item: any, repeat: number): any[]

image

Examples

image

This example returns ["foo", "foo", "foo"]

Exceptions

NON_INTEGER_VALUE is thrown if repeat is not an integer
NEGATIVE_VALUE is thrown if repeat is a negative number

Range

The range method creates a range of numbers starting from start, ending with end (not included) while increasing each value in the range by step (optional; default is 1)

function range(start: number, end: number, step: number): number[]

image

image

Examples

image

This example will return [0, 1, 2, 3, 4]

image

This example will return [0, 2, 4, 6, 8]

Exceptions

NON_INTEGER_VALUE is thrown if start, end, or step are not integers
NEGATIVE_VALUE is thrown if step is a negative number
ZERO_STEP is thrown if step is equal to 0
INVALID_RANGE is thrown if end is lower than start

Read

The Read category contains blocks that read data from arrays. BetterArrays adds 9 new blocks to it.

Find Last

The findLast method returns the index of the last occurrence of an item in an array.
Returns -1 if the item is not found.

function findLast(array: any[], item: any): number

image

Examples

This example returns 2 (because the last occurrence of “foo” is at index 2)

image

This example returns -1 because “baz” is not in the array.

Find All

The findAll method returns an array of indicies pointing to every occurrence of an item. You can use max to limit the number of indicies that are retrieved (default is 0, which is unlimited).

function findAll(array: any[], item: any, max: number): number[]

image

image

Examples

This example returns [0, 2] (because “foo” appears on indicies 0 and 2)

This example returns [0] (because number of found indicies is limited to 1)

Exceptions

NON_INTEGER_VALUE is thrown if max is not an integer
NEGATIVE_VALUE if max is a negative number

Count

The count method counts the number of times an item occurs in an array.

function count(array: any[], item: any): number

image

Examples

This example returns 2 (because “foo” occurs twice in the array)

Convert to string

The toString method converts an array to a string.

function toString(array: any[]): string

image

Random Index

The randomIndex method returns a random index from an array.

function randomIndex(array: any[]): number

image

Exception

EMPTY_ARRAY is thrown if array is empty

Min Index

The minIndex method returns the index of the smallest element from a number array.

function minIndex(array: number[]): number

image

Examples

image

This example returns 2 (2 is the index of the biggest element, 2)

Exceptions

EMPTY_ARRAY is thrown if array is empty

Min

The min method returns the smallest element from a number array.

function min(array: number[]): number

image

Examples

image

This example returns 2

Exceptions

EMPTY_ARRAY is thrown if array is empty

Max Index

The maxIndex method returns the index of the biggest element from a number array.

function maxIndex(array: number[]): number

image

Examples

image

This example returns 1 (1 is the index of the biggest element which is 6)

Exceptions

EMPTY_ARRAY is thrown if array is empty

Max

The max method returns the biggest element from a number array.

function max(array: number[]): number

image

Examples

image

This example returns 6

Exceptions

EMPTY_ARRAY is thrown if array is empty

Modify

The Modify category contains blocks that modify arrays directly. BetterArrays adds 18 new blocks to it.

Remove All

The removeAll method removes all occurrences of item from an array. You can use max (default is 0, which is unlimited) to limit the number of items removed. This method modifies the original array.

function removeAll(array: any[], item: any, max: number): void

image

image

Examples

image

In this example list becomes ["bar"] (both “foo” elements are removed)

image

In this example list becomes ["bar", "foo"] (the first and second “foo” are removed, leaving “bar” and the last “foo”)

Exceptions

NON_INTEGER_VALUE is thrown if max is not an integer
NEGATIVE_VALUE is thrown if max is negative

Swap

The swap method swaps items at first and second indicies in an array. This method modifies the original array.

function swap(array: any[], first: number, second: number): void

image

Examples

image

In this example, list becomes ["baz", "bar", "foo"] (because the first and last items are swapped)

Exceptions

NON_INTEGER_VALUE is thrown if first or second are not integers
NEGATIVE_VALUE is thrown if first or second are negative
OUT_OF_RANGE is thrown if first or second are out of array range

Replace

The replace method replaces all elements in an array matching item with replacement. This method modifies the original array.

function replace(array: any[], item: any, replacement: any): void

image

Examples

image

In this example list becomes ["bar", "bar", "baz"] (“foo” is replaced with “bar”)

Fill

The fill method fills an item with a static item from a start (optional; default is 0) index to an end (optional; default is array lenght; end index is excluded) index. This method modifies the original array.

function fill(array: any[], item: any, start: number, end: number): void

image

image

image

Examples

image

In this example list becomes ["bam", "bam", "bam"] (array is completely filled)

image

In this example list becomes ["foo", "bam", "bam"] (filled from 1 to end)

image

In this example list becomes ["bam", "bam", "baz"] (filled from 0 to 2, not including 2, so only items at indicies 0 and 1 are set)

Exceptions

NON_INTEGER_VALUE is thrown if start or end are not integers
NEGATIVE_VALUE is thrown if start or end are negative
OUT_OF_RANGE is thrown if start or end are out of array range
INVALID_RANGE is thrown if end is smaller than start

Concatenate

The concat method concatenates (adds) a second array to the end of an array. This mehtod modifies the first array.

function concat(first: any[], second: any[]): void

image

Examples

image

In this example list becomes ["foo", "bar", "baz", "bam"] (["foo", "bar"] + ["baz", bam"] = ["foo", "bar", "baz", "bam"])

Slice

The slice extension slices an array from a start (optional; default is 0) index to an end (optional; default is array length; end index is excluded) index, with an optional step value. This method modifies the original array.

function slice(array: any[], start: number, end: number, step: number): void

image

image

image

image

Examples

image

In this example list does not change its value (because the array is sliced from start to end. I’m not sure why this feature exists)

image

In this example list becomes ["bar", "baz"] (the list is sliced from index 1, leaving index 0 out)

image

In this example list becomes ["foo", "bar"] (the list is sliced from 0 to 2, where 2 is excluded, so “baz” is excluded)

image

In this example list becomes ["foo", "baz"] (starting at index 0, the method steps two elements forward to index 2, which gets “baz” and skips “bar”)

Exceptions

NON_INTEGER_VALUE is thrown if start, end or step are not integers
NEGATIVE_VALUE is thrown if start, end or step are negative
OUT_OF_RANGE is thrown if start or end are out of list range
ZERO_STEP is thrown if step is 0
INVALID_RANGE is thrown if end is smaller than start

Zip

The zip method creates an array of pairs by grouping elements from two arrays. If the arrays are not the same length, excess items in the longer array will be ignored. This method modifies the first array.

function zip(first: any[], second: any[]): void

image

Examples

image

In this example list becomes [["foo", 1], ["bar", 2], ["baz", 3]]

image

In this example list becomes [["foo", 0], ["bar", 1]] (3rd item is ignored because shorter array length is 2)

Clear

The clear method clears the array. This method modifies the original array.

function clear(array: any[]): void

image

Examples

image

In this example list becomes []

Union

The union method creates a union (all elements from both arrays together, no duplicates) from two arrays. This method modifies the first array.

function union(first: any[], second: any[]): void

image

Examples

image

In this example list becomes ["foo", "bar", "baz"] (elements from both arrays, but with “bar” appearing once because it’s a duplicate)

Intersection

The intersection method creates an intersection (only elements that appear in both arrays, no duplicates) from two arrays. This method modifies the first array.

function intersection(first: any[], second: any[]): void

image

Examples

image

In this example list becomes ["bar"] (only “bar” is in both arrays)

Difference

The difference method creates a difference (elements that appear in the first array, without the items from the second array) from two arrays. This method modifies the first array.

function difference(first: any[], second: any[]): void

image

Examples

image

In this example list becomes ["foo"] (“bar” is removed because it’s also in the second array)

Purge (Remove Duplicates)

The purge method removes duplicate elements from an array. This method modifies the original array.

function purge(array: any[]): void

image

Examples

image

In this example list becomes ["foo", "bar"] (the duplicate “foo” is removed)

Sort

The sort method sorts a number array in ascending or descending order. String arrays may be supported in the future. This method modifies the original array.

function sort(array: number[], order: SortOrder): void

image

image

Examples

image

In this example list becomes [1, 2, 3]

image

In this example list becomes [3, 2, 1]

Enumerate

The enumerate method enumerates elements of an array (creates value-index pairs). This method modifies the original array.

function enumerate(array: any[]): void

image

Examples

image

In this example list becomes [["foo", 0], ["bar", 1], ["baz", 2] (value-index pairs from array)

Splice

The splice method deletes count elements from start index in an array. This method modifies the original array.

function splice(array: any[], start: number, count: number): void

image

Examples

image

In this example list becomes [1] (2 elements starting from 0 were removed)

Exceptions

NON_INTEGER_VALUE is thrown if start or count are not integers
NEGATIVE_VALUE if start or count are negative

Unzip

The unzip method extracts elements from an array of pairs, at target index. This method modifies the original array.

function unzip(array: any[][], target: number): void

image

Examples

In this example list will become ["a", "b"] (Gets index 0 from every pair)

Exceptions

NON_INTEGER_VALUE is thrown if target is not an integer
NEGATIVE_VALUE if target is negative
NOT_ARRAY if element to unpack is not an array (every element must be an array)
OUT_OF_RANGE if target index is bigger than pair length

Shift

The shift method shifts all elements in the array backwards by elements. This method modifies the original array.

function shift(array: any[], elements: number): void

image

Examples

image

In this example list becomes [2, 3]

Exceptions

NON_INTEGER_VALUE is thrown if elements is not an integer
NEGATIVE_VALUE is thrown if elements is negative
INVALID_SHIFT is thrown if elements is bigger than array length

Flatten

The flatten method unpacks arrays within an array recursively to the surface level up to a max depth value (default is 0, which is unlimited). This method modifies the original array.

function flatten(array: any[], max: number): void

image

image

Examples

In this example, list becomes [1, 2, 3, 4]

In this example list becomes [1, 2, [3, 4]] (because it only unpacks the first layer)

Exceptions

NON_INTEGER_VALUE is thrown if max is not an integer
NEGATIVE_VALUE is thrown if max is negative

Operations

The Operation category contains blocks that perform various operations on arrays, without modifying the original array. BetterArrays adds 21 new blocks to it.

To Shifted

The toShifted method (equivalent to shift) returns a copy of the array with all elements in the array shifted backwards by elements. This mehod does not modify the original array.

function toShifted(array: any[], elements: number): void

image

Examples

image

This example returns ["bar", "baz"]

Exceptions

NON_INTEGER_VALUE is thrown if elements is not an integer
NEGATIVE_VALUE is thrown if elements is negative
INVALID_SHIFT is thrown if elements is bigger than array length

Concatenate Many

The concatMany returns a concatenation (addition) of an array of arrays. This method does not modify the original array.

function concatMany(arrays: any[][]): any[]

image

Examples

image

This example returns [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

Zip Many

The zipMany method returns an array of pairs by grouping elements from multiple arrays. If the arrays are not the same length, excess items in the longer array(s) will be ignored.

function zipMany(arrays: any[]): any[][]

image

Examples

image

This example returns [[1, 4, 7, 10], [2, 5, 8, 11], [3, 6, 9, 12]]

This examples [["a", 0], ["b", 1]] (3rd element is ignored because shortest array has length 2)

To Flattened

The toFlattened method (equivalent to flatten) returns a copy of an array with arrays within unpacked recursively to the surface level up to a max depth value (default is 0, which is unlimited). This method does not modify the original array.

function toFlattened(array: any[], max: number): any[]

image

image

Examples

This example returns [1, 2, 3, 4]

This example returns [1, 2, [3, 4]]

Exceptions

NON_INTEGER_VALUE is thrown if max is not an integer
NEGATIVE_VALUE is thrown if max is negative

Copy

The copy method returns a copy of the array (new array with same items). This method does not modify the original array.

function copy(array: any[]): void

image

Examples

image

This example returns ["foo", "bar"] (who could have predicted that?)

To Removed All

The toRemovedAll method returns an array copy with all occurrences of item removed. You can use max (default is 0, which is unlimited) to limit the number of items removed. This method does not modify the original array.

function toRemovedAll(array: any[], item: any, max: number): any[]

image

image

Examples

This example returns ["bar"]

This example returns ["bar", "foo"] (second “foo” is not removed because max is 1)

Exceptions

NON_INTEGER_VALUE is thrown if max is not an integer
NEGATIVE_VALUE is thrown if max is negative

To Swapped

The toSwapped method returns an array copy with swapped items at first and second indicies. This method does not modify the original array.

function toSwapped(array: any[], first: number, second: number): any[]

image

Examples

This example returns ["baz", "bar", "foo"]

Exceptions

NON_INTEGER_VALUE is thrown if first or second are not integers
NEGATIVE_VALUE is thrown if first or second are negative
OUT_OF_RANGE is thrown if first or second are out of array range

To Replaced

The toReplaced method returns an array copy with all elements matching item replaced with replacement. This method does not modify the original array.

function toReplaced(array: any[], item: any, replacement: any): any[]

image

Examples

This example returns ["baz", "bar", "baz"]

To Filled

The toFilled method returns an array copy filled with a static item from a start (optional; default is 0) index to an end (optional; default is array lenght; end index is excluded) index. This method does not modify the original array.

function toFilled(array: any[], item: any, start: number, end: number): any[]

image

image

image

Examples

image

This example returns ["bam", "bam", "bam"]

This example returns ["foo", "bam", "bam"]

This example returns ["bam", "bam", "baz"]

Exceptions

NON_INTEGER_VALUE is thrown if start or end are not integers
NEGATIVE_VALUE is thrown if start or end are negative
OUT_OF_RANGE is thrown if start or end are out of array range
INVALID_RANGE is thrown if end is smaller than start

To Sliced

The toSliced method returns a slice of an array from a start (optional; default is 0) index to an end (optional; default is array length; end index is excluded) index, with an optional step value. This method does not modify the original array.

function toSliced(array: any[], start: number, end: number, step: number): any[]

image

image

image

image

Examples

image

This example returns ["foo", "bar", "baz"] (for some reason)

image

This example returns ["bar", "baz"]

This example returns ["foo", "bar"] (index 2 is excluded)

This example returns ["foo", "baz"]

Exceptions

NON_INTEGER_VALUE is thrown if start, end or step are not integers
NEGATIVE_VALUE is thrown if start, end or step are negative
OUT_OF_RANGE is thrown if start or end are out of list range
ZERO_STEP is thrown if step is 0
INVALID_RANGE is thrown if end is smaller than start

To Zipped

The toZipped method returns an array of pairs created from two arrays. If the arrays are not the same length, excess items in the longer array will be ignored.

function toZipped(first: any[], second: any[]): any[][]

image

Examples

This example returns [["foo", 1], ["bar", 2], ["baz", 3]]

This example returns [["foo", 1], ["bar", 2]] (3rd element from first array is ignored because second array length is 2)

To Reversed

The toReversed method returns a reversed copy of an array.

function toReversed(array: any[]): any[]

image

Examples

image

This example returns ["baz", "bar", "foo"]

For Each

The forEach method loops through an array with value and index parameters. You can drag any blocks into the handler to execute them within the loop using the parameters.

function forEach(array: any[], handler: (value: any, index: number) => void): void

image

Examples

image

This example logs
0 = foo
1 = bar
2 = baz
to the console

To Purged

The toPurged method returns an array copy with all duplicates removed.

function toPurged(array: any[]): any[]

image

Examples

image

This example returns ["foo", "bar"]

Extract

The extract method returns an array comprised of every occurrence of an item in an array.

function extract(array: any[]): any[]

image

Examples

image

This example returns ["foo", "foo"] (the first and last element are extracted from the original array and returned in a new array)

To Sorted

The toSorted method returns a sorted number array copy in ascending or descending order. String arrays may be supported in the future. This method does not modify the original array.

function toSorted(array: number[], order: SortOrder): number[]

image

image

Examples

image

This example returns [1, 2, 3]

image

This example returns [3, 2, 1]

Sum

The sum method returns a sum of elements in a number array.

function sum(array: number[]): number

image

Examples

image

This example returns 6

To Enumerated

The toEnumerated method returns enumerated elements of an array (creates value-index pairs). This method does not modify the original array.

function toEnumerated(array: any[]): any[]

image

Examples

image

This example returns [["foo", 0], ["bar", 1], ["baz", 2]]

Join

The join method returns a string array joined into a single string using a separator (optional; default is nothing).

function join(array: string[]): string

image

image

Examples

image

This example returns foobarbaz

image

This example returns foo-bar-baz

To Spliced

The toSpliced method returns an array copy with count elements deleted from start index. This method does not modify the original array.

function toSpliced(array: any[], start: number, count: number): any[]

image

Examples

This example returns ["baz"]

Exceptions

NON_INTEGER_VALUE is thrown if start or count are not integers
NEGATIVE_VALUE is thrown if start or count are negative
OUT_OF_RANGE is thrown if start is out of array range

To Unzipped

The toUnzipped method returns extracted elements from an array of pairs, at target index. This method does not modify the original array.

function toUnzipped(array: any[], target: number): any[]

image

Examples

This example returns ["foo", "bar"] (extracts every element at index 0)

Exceptions

NON_INTEGER_VALUE if target is not an integer
NEGATIVE_VALUE if target is negative
NOT_ARRAY if element to unpack is not an array (every element must be an array)
OUT_OF_RANGE if target is bigger than pair length

21 Likes
Checks

The Checks category (new category) contains blocks that return true or false based on a condition inside of an array. BetterArrays adds 7 blocks to it.

Equal

The equal method returns true if two arrays are equal (regular javascript equality operation does not work on arrays, for some reason)

function equal(first: any[], second: any[]): boolean

image

Examples

image

This example does not return true, because javascript.

image

This example returns true (as it should)

In Range

The inRange method returns true if index is in range (between 0 and array length) of array.

function inRange(array: any[], index: number): boolean

image

Examples

image

This example returns true (0 < 1 < 2 is true)

image

This example returns false (0 < 2 < 2 is false)

Exceptions

NON_INTEGER_VALUE if index is not an integer

Includes

The includes method returns true if item is included in an array.

function includes(array: any[], item: any): boolean

image

Examples

image

This example returns true

image

This example returns false

Is Empty

The isEmpty method returns true if an array is empty (length is 0).

function isEmpty(array: any[]): boolean

image

Examples

image

This example returns true

image

This example returns false

All True

The allTrue method returns true if all elements in an array evaluate to true.

function allTrue(array: any[]): boolean

image

Examples

image

This example returns true

image

This example returns false (0 evaluates to false)

Any True

The anyTrue method returns true if any element in an array evaluates to true.

function anyTrue(array: any[]): boolean

image

This example returns true (only true evaluates to true, but that’s enough to return true)

image

This example returns false (all elements evaluates to false)

All Equal

The allEqual method returns true if every element in an array is equal to item.

function allEqual(array: any[], item: any): boolean

image

Examples

image

This example returns true

image

This example returns false

Mutual operations

The Mutual Operations category (new category) contains blocks that perform operations comparing elements of two arrays and return the result. BetterArrays adds 3 blocks to it.

To Union

The toUnion method returns a union (all elements from both arrays together, no duplicates) of two arrays. This method does not modify the first array.

function toUnion(first: any[], second: any[]): any[]

image

Examples

image

This example returns ["foo", "bar", "baz"]

To Intersection

The toIntersection method returns an intersection (only elements that appear in both arrays, no duplicates) of two arrays. This method does not modify the first array.

function toIntersection(first: any[], second: any[]): any[]

image

Examples

image

This example returns ["baz"]

To Difference

The toDifference method returns a difference (elements that appear in the first array, without the items from the second array) of two arrays. This method does not modify the first array.

function toDifference(first: any[], second: any[]): any[]

image

Examples

image

This example returns ["foo"]


Exceptions

As you can gather from the blocks chapter (see above), some blocks have an exceptions category. This category describes which exceptions a block can throw, and under which condition that can occur.

BetterArrays throws exceptions for illegal values to make debugging easier and prevent unexpected behaviour. Below is an explanation of each of those exceptions.

NON_INTEGER_VALUE

This exception is thrown if a given value is not an integer (whole number)
Certain values (mostly indicies) cannot be decimal values

Value must be integer (not [value])

NEGATIVE_VALUE

This exception is thrown if a given value is negative
Certain values (mostly indicies) cannot be lower than 0

Value must not be negative (not [value])

OUT_OF_RANGE

This exception is thrown if a given value is not within an array range
Values used for accessing values within an array must not be outside of array bounds

Index ([value]) must be in list range (0, [array length; excluded])

ZERO_STEP

This exception is thrown if a step value is equal to 0
Stepping values cannot be 0, as it would cause an infinite loop

Stepping value cannot be 0

INVALID_RANGE

This exception is thrown if an end value is lower than a start value
Start values must be lower than end values in order to create a valid range

Start value ([start]) must be lower than end value ([end])

EMPTY_ARRAY

This exception is thrown if a given array is empty
Certain methods require arrays containing at least one element

Operation cannot be performed on empty array

NOT_ARRAY

This exception is thrown if a given value type is not array
Certain methods expect elements to be an array type

Expected array type (not [typeof value])

INVALID_SHIFT

This exception is thrown if a shift value is bigger than an array length
The shift and toShifted methods can throw this exception

Shift value ([shift]) cannot be bigger than array length ([length of array])


Hardware Support

@danger_kitty pointed out that this extension (because it’s so huge) could take up too much device storage, making this extension unusable for projects that are intended for hardware ports.

After testing this theory, it was discovered that adding this extension to an empty project increases the compiled file size by a whopping 0.4%! Therefore, we can conclude that this extension can be used for hardware games as well.


And that’s the BetterArrays extension! I’ve sank a lot of my time making this extension, both writing code, and this post. If you find this useful, smash like and star the repo, would appreciate. If you found a mistake in this post, or unexpected behaviour in the extension, please let me know. Also be sure to submit any feature requests/ideas, as I’m open to adding new stuff!

Import the extension here

Now, I’m going to take a very long nap. Peace :v:

16 Likes

@Sarge MakeCode’s compiler is actually really smart about only compiling code that is actually used in your project. This is called tree shaking.

As such, it’s totally possible to make huge extensions but not add that much to the compiled binary! Only the code that is actually referenced in the project will make it in.

13 Likes

Lovely extension! This will make our lives a lot easier!

Waiting for BetterStrings now :melting_face:

6 Likes

So anyway pictures in part 2 dissapeared because discourse processes images in a goofy way so I’ll be posting those here soon, sorry for the inconvenience

5 Likes

Lets goooo!!!

3 Likes

zNEW WORLD RECORD. he broke discourse.

2 Likes

Uhhh @richard why is this block appearing as a square block and not a round one?

image

4 Likes

Nevermind, I am an idiot, the concat and toConcated blocks had the same id -.-

7 Likes

:loudspeaker: 1.2.0 update (yes, there have been minor updates I didn’t announce)
Changelog:

  • Added new shuffle and toShuffled methods (certainly not related to the upcoming jam) :face_with_hand_over_mouth:
  • Fixed minor issues and updated dependencies

Shuffle method

The shuffle method rearranges items in an array in a random order. This method modifies the original array.

function shuffle(array: any[]): void

image

To shuffled method

The toShuffled method returns an array copy with items rearranged in a random order. This method does not modify the original array.

function toShuffled(array: any[]): any[]

image

Until next time, peace :v:

6 Likes

:loudspeaker: Just an announcement, patch 1.2.2 is out, if you needed to use methods on image or tile arrays and they weren’t working, now they do. Make sure to update the extension in your projects. See ya

4 Likes

Would a tile map saving extension be possible? :eyes:
Also I love this extension! As someone who has done a bit of python, I enjoy what you can do with arrays (not necessarily how messy it is). It is a bit of a niche extension for most users, and I just thought of a very good way to use it in one of my games.

2 Likes