From 7746a9923396f2e652a3a16755b090b1941a3d80 Mon Sep 17 00:00:00 2001 From: evolutionleo Date: Thu, 25 Mar 2021 12:56:50 +0300 Subject: [PATCH] New Functions and stuff --- ArrayClass.yymps | Bin 9103 -> 13053 bytes .../scripts/ArrayClass/ArrayClass.gml.backup0 | 1029 +++++++++++++++++ .../scripts/SpeedTimer/SpeedTimer.gml.backup0 | 29 + .../#backups/scripts/Tests/Tests.gml.backup0 | 307 +++++ Sample+Tests/#config/properties.json | 6 + Sample+Tests/ArrayClass.yyp | 21 +- .../options/amazonfire/options_amazonfire.yy | 49 + .../options/android/options_android.yy | 76 ++ Sample+Tests/options/ios/options_ios.yy | 50 + Sample+Tests/options/tvos/options_tvos.yy | 29 + .../options/windows/options_windows.yy | 15 +- .../scripts/ArrayClass/ArrayClass.gml | 677 +++++++++-- .../scripts/SpeedTimer/SpeedTimer.gml | 28 + Sample+Tests/scripts/SpeedTimer/SpeedTimer.yy | 12 + Sample+Tests/scripts/Tests/Tests.gml | 85 +- 15 files changed, 2275 insertions(+), 138 deletions(-) create mode 100644 Sample+Tests/#backups/scripts/ArrayClass/ArrayClass.gml.backup0 create mode 100644 Sample+Tests/#backups/scripts/SpeedTimer/SpeedTimer.gml.backup0 create mode 100644 Sample+Tests/#backups/scripts/Tests/Tests.gml.backup0 create mode 100644 Sample+Tests/#config/properties.json create mode 100644 Sample+Tests/options/amazonfire/options_amazonfire.yy create mode 100644 Sample+Tests/options/android/options_android.yy create mode 100644 Sample+Tests/options/ios/options_ios.yy create mode 100644 Sample+Tests/options/tvos/options_tvos.yy create mode 100644 Sample+Tests/scripts/SpeedTimer/SpeedTimer.gml create mode 100644 Sample+Tests/scripts/SpeedTimer/SpeedTimer.yy diff --git a/ArrayClass.yymps b/ArrayClass.yymps index 39b3b9ad26836756fc99a7ffd46968cd0b4244a3..b3b88f860ad38405a2a7cae107b0a20563cc4ca9 100644 GIT binary patch literal 13053 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 delta 8416 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 size-1) { + __throw( "Error: index "+string(pos)+" is out of range [0, "+string(size-1)+"]"); + return undefined; + } + + + return content[pos]; + } + + ///@function getRandom() + ///@description Returns a random element from the array + static getRandom = function() { + var idx = irandom(size-1) + if empty() { + var ans = undefined + } + else { + var ans = get(idx) + } + + return ans + } + + ///@function insert(pos, value) + ///@description inserts a value into the array at given position + ///@param {real} pos + ///@param {any} value + static insert = function(pos, value) { + if(pos < 0) + pos += size; + + if(pos < 0 or (pos > size-1 and size != 0)) { + show_debug_message("Warning: trying to insert a value outside of the array. Use Array.set() or Array.append() instead"); + return set(pos, value); + } + + var part1 = slice(0, pos); + var part2 = slice(pos); + + part1.append(value); + part1.concat(part2); + + content = part1.content; + size++; + + return self; + } + + ///@function isSorted(func) + ///@description checks wether the array is sorted or not. + /// You can provide a function that compares `a` and `b` and returns true if a is "less" + /// default function: (a, b) => { return a < b; } + ///@param {function} func + static isSorted = function(func) { + if is_undefined(func) { + func = function(a, b) { + return a < b; + } + } + + for(var i = 1; i < size; ++i) { + if !func(content[i-1], content[i]) + return false; + } + return true; + } + + ///@function join(separator) + ///@description returns a string, containing all of the array values separated by 'sep' + ///@tip to join part of the array, use array.slice().join() + ///@param {string} separator + ///@param {bool} show_bounds + static join = function(sep, show_bounds) { + if is_undefined(sep) + sep = ", " + if is_undefined(show_bounds) + show_bounds = true + + _sep = sep + + if show_bounds + str = "[" + else + str = "" + + forEach(function(el, i) { + str += string(el) + if(i < size-1) + str += _sep + }) + + if show_bounds + str += "]" + + return str + } + + ///@function lambda(func) + ///@description Loops through the array and applies the function to each element + ///@param {function} func(x, *pos) + static lambda = function(func) { + for(var i = 0; i < size; i++) { + set(i, func(get(i), i) ); + } + + return self; + } + + ///@function last() + ///@description Returns the last value of the array + static last = function() { + return get(-1); + } + + ///@function _max() + ///@description Returns a maximum of the array. Only works with numbers + static _max = function() { + ans = get(0); + + forEach(function(x) { + if(!is_numeric(x)) { + __throw( "TypeError: Trying to calculate maximum of "+typeof(x)+""); + ans = undefined; + return 1 // Break out of forEach() + } + + if(x > ans) + ans = x; + }); + + return ans; + } + + ///@function _min() + ///@description Returns a minimum of the array. Only works with numbers + static _min = function() { + ans = content[0]; + + forEach(function(x) { + if(!is_numeric(x)) { + __throw( "TypeError: Trying to calculate minimum of "+typeof(x)+""); + ans = undefined; + return 1 + } + + if(x < ans) + ans = x; + }); + + return ans; + } + + ///@function merge(other) + ///@description Merges this array with another + static merge = function(_other) { + for(var i = 0; i < _other.size; ++i) { + self.append(_other.get(i)); + } + + return self; + } + + ///@function merged(other) + ///@description like merge() method, but without modifying the original array + static merged = function(_other) { + ans = self.copy(); + _other.forEach(function(item) { + ans.append(item); + }) + + return ans; + } + + ///@function __merge(other) + ///@description an internal function, used for MergeSorting. Not for you to use (unless you know what you're doing) :] + static __merge = function(_other) { + var ans = array_create(size + _other.size); + var i = 0; + var j = 0; + var k = 0; + while(i < size && j < _other.size) { + if self.get(i) < _other.get(j) { + ans[k] = self.get(i); + i++; + } + else { + ans[k] = _other.get(j); + j++; + } + + k++ + } + + while(i < size) { + ans[k] = self.get(i); + i++; + k++; + } + + while(j < _other.size) { + ans[k] = _other.get(j); + j++; + k++; + } + + return ans; + } + + ///@function mergeSort(l, r) + ///@description Sorts the array using merge sort algorithm (pretty fast) + static mergeSort = function(l, r) { + if size == 1 + return self; + + if is_undefined(l) { + l = 0; + } + if is_undefined(r) + r = size; + + // var mid = (size - 1) div 2; + // var left = (slice(0, mid)).mergeSort(); + // var right = (slice(mid+1, size)).mergeSort(); + + var mid = (l + r - 1) div 2; + var left = mergeSort(l, mid); + var right = mergeSort(mid+1, r); + + + show_debug_message("left: "+left.toString()); + show_debug_message("right: "+right.toString()); + + var _merged = left.__merge(right); + + // if (first_time) { + // content = _merged.content; + // size = array_length(content); + // return self; + // } + // else { + return _merged; + // } + } + + ///@function number(value) + ///@description Returns the amount of elements equal to given value in the array + ///@note IMPORTANT! Don't try to use this with data structures, as results may be unpredictable + /// (Use forEach() with your own logic instead) + ///@param {any} value + static number = function(_val) { + val = _val; + ans = 0; + + forEach(function(x, pos) { + if(x == val) + ans++; + }); + + return ans; + } + + ///@function pop() + ///@description removes a value from the end of the array and returns it + static pop = function() { + ans = last(); + if(empty()) { + __throw( "Error: trying to pop value from empty Array"); + return undefined; + } + + remove(-1); + + return ans; + } + + ///@function popBack() + ///@description removes a value from the beginning of the array and returns it + static popBack = function() { + ans = first(); + remove(0); + + return ans; + } + + ///@function push(value, value2, ..) + ///@description Mirrors append() method + ///@param {any} value + static push = function(value) { + for(var i = 0; i < argument_count; ++i) { + var val = argument[i] + content[size] = val; + ++size; + } + + return self; + } + + ///@function pushBack(value) + ///@description inserts a value to the beginning of the array + ///@param {any} value + static pushBack = function(val) { + insert(0, val); + } + + ///@function radixSort() + ///@description sorts the array using radix sort algorythm + static radixSort = function(digits) { + + static getDigit = function(num, digit) { // digit from right to left + repeat(digit) { + num = num div 10; + } + return (num % 10); + } + + for(var digit = 0; digit < digits; ++digit) { + // 0-9 indexies representing each possible digit + var counters = array_create(10, 0); + output = array_create(size, -1); + + for(var i = 0; i < size; ++i) { + var dig = getDigit(content[i], digit); + counters[dig]++; + } + + // sum + for(var i = 1; i < array_length(counters); ++i) { + counters[i] += counters[i - 1]; // get positions + } + + for(var i = size - 1; i >= 0; --i) { + var dig = getDigit(content[i], digit); + var pos = counters[dig]; + + if pos != 0 + pos--; + + while(output[pos] != -1) + pos--; + + output[pos] = content[i]; + } + + array_copy(content, 0, output, 0, array_length(output)); + } + + return self; + } + + ///@function remove(pos) + ///@description removes the value at given position + ///@param {real} pos + static remove = function(pos) { + if(pos < 0) + pos += size; + + if(size == 0) { + __throw("Error: trying to remove value from an empty Array"); + return self; + } + else if(pos < 0 or pos > size - 1) { + __throw( "Error: index "+string(pos)+" is out of range [0, "+string(size-1)+"]"); + return self; + } + + var part1 = slice(0, pos); + var part2 = slice(pos+1); + + part1.concat(part2); + + content = part1.content; + size--; + + return self; + } + + ///@function resize(size) + ///@description resizes the array. Sizing up leads to filling the empty spots with zeros + ///@param {real} size + static resize = function(size) { + if(size < 0) { + __throw( "Error: array size cannot be negative"); + return self; + } + + while(size < size) { + append(0); + } + while(size > size) { + pop(); + } + + return self; + } + + ///@function reverse() + ///@description reverses the array, affecting it + static reverse = function() { + ans = new Array(); + forEach(function(element, pos) { + ans.set(size-pos-1, element); + }); + + content = ans.content; + return self; + } + + ///@function reversed() + ///@description Returns reversed version of the array, without affecting the original + static reversed = function() { + ans = new Array(); + forEach(function(element, pos) { + ans.set(size-pos-1, element); + }); + + return ans; + } + + ///@function set(pos, value) + ///@description sets value in the array at given index + ///@param {real} pos + ///@param {any} item + static set = function(pos, value) { + if(pos < 0) + pos += size; + + if(pos > size-1) + size = pos+1; + + + content[pos] = value; + + return self; + } + + ///@function slice(begin, end) + ///@description Returns a slice from the array with given boundaries. If begin > end - returns reversed version + ///@param {real} begin + ///@param {real} end + static slice = function(_begin, _end) { + if(is_undefined(_begin)) + _begin = 0; + + if(is_undefined(_end)) + _end = size; + + ans = new Array(); + + + if(_begin > _end) { + for(var i = _end; i < _begin; i++) { + ans.pushBack(content[i]); + } + } + else { + for(var i = _begin; i < _end; i++) { + ans.append(content[i]); + } + } + + return ans; + } + + ///@function sort(func, *startpos, *endpos) + ///@description Bubble sorts through the array in given range, comparing values using provided function. + ///Function gets (a, b) as input and must return True if A has more priority than B and False otherwise. + ///@example myarray.sort(function(a, b) { return a > b }) will sort 'myarray' in descending order + ///@param {function} func + ///@param {real} *startpos Default - 0 + ///@param {real} *endpos Default - size + static sort = function(compare, _begin, _end) { + if (is_undefined(compare)) + compare = SORT_ASCENDING; + + if(is_undefined(_begin)) + _begin = 0; + + if(is_undefined(_end)) + _end = size; + + + if(!is_numeric(_begin) or round(_begin) != _begin or !is_numeric(_end) or round(_end) != _end) { + __throw( "TypeError: sort boundaries must be integers"); + return self; + } + + for(var i = _begin; i < _end; i++) { // Bubble sort LUL + for(var j = i; j > _begin; j--) { + if(j > 0 and compare(get(j), get(j-1))) { + swap(j, j-1); + } + } + } + + return self; + } + + #macro SORT_ASCENDING (function(a, b) { return a < b }) + #macro SORT_DESCENDING (function(a, b) { return a > b }) + + + ///@function sorted(func, *startpos, *endpos) + ///@description Mirrors .sort() function, but doesn't affect the original Array + static sorted = function(compare, _begin, _end) { + var ans = copy() // self.copy() + return ans.sort(compare, _begin, _end) + } + + ///@function shuffle() + ///@description shuffles the array (randomly replaces every element) + static shuffle = function() { + // Knuth shuffle implementation + for(var i = size-1; i > 0; --i) { + var j = irandom_range(0, i) + swap(i, j) + } + + + return self + } + + ///@function shuffled() + ///@description clean version of .shuffle() + static shuffled = function() { + var ans = copy(); + return ans.shuffle(); + } + + ///@function sum() + ///@description Returns the sum of all the elements of the array. concats strings. + ///NOTE: Works only with strings or numbars and only if all the elements are the same type. + static sum = function() { + if(is_string(get(0))) + ans = ""; + else if(is_numeric(get(0))) + ans = 0; + else { + __throw( "TypeError: trying to sum up elements, that aren't strings or reals"); + return undefined; + } + + forEach(function(el) { + if(typeof(el) != typeof(ans)) + __throw( "TypeError: Array elements aren't the same type: got "+typeof(el)+", "+typeof(ans)+" expected."); + + ans += el; + }); + + return ans; + } + + ///@function swap(pos1, pos2) + ///@description swaps 2 values at given positions + ///@param {real} pos1 + ///@param {real} pos2 + static swap = function(pos1, pos2) { + var temp = get(pos1); + set(pos1, get(pos2)); + set(pos2, temp); + + return self; + } + + ///@function unique() + ///@description Returns a copy of this Array object, deleting all duplicates + static unique = function() { + ans = new Array(); + + forEach(function(x) { + if(!ans.exists(x)) + ans.append(x); + }); + + return ans; + } + + for(var i = 0; i < argument_count; i++) + append(argument[i]) + + + static toString = function() { + return self.join() + } +} + + +///@function Range(min, max, step) +///@function Range(min, max) +///@function Range(max) +///@description Returns a new Array object, containing numbers in certain range +function Range() : Array() constructor { + + if argument_count > 1 { + var mi = argument[0]; + var ma = argument[1]; + } + else { + var mi = 0; + var ma = argument[0]; + } + + if argument_count > 2 { + var step = argument[2]; + } + else { + var step = 1; + } + + + // Iterate! + if mi < ma // Normal + { + for(var i = mi; i <= ma; i += step) { + append(i); + } + } + else { // Reversed + for(var i = mi; i >= ma; i += step) { + append(i); + } + } + + return self +} + + +///@function Iterator(arr) +///@description Constructs an iterator object to allow easier iteration through Array's +function Iterator(arr) constructor { + self.index = -1; + self.value = undefined; + self.array = arr + + ///@function next() + next = function() { + index++; + try { + value = array.get(index); + } + catch(e) { + value = undefined; + } + + return value; + } + + get = function() { + return value; + } + + + return self; +} + +// Helper functions to convert between data types + +///@function array_to_Array(array) +///@description Returns an instance of Array object with all the contents of an array +///@param {array} array +function array_to_Array(array) { + if(!is_array(array)) { + __throw( "TypeError: expected array, got "+typeof(array)); + return undefined; + } + + ans = new Array(); + + for(var i = 0; i < array_length(array); i++) { + ans.append(array[i]); + } + + return ans; +} + +///@function array_from_Array(Arr) +///@description Mirrors function Array_to_array() +///@param {Array} Arr +function array_from_Array(Arr) { + return Array_to_array(Arr) +} + +///@function ds_list_to_Array(list) +///@description Returns an instance of Array object with all the contents of an array +///@param {real} list +function ds_list_to_Array(list) { + if(!ds_exists(list, ds_type_list)) { + __throw( "Error: ds_list with given index does not exist"); + return undefined; + } + + ans = new Array(); + + for(var i = 0; i < ds_list_size(list); i++) { + ans.append(list[| i]); + } + + return ans; +} + +///@function is_Array(Arr) +///@description Checks if a variable holds reference to an Array object +///@param {any} arr +function is_Array(Arr) { + return is_struct(Arr) and (instanceof(Arr) == "Array" or instanceof(Arr) == "Range"); +} + +///@function Array_to_array(Arr) +///@description Returns contents of an Array object in format of regular array +///@param {Array} Arr +function Array_to_array(Arr) { + if !is_Array(Arr) { + __throw("Error in function Array_to_array(): expected Array(), got "+typeof(Arr)) + return undefined; + } + return Arr.content +} + +///@function ds_list_from_Array(Arr) +///@description Returns contents of an Array object in format of ds_list +///@param {Array} Arr +function ds_list_from_Array(Arr) { + if !is_Array(Arr) { + __throw("Error in function ds_list_from_Array(): expected Array(), got "+typeof(Arr)) + return undefined; + } + + _list = ds_list_create() + Arr.forEach(function(item) { + ds_list_add(_list, item) + }) + return _list +} + +///@function Array_to_ds_list(Arr) +///@description Mirrors function ds_list_from_Array() +///@param {Array} Arr +function Array_to_ds_list(Arr) { + return ds_list_from_Array(Arr) +} + +///@function ds_list_to_array(ds_list) +///@description IMPORTANT: Used for native gm arrays, not Array Class!!! +// use ds_list_to_Array() for Array Class support +///@param {real} ds_list +function ds_list_to_array(_list) { + var arr = [] + + // ah yes, performance + for(var i = ds_list_size(_list) - 1; i >= 0; --i) { + arr[i] = _list[| i] + } + + return arr +} + +///@function ds_list_from_array(gm_array) +///@description IMPORTANT: Used for native gm arrays, not Array Class!!! +// use ds_list_from_Array() for Array Class support +///@param {array} arr +function ds_list_from_array(arr) { + var _list = ds_list_create() + + for(var i = array_length(arr) - 1; i >= 0; --i) { + _list[| i] = arr[i] + } + + return _list +} + +///@function array_to_ds_list(gm_array) +///@description IMPORTANT: Used for native gm arrays, not Array Class!!! +// use ds_list_from_Array() for Array Class support +///@param {array} arr +function array_to_ds_list(arr) { + return ds_list_from_array(arr) +} \ No newline at end of file diff --git a/Sample+Tests/#backups/scripts/SpeedTimer/SpeedTimer.gml.backup0 b/Sample+Tests/#backups/scripts/SpeedTimer/SpeedTimer.gml.backup0 new file mode 100644 index 0000000..53604ca --- /dev/null +++ b/Sample+Tests/#backups/scripts/SpeedTimer/SpeedTimer.gml.backup0 @@ -0,0 +1,29 @@ +// 2020-09-15 09:45:53 +function SpeedTimer() constructor { + start_time = get_timer(); + last_time = start_time; + last_split = undefined; + running = false; + splits = new Array(); + + static startSplit = function() { + running = true; + last_time = get_timer(); + return get_timer(); + } + + static endSplit = function() { + running = false; + var _split = get_timer() - last_time; + splits.append(_split); + + return _split; + } + + static split = function() { + var ans = endSplit(); + startSplit(); + + return ans; + } +} \ No newline at end of file diff --git a/Sample+Tests/#backups/scripts/Tests/Tests.gml.backup0 b/Sample+Tests/#backups/scripts/Tests/Tests.gml.backup0 new file mode 100644 index 0000000..a536410 --- /dev/null +++ b/Sample+Tests/#backups/scripts/Tests/Tests.gml.backup0 @@ -0,0 +1,307 @@ +// 2020-09-15 10:41:53 +// +// +///@description check out ArrayClass.gml for docs + +randomize(); + + +function __Array_test() { + show_debug_message("#### STARTING TESTS ####") + + + // Creating + var array = new Array(0) + + + // Use these if you have fps issues due to garbage collection + // v F1 or Middle Click v + //gc_enable(false) + //gc_collect() + + + // Adding new stuff + array.append(1, 2, 3) + show_debug_message(array) + + + // the most useful function + show_debug_message("#### FOREACH ####") + array.forEach(function(num, pos) { + if num == 3 { + show_debug_message(string(pos) + ") " + string(num) + " is for suckers") + return 1 + // break out of forEach() + } + + if num % 2 == 0 { + show_debug_message(string(pos) + ") " + string(num) + " (even)") + } + else { + show_debug_message(string(pos) + ") " + string(num) + " (odd)") + } + + + // Please don't delete stuff inside .forEach(), use .filter() instead + }) + show_debug_message(array) + + + + // Concatenating regular arrays + show_debug_message("#### CONCAT ####") + array.concat(["string", 1, -pi]) + show_debug_message(array) + + + + // Chaining methods + show_debug_message("#### CHAINING METHODS ####") + + array = new Array(1, "string", pi) + + array = array.insert(0, "first") + .insert(1, "second") + .append("last", "last2") + show_debug_message(array) + + + + // Careful: some methods don't return the array + show_debug_message("#### CHAINING METHODS 2 ####") + var m = array.clear() + //.concat(new Range(1, 4, 1)) + //.concat(new Range(3, 1, -1)) + .append(1, 2, 3, 4) + .append(3, 2, 1) + ._max() + + //.add(1) would throw an error, as it would apply .add() to a number + show_debug_message(array) + show_debug_message(m) + + + + + // getting/setting + show_debug_message("#### GET/SET ####") + var first = array.get(0) + var second = array.get(1) + var last = array.get(array.size-1) + show_debug_message(array) + show_debug_message("First: "+string(first)) + show_debug_message("Second: "+string(second)) + show_debug_message("Last: "+string(last)) + + array.set(0, "first") + array.set(1, "second") + array.set(array.size-1, "last") + show_debug_message(array) + + + + // Modifying contents by hand + show_debug_message("#### MANUAL MODIFYING ####") + array.content = [4, 2, 1, 3, 8, 7, 6, 5] + // Note that size will not automatically update this way + array.size = 8 + show_debug_message(array) + + + + + // Swap + show_debug_message("#### SWAP ####") + array.swap(0, array.size-1) + show_debug_message(array) + + + + + // Slice + show_debug_message("#### SLICE ####") + var array_slice = array.slice(0, 4) + show_debug_message("Sliced 0-4. Result: "+string(array_slice)) + + + // Joining + show_debug_message("#### PRINTING (JOINING) ####") + show_debug_message(array.join("|")) + + + // sorting (slow, don't do every frame) + show_debug_message("#### SORTING ####") + + var t = new SpeedTimer(); + + array.sort(function(a, b) { + return a > b // Descending + }, 0, 4) // from 0 to 3 + + array.sort(function(a, b) { + return a < b // Ascending + }, 4) // from 4 to end + + show_debug_message(array) + + + + // .sorted() and .reversed(), as well as .filter() don't modify the original array + show_debug_message("#### CLEAN FUNCTIONS ####") + var myarray = array.sorted(SORT_ASCENDING, 0, array.size).reversed() + show_debug_message(myarray) + show_debug_message(array) + + + + + // Useful to delete several elements based on some parameter + show_debug_message("#### FILTER ####") + array = array.filter(function(num) { + return num % 2 == 0 + }).concat(array.copy()) // Repeat the array. Note how the copy still has the odd numbers + show_debug_message(array) + + + + + // find() / findAll() + show_debug_message("#### SEARCHING ####") + var idx = array.find(2) + show_debug_message("First 2 is found at "+string(idx)) + + var arr = array.findAll(2) + // yep, you can string() arrays! + show_debug_message("All 2's positions: " + string(arr)) + var num = array.number(2) + show_debug_message("Total amount of 2's: " + string(num)) + + var uniq = array.unique() // like array but without duplicates + var num = uniq.number(2) + show_debug_message("Total amount of 2's: " + string(num)) + + + + + // adding up the whole array + show_debug_message("#### ADDING UP ####") + var sum = array.sum() + show_debug_message(sum) + + // Strings are summable too + array = array.clear().append("Hello", ", ", "World", "!") + show_debug_message(array.sum()) + + + + + // shuffle! + show_debug_message("#### SHUFFLING ####") + array = new Array(1, 2, 3, 4, 5, 6, 7, 8) // array.clear().append() is the most stupid thing you could ever do... + show_debug_message(array.shuffled()) + array.shuffle() + show_debug_message(array) + + + + + // iterators + show_debug_message("#### ITERATORS (EXPERIMENTAL) ####") + + var iter = new Iterator(array) + while !is_undefined(iter.next()) { + var it = iter.get() + show_debug_message("Current iteration: "+string(it)) + } + + + // convertation + show_debug_message("#### CONVERSION ####") + + var arr = ["Lowercase", "a"] + var Arr = new Array("Uppercase", "A") + + var list = ds_list_create() + ds_list_add(list, "ds", "list") + + + var a_to_A = array_to_Array(arr) + var a_to_l = array_to_ds_list(arr) + var A_to_a = Array_to_array(Arr) + var A_to_l = Array_to_ds_list(Arr) + var l_to_a = ds_list_to_array(list) + var l_to_A = ds_list_to_Array(list) + + show_debug_message("From regular array:") + show_debug_message(a_to_A) + show_debug_message(a_to_l) + + show_debug_message("From Array Class:") + show_debug_message(A_to_a) + show_debug_message(A_to_l) + + show_debug_message("From ds_list:") + show_debug_message(l_to_a) + show_debug_message(l_to_A) + + + ds_list_destroy(a_to_l) + ds_list_destroy(A_to_l) + + + // DIFFERENT SORTING ALGORITHMS + var t = new SpeedTimer(); + + // generate dataset + var array = new Array(); + repeat(15) { + array.append(irandom(1000)); + } + + // radix sort + show_debug_message("#### RADIX SORT ####"); + + var arr = array.copy(); + + var time = string(t.split()); + show_debug_message("Array allocated in: "+time); + + show_debug_message(arr.radixSort(4)); + + var time = string(t.split()); + show_debug_message("RadixSorted in: "+time); + + // bogosort OMEGALUL +// show_debug_message("#### BOGOSORT (OMG) ####"); + +// var arr = new Array(3812, 5, 604, 69, 31123, -123456, 1337, .56789, 404); +// var time = string(t.split()); +// show_debug_message("Array allocated in: "+time); + +// show_debug_message(arr.bogosort()); + +// var time = string(t.split()); +// show_debug_message("BogoSorted in: "+time+"("+string(time / 1000000)+"s)"); + + + // merge sort +// var arr = array.copy(); +// var time = string(t.split()); +// show_debug_message("Array allocated in: "+time); + +// show_debug_message(arr.mergeSort()); + +// var time = string(t.split()); +// show_debug_message("MergeSorted in: "+time); + + + // bubble sort + var arr = array.copy(); + var time = string(t.split()); + show_debug_message("Array allocated in: "+time); + + show_debug_message(arr.sort()); + + var time = string(t.split()); + show_debug_message("BubbleSorted in: "+time); +} \ No newline at end of file diff --git a/Sample+Tests/#config/properties.json b/Sample+Tests/#config/properties.json new file mode 100644 index 0000000..0d1b749 --- /dev/null +++ b/Sample+Tests/#config/properties.json @@ -0,0 +1,6 @@ +{ + "indentWithTabs": true, + "linterPrefs": { + + } +} \ No newline at end of file diff --git a/Sample+Tests/ArrayClass.yyp b/Sample+Tests/ArrayClass.yyp index dbb0537..fbe68d3 100644 --- a/Sample+Tests/ArrayClass.yyp +++ b/Sample+Tests/ArrayClass.yyp @@ -1,8 +1,9 @@ { "resources": [ {"id":{"name":"oMain","path":"objects/oMain/oMain.yy",},"order":0,}, - {"id":{"name":"Tests","path":"scripts/Tests/Tests.yy",},"order":1,}, - {"id":{"name":"ArrayClass","path":"scripts/ArrayClass/ArrayClass.yy",},"order":0,}, + {"id":{"name":"ArrayClass","path":"scripts/ArrayClass/ArrayClass.yy",},"order":3,}, + {"id":{"name":"Tests","path":"scripts/Tests/Tests.yy",},"order":0,}, + {"id":{"name":"SpeedTimer","path":"scripts/SpeedTimer/SpeedTimer.yy",},"order":1,}, {"id":{"name":"Room1","path":"rooms/Room1/Room1.yy",},"order":0,}, ], "Options": [ @@ -11,6 +12,10 @@ {"name":"macOS","path":"options/mac/options_mac.yy",}, {"name":"Main","path":"options/main/options_main.yy",}, {"name":"Windows","path":"options/windows/options_windows.yy",}, + {"name":"Amazon Fire","path":"options/amazonfire/options_amazonfire.yy",}, + {"name":"Android","path":"options/android/options_android.yy",}, + {"name":"iOS","path":"options/ios/options_ios.yy",}, + {"name":"tvOS","path":"options/tvos/options_tvos.yy",}, ], "isDnDProject": false, "isEcma": false, @@ -19,8 +24,8 @@ "name": "Default", "children": [], }, - "RoomOrder": [ - {"name":"Room1","path":"rooms/Room1/Room1.yy",}, + "RoomOrderNodes": [ + {"roomId":{"name":"Room1","path":"rooms/Room1/Room1.yy",},}, ], "Folders": [ {"folderPath":"folders/Scripts.yy","order":5,"resourceVersion":"1.0","name":"Scripts","tags":[],"resourceType":"GMFolder",}, @@ -28,10 +33,10 @@ {"folderPath":"folders/Rooms.yy","order":10,"resourceVersion":"1.0","name":"Rooms","tags":[],"resourceType":"GMFolder",}, ], "AudioGroups": [ - {"targets":461609314234257646,"resourceVersion":"1.0","name":"audiogroup_default","resourceType":"GMAudioGroup",}, + {"targets":-1,"resourceVersion":"1.3","name":"audiogroup_default","resourceType":"GMAudioGroup",}, ], "TextureGroups": [ - {"isScaled":true,"autocrop":true,"border":2,"mipsToGenerate":0,"targets":461609314234257646,"resourceVersion":"1.0","name":"Default","resourceType":"GMTextureGroup",}, + {"isScaled":true,"autocrop":true,"border":2,"mipsToGenerate":0,"groupParent":null,"targets":-1,"resourceVersion":"1.3","name":"Default","resourceType":"GMTextureGroup",}, ], "IncludedFiles": [ {"CopyToMask":0,"filePath":"datafiles/GMLive","resourceVersion":"1.0","name":"gcmt-dll.dll","resourceType":"GMIncludedFile",}, @@ -50,9 +55,9 @@ {"CopyToMask":-1,"filePath":"datafiles/GMLive","resourceVersion":"1.0","name":"gmlive-server.n","resourceType":"GMIncludedFile",}, ], "MetaData": { - "IDEVersion": "2.3.0.529", + "IDEVersion": "2.3.1.542", }, - "resourceVersion": "1.3", + "resourceVersion": "1.4", "name": "ArrayClass", "tags": [], "resourceType": "GMProject", diff --git a/Sample+Tests/options/amazonfire/options_amazonfire.yy b/Sample+Tests/options/amazonfire/options_amazonfire.yy new file mode 100644 index 0000000..c4b6d7d --- /dev/null +++ b/Sample+Tests/options/amazonfire/options_amazonfire.yy @@ -0,0 +1,49 @@ +{ + "option_amazonfire_sync_android": false, + "option_amazonfire_display_name": "Created with GameMaker Studio 2", + "option_amazonfire_version": "1.0.0.0", + "option_amazonfire_tools_from_version": false, + "option_amazonfire_build_tools": "", + "option_amazonfire_support_lib": "", + "option_amazonfire_target_sdk": "", + "option_amazonfire_minimum_sdk": "", + "option_amazonfire_compile_sdk": "", + "option_amazonfire_package_domain": "com", + "option_amazonfire_package_company": "company", + "option_amazonfire_package_product": "game", + "option_amazonfire_orient_portrait": true, + "option_amazonfire_orient_portrait_flipped": true, + "option_amazonfire_orient_landscape": true, + "option_amazonfire_orient_landscape_flipped": true, + "option_amazonfire_gamepad_support": true, + "option_amazonfire_lint": false, + "option_amazonfire_install_location": 0, + "option_amazonfire_sleep_margin": 4, + "option_amazonfire_splash_screens_landscape": "${base_options_dir}/amazonfire/splash/landscape.png", + "option_amazonfire_splash_screens_portrait": "${base_options_dir}/amazonfire/splash/portrait.png", + "option_amazonfire_splash_time": 0, + "option_amazonfire_launchscreen_fill": 0, + "option_amazonfire_splashscreen_background_colour": 255, + "option_amazonfire_tv_banner": "${base_options_dir}/amazonfire/tv_banner.png", + "option_amazonfire_interpolate_pixels": false, + "option_amazonfire_screen_depth": 0, + "option_amazonfire_scale": 0, + "option_amazonfire_texture_page": "2048x2048", + "option_amazonfire_icon_ldpi": "${base_options_dir}/android/icons/ldpi.png", + "option_amazonfire_icon_mdpi": "${base_options_dir}/android/icons/mdpi.png", + "option_amazonfire_icon_hdpi": "${base_options_dir}/android/icons/hdpi.png", + "option_amazonfire_icon_xhdpi": "${base_options_dir}/android/icons/xhdpi.png", + "option_amazonfire_icon_xxhdpi": "${base_options_dir}/android/icons/xxhdpi.png", + "option_amazonfire_icon_xxxhdpi": "${base_options_dir}/android/icons/xxxhdpi.png", + "option_amazonfire_permission_write_external_storage": false, + "option_amazonfire_permission_read_phone_state": false, + "option_amazonfire_permission_network_state": false, + "option_amazonfire_permission_internet": true, + "option_amazonfire_permission_bluetooth": true, + "option_amazonfire_permission_record_audio": false, + "option_amazonfire_application_tag_inject": "", + "resourceVersion": "1.0", + "name": "Amazon Fire", + "tags": [], + "resourceType": "GMAmazonFireOptions", +} \ No newline at end of file diff --git a/Sample+Tests/options/android/options_android.yy b/Sample+Tests/options/android/options_android.yy new file mode 100644 index 0000000..328f326 --- /dev/null +++ b/Sample+Tests/options/android/options_android.yy @@ -0,0 +1,76 @@ +{ + "option_android_sync_amazon": false, + "option_android_display_name": "Created with GameMaker Studio 2", + "option_android_version": "1.0.0.0", + "option_android_tools_from_version": false, + "option_android_build_tools": "", + "option_android_support_lib": "", + "option_android_target_sdk": "", + "option_android_minimum_sdk": "", + "option_android_compile_sdk": "", + "option_android_package_domain": "com", + "option_android_package_company": "company", + "option_android_package_product": "game", + "option_android_arch_armv7": true, + "option_android_arch_x86": false, + "option_android_arch_arm64": false, + "option_android_arch_x86_64": false, + "option_android_orient_portrait": true, + "option_android_orient_portrait_flipped": true, + "option_android_orient_landscape": true, + "option_android_orient_landscape_flipped": true, + "option_android_gamepad_support": true, + "option_android_lint": false, + "option_android_install_location": 0, + "option_android_sleep_margin": 4, + "option_android_splash_screens_landscape": "${base_options_dir}/android/splash/landscape.png", + "option_android_splash_screens_portrait": "${base_options_dir}/android/splash/portrait.png", + "option_android_splash_time": 0, + "option_android_launchscreen_fill": 0, + "option_android_splashscreen_background_colour": 255, + "option_android_tv_banner": "${base_options_dir}/android/tv_banner.png", + "option_android_interpolate_pixels": false, + "option_android_screen_depth": 0, + "option_android_device_support": 0, + "option_android_scale": 0, + "option_android_texture_page": "2048x2048", + "option_android_icon_ldpi": "${base_options_dir}/android/icons/ldpi.png", + "option_android_icon_mdpi": "${base_options_dir}/android/icons/mdpi.png", + "option_android_icon_hdpi": "${base_options_dir}/android/icons/hdpi.png", + "option_android_icon_xhdpi": "${base_options_dir}/android/icons/xhdpi.png", + "option_android_icon_xxhdpi": "${base_options_dir}/android/icons/xxhdpi.png", + "option_android_icon_xxxhdpi": "${base_options_dir}/android/icons/xxxhdpi.png", + "option_android_icon_adaptive_generate": false, + "option_android_icon_adaptive_ldpi": "${base_options_dir}/android/icons_adaptive/ldpi.png", + "option_android_icon_adaptive_mdpi": "${base_options_dir}/android/icons_adaptive/mdpi.png", + "option_android_icon_adaptive_hdpi": "${base_options_dir}/android/icons_adaptive/hdpi.png", + "option_android_icon_adaptive_xhdpi": "${base_options_dir}/android/icons_adaptive/xhdpi.png", + "option_android_icon_adaptive_xxhdpi": "${base_options_dir}/android/icons_adaptive/xxhdpi.png", + "option_android_icon_adaptive_xxxhdpi": "${base_options_dir}/android/icons_adaptive/xxxhdpi.png", + "option_android_icon_adaptivebg_ldpi": "${base_options_dir}/android/icons_adaptivebg/ldpi.png", + "option_android_icon_adaptivebg_mdpi": "${base_options_dir}/android/icons_adaptivebg/mdpi.png", + "option_android_icon_adaptivebg_hdpi": "${base_options_dir}/android/icons_adaptivebg/hdpi.png", + "option_android_icon_adaptivebg_xhdpi": "${base_options_dir}/android/icons_adaptivebg/xhdpi.png", + "option_android_icon_adaptivebg_xxhdpi": "${base_options_dir}/android/icons_adaptivebg/xxhdpi.png", + "option_android_icon_adaptivebg_xxxhdpi": "${base_options_dir}/android/icons_adaptivebg/xxxhdpi.png", + "option_android_use_facebook": false, + "option_android_facebook_id": "", + "option_android_facebook_app_display_name": "", + "option_android_google_cloud_saving": false, + "option_android_google_services_app_id": "", + "option_android_permission_write_external_storage": false, + "option_android_permission_read_phone_state": false, + "option_android_permission_network_state": false, + "option_android_permission_internet": true, + "option_android_permission_bluetooth": true, + "option_android_permission_record_audio": false, + "option_android_application_tag_inject": "", + "option_android_google_apk_expansion": false, + "option_android_google_dynamic_asset_delivery": false, + "option_android_google_licensing_public_key": "", + "option_android_tv_isgame": true, + "resourceVersion": "1.0", + "name": "Android", + "tags": [], + "resourceType": "GMAndroidOptions", +} \ No newline at end of file diff --git a/Sample+Tests/options/ios/options_ios.yy b/Sample+Tests/options/ios/options_ios.yy new file mode 100644 index 0000000..1498dc4 --- /dev/null +++ b/Sample+Tests/options/ios/options_ios.yy @@ -0,0 +1,50 @@ +{ + "option_ios_display_name": "Created with GameMaker Studio 2", + "option_ios_bundle_name": "com.company.game", + "option_ios_version": "1.0.0.0", + "option_ios_output_dir": "~/gamemakerstudio2", + "option_ios_team_id": "", + "option_ios_orientation_portrait": true, + "option_ios_orientation_portrait_flipped": true, + "option_ios_orientation_landscape": true, + "option_ios_orientation_landscape_flipped": true, + "option_ios_devices": 2, + "option_ios_defer_home_indicator": false, + "option_ios_icon_iphone_app_120": "${base_options_dir}/ios/icons/app/iphone_120.png", + "option_ios_icon_iphone_app_180": "${base_options_dir}/ios/icons/app/iphone_180.png", + "option_ios_icon_ipad_app_76": "${base_options_dir}/ios/icons/app/ipad_76.png", + "option_ios_icon_ipad_app_152": "${base_options_dir}/ios/icons/app/ipad_152.png", + "option_ios_icon_ipad_pro_app_167": "${base_options_dir}/ios/icons/app/ipad_pro_167.png", + "option_ios_icon_iphone_notification_40": "${base_options_dir}/ios/icons/notification/iphone_40.png", + "option_ios_icon_iphone_notification_60": "${base_options_dir}/ios/icons/notification/iphone_60.png", + "option_ios_icon_ipad_notification_20": "${base_options_dir}/ios/icons/notification/ipad_20.png", + "option_ios_icon_ipad_notification_40": "${base_options_dir}/ios/icons/notification/ipad_40.png", + "option_ios_icon_iphone_spotlight_80": "${base_options_dir}/ios/icons/spotlight/iphone_80.png", + "option_ios_icon_iphone_spotlight_120": "${base_options_dir}/ios/icons/spotlight/iphone_120.png", + "option_ios_icon_ipad_spotlight_40": "${base_options_dir}/ios/icons/spotlight/ipad_40.png", + "option_ios_icon_ipad_spotlight_80": "${base_options_dir}/ios/icons/spotlight/ipad_80.png", + "option_ios_icon_iphone_settings_58": "${base_options_dir}/ios/icons/settings/iphone_58.png", + "option_ios_icon_iphone_settings_87": "${base_options_dir}/ios/icons/settings/iphone_87.png", + "option_ios_icon_ipad_settings_29": "${base_options_dir}/ios/icons/settings/ipad_29.png", + "option_ios_icon_ipad_settings_58": "${base_options_dir}/ios/icons/settings/ipad_58.png", + "option_ios_icon_itunes_artwork_1024": "${base_options_dir}/ios/icons/itunes/itunes_1024.png", + "option_ios_splashscreen_background_colour": 255, + "option_ios_launchscreen_image": "${base_options_dir}/ios/splash/launchscreen.png", + "option_ios_launchscreen_image_landscape": "${base_options_dir}/ios/splash/launchscreen-landscape.png", + "option_ios_launchscreen_fill": 0, + "option_ios_interpolate_pixels": false, + "option_ios_half_ipad1_textures": false, + "option_ios_scale": 0, + "option_ios_texture_page": "2048x2048", + "option_ios_use_facebook": false, + "option_ios_facebook_id": "", + "option_ios_facebook_app_display_name": "", + "option_ios_push_notifications": false, + "option_ios_apple_sign_in": false, + "option_ios_podfile_path": "${options_dir}/ios/Podfile", + "option_ios_podfile_lock_path": "${options_dir}/ios/Podfile.lock", + "resourceVersion": "1.3", + "name": "iOS", + "tags": [], + "resourceType": "GMiOSOptions", +} \ No newline at end of file diff --git a/Sample+Tests/options/tvos/options_tvos.yy b/Sample+Tests/options/tvos/options_tvos.yy new file mode 100644 index 0000000..5ee2c44 --- /dev/null +++ b/Sample+Tests/options/tvos/options_tvos.yy @@ -0,0 +1,29 @@ +{ + "option_tvos_display_name": "Made in GameMaker Studio 2", + "option_tvos_bundle_name": "com.company.game", + "option_tvos_version": "1.0.0.0", + "option_tvos_output_dir": "~/GameMakerStudio2/tvOS", + "option_tvos_team_id": "", + "option_tvos_icon_400": "${base_options_dir}/tvos/icons/400.png", + "option_tvos_icon_400_2x": "${base_options_dir}/tvos/icons/400_2x.png", + "option_tvos_icon_1280": "${base_options_dir}/tvos/icons/1280.png", + "option_tvos_topshelf": "${base_options_dir}/tvos/topshelf/topshelf.png", + "option_tvos_topshelf_2x": "${base_options_dir}/tvos/topshelf/topshelf_2x.png", + "option_tvos_topshelf_wide": "${base_options_dir}/tvos/topshelf/topshelf_wide.png", + "option_tvos_topshelf_wide_2x": "${base_options_dir}/tvos/topshelf/topshelf_wide_2x.png", + "option_tvos_splashscreen": "${base_options_dir}/tvos/splash/splash.png", + "option_tvos_splashscreen_2x": "${base_options_dir}/tvos/splash/splash_2x.png", + "option_tvos_splash_time": 0, + "option_tvos_interpolate_pixels": true, + "option_tvos_scale": 0, + "option_tvos_texture_page": "2048x2048", + "option_tvos_display_cursor": false, + "option_tvos_push_notifications": false, + "option_tvos_apple_sign_in": false, + "option_tvos_podfile_path": "${options_dir}\\tvos\\Podfile", + "option_tvos_podfile_lock_path": "${options_dir}\\tvos\\Podfile.lock", + "resourceVersion": "1.3", + "name": "tvOS", + "tags": [], + "resourceType": "GMtvOSOptions", +} \ No newline at end of file diff --git a/Sample+Tests/options/windows/options_windows.yy b/Sample+Tests/options/windows/options_windows.yy index 7fb7dad..44cc31c 100644 --- a/Sample+Tests/options/windows/options_windows.yy +++ b/Sample+Tests/options/windows/options_windows.yy @@ -7,9 +7,9 @@ "option_windows_copyright_info": "", "option_windows_description_info": "A GameMaker Studio 2 Game", "option_windows_display_cursor": true, - "option_windows_icon": "${base_options_dir}\\windows\\icons\\icon.ico", + "option_windows_icon": "${base_options_dir}/windows/icons/icon.ico", "option_windows_save_location": 0, - "option_windows_splash_screen": "${base_options_dir}\\windows\\splash\\splash.png", + "option_windows_splash_screen": "${base_options_dir}/windows/splash/splash.png", "option_windows_use_splash": false, "option_windows_start_fullscreen": false, "option_windows_allow_fullscreen_switching": false, @@ -21,14 +21,15 @@ "option_windows_copy_exe_to_dest": false, "option_windows_sleep_margin": 10, "option_windows_texture_page": "2048x2048", - "option_windows_installer_finished": "${base_options_dir}\\windows\\installer\\finished.bmp", - "option_windows_installer_header": "${base_options_dir}\\windows\\installer\\header.bmp", - "option_windows_license": "${base_options_dir}\\windows\\installer\\license.txt", - "option_windows_nsis_file": "${base_options_dir}\\windows\\installer\\nsis_script.nsi", + "option_windows_installer_finished": "${base_options_dir}/windows/installer/finished.bmp", + "option_windows_installer_header": "${base_options_dir}/windows/installer/header.bmp", + "option_windows_license": "${base_options_dir}/windows/installer/license.txt", + "option_windows_nsis_file": "${base_options_dir}/windows/installer/nsis_script.nsi", "option_windows_enable_steam": false, "option_windows_disable_sandbox": false, "option_windows_steam_use_alternative_launcher": false, - "resourceVersion": "1.0", + "option_windows_use_x64": false, + "resourceVersion": "1.1", "name": "Windows", "tags": [], "resourceType": "GMWindowsOptions", diff --git a/Sample+Tests/scripts/ArrayClass/ArrayClass.gml b/Sample+Tests/scripts/ArrayClass/ArrayClass.gml index af55f8c..504460a 100644 --- a/Sample+Tests/scripts/ArrayClass/ArrayClass.gml +++ b/Sample+Tests/scripts/ArrayClass/ArrayClass.gml @@ -4,6 +4,8 @@ // See type-conversion API at the bottom of this file +globalvar ARRAY_LOOP; // edit this inside forEach, filter, etc. to exit a loop +ARRAY_LOOP = 1; ///@function Array(*item1, *item2, ...) ///@description Constructor funcion for Array objects @@ -18,13 +20,16 @@ function Array() constructor { #macro ARRAY_SHOW_WARNING true - __throw = function(err) { + static __throw = function(err) { if ARRAY_SHOW_ERROR { throw err; } else if ARRAY_SHOW_WARNING { show_debug_message("Array error: "+string(err)) } + else { + // nothing + } } ///@function append(value, value2, ..) @@ -53,6 +58,19 @@ function Array() constructor { return self; } + ///@function bogosort() + ///@description This is just a funny meme, please don't use this in actual projects + static bogosort = function(func) { + var i = 0; + while(!self.isSorted(func)) { + self.shuffle(); + i++; + } + + //show_debug_message("bogosort complete in "+string(i)+" iteration(s)"); + return self; + } + ///@function concat(other) ///@description Adds every element of the second array to this array ///@param {Array/array} other @@ -77,11 +95,12 @@ function Array() constructor { ///@function copy() ///@description Returns a copy of the array object static copy = function() { - ans = new Array(); + var ans = new Array(); - forEach(function(el) { - ans.append(el); - }); + for(var i = 0; i < size; ++i) { + var el = get(i); + ans.push(el); + } return ans; } @@ -95,33 +114,6 @@ function Array() constructor { return self; } - ///@function remove(pos) - ///@description removes the value at given position - ///@param {real} pos - static remove = function(pos) { - if(pos < 0) - pos += size; - - if(size == 0) { - __throw("Error: trying to remove value from an empty Array"); - return self; - } - else if(pos < 0 or pos > size - 1) { - __throw( "Error: index "+string(pos)+" is out of range [0, "+string(size-1)+"]"); - return self; - } - - var part1 = slice(0, pos); - var part2 = slice(pos+1); - - part1.concat(part2); - - content = part1.content; - size--; - - return self; - } - ///@function empty() ///@description Returns true if the array is empty and false otherwise static empty = function() { @@ -165,38 +157,39 @@ function Array() constructor { ///@function exists(value) ///@description Returns true if the value exists in the array and false otherwise - static exists = function(_val) { - val = _val; - ans = false; - - forEach(function(x, pos) { - if(x == val) { + static exists = function(val) { + var ans = false; + for(var i = 0; i < size; ++i) { + if (get(i) == val) { ans = true; - return 1; //Break out of forEach() + break; } - }); + } return ans; } ///@function filter(func) ///@description Loops through the array and passes each value into a function. - /// Returns a new array with only values, that returned true. + /// Filters the array to only include values, that returned true. /// Function func gets (x, *pos) as input - /// Note: Clean function. Does not affect the original array! ///@param {function} func static filter = function(_func) { func = _func; - ans = new Array(); + var ans = new Array(); - forEach(function(x, pos) { - if(func(x, pos)) - ans.append(x); - }); + ARRAY_LOOP = true; + for(var i = 0; i < size; ++i) { + if(func(get(i), i)) + ans.append(get(i)); + + if (!ARRAY_LOOP) + break; + } - //content = ans.content; - //return self; - return ans; + content = ans.content; + size = ans.size; + return self; } ///@function find(value) @@ -204,14 +197,14 @@ function Array() constructor { ///@param {any} value static find = function(_val) { val = _val; - ans = -1; + var ans = -1; - forEach(function(x, pos) { + ans = findAnswer(function(x, pos, ans) { if(x == val) { - ans = pos; - return 1; //Break out of forEach() + ARRAY_LOOP = 0; + return pos; } - }); + }, ans); return ans; } @@ -219,17 +212,55 @@ function Array() constructor { ///@function findAll(value) ///@description finds all places a value appears and returns an Array with all the positions. empty set if not found ///@param {any} value - static findAll = function(_val) { - val = _val; - ans = new Array(); + static findAll = function(val) { + var ans = new Array(); - forEach(function(x, pos) { - if(x == val) + ans = findAnswer(function(x, pos, struct) { + var val = struct.val; + var ans = struct.ans; + + if(x == val) { ans.append(pos); - }); + } + + if (pos == size-1) { + ARRAY_LOOP = false; + return ans; + } + else { + return {ans: ans, val: val} + } + }, {ans: ans, val: val}); + + return ans; + } + + ///@function findAnswer(func, def_ans) + ///@description loops over the Array and returns the value when your function sets ARRAY_LOOP to `false` + /// works not too unlike forEach(), but uses function format `foo(val, idx, ans)`, on first iteration ans = undefined + /// alternatively you can provide a default answer, that gets passed into the first iteration + /// basically this is a customized find() function, that can return anything you want + ///@note + /// Note: Loop will stop immediately if you set ARRAY_LOOP globalvar to 0 + ///@param {function} func + ///@param {any} def_ans + static findAnswer = function(func, ans) { + if (argument_count < 2) + ans = undefined; + + ARRAY_LOOP = true; + + for(var i = 0; i < size; ++i) { + ans = func(get(i), i, ans); + if (!ARRAY_LOOP) { + break; + } + } return ans; } + + static findCustom = findAnswer; ///@function first() ///@description Returns the first value of the array @@ -239,13 +270,16 @@ function Array() constructor { ///@function forEach(func) ///@description Loops through the array and runs the function with each element as an argument - /// Function func gets (x, *pos) as arguments - /// Note: Loop will stop immediately if the function returns anything but zero or undefined - ///@param {function} func(x, *pos) + /// Function format is `foo(val, *pos)` (function takes value and position as arguments) + /// Note: Loop will stop immediately if you set ARRAY_LOOP globalvar to 0 + ///@param {function} func static forEach = function(func) { + ARRAY_LOOP = true; + for(var i = 0; i < size; i++) { - var res = func(get(i), i) - if(!is_undefined(res) and res != 0) { + //var res = + func(get(i), i) + if(!ARRAY_LOOP) { break; } } @@ -273,6 +307,20 @@ function Array() constructor { return content[pos]; } + ///@function getRandom() + ///@description Returns a random element from the array + static getRandom = function() { + var idx = irandom(size-1) + if empty() { + var ans = undefined + } + else { + var ans = get(idx) + } + + return ans + } + ///@function insert(pos, value) ///@description inserts a value into the array at given position ///@param {real} pos @@ -298,6 +346,26 @@ function Array() constructor { return self; } + ///@function isSorted(func) + ///@description checks wether the array is sorted or not. + /// You can provide a function that compares `a` and `b` and returns true if a is "less" + /// default function: (a, b) => { return a < b; } + ///@param {function} func + static isSorted = function(func) { + if is_undefined(func) { + //func = function(a, b) { + // return a < b; + //} + func = SORT_ASCENDING + } + + for(var i = 1; i < size; ++i) { + if !func(content[i-1], content[i]) + return false; + } + return true; + } + ///@function join(separator) ///@description returns a string, containing all of the array values separated by 'sep' ///@tip to join part of the array, use array.slice().join() @@ -331,9 +399,14 @@ function Array() constructor { ///@function lambda(func) ///@description Loops through the array and applies the function to each element ///@param {function} func(x, *pos) + /// Note: Loop will stop immediately if you set ARRAY_LOOP globalvar to 0 static lambda = function(func) { + ARRAY_LOOP = true; + for(var i = 0; i < size; i++) { - set(i, func(get(i), i) ); + set(i, func(get(i),i) ); + if(!ARRAY_LOOP) + break; } return self; @@ -348,18 +421,17 @@ function Array() constructor { ///@function _max() ///@description Returns a maximum of the array. Only works with numbers static _max = function() { - ans = get(0); + var ans = get(0); - forEach(function(x) { + ans = findAnswer(function(x, ans) { if(!is_numeric(x)) { __throw( "TypeError: Trying to calculate maximum of "+typeof(x)+""); - ans = undefined; - return 1 // Break out of forEach() + return undefined; // Break out of the loop } if(x > ans) - ans = x; - }); + return x; + }, ans); return ans; } @@ -367,22 +439,123 @@ function Array() constructor { ///@function _min() ///@description Returns a minimum of the array. Only works with numbers static _min = function() { - ans = content[0]; + var ans = get(0); - forEach(function(x) { + forEach(function(x, ans) { if(!is_numeric(x)) { __throw( "TypeError: Trying to calculate minimum of "+typeof(x)+""); - ans = undefined; - return 1 + ARRAY_LOOP = false; + return undefined; } if(x < ans) - ans = x; - }); + return x; + }, ans); return ans; } + ///@function merge(other) + ///@description Merges this array with another + static merge = function(_other) { + for(var i = 0; i < _other.size; ++i) { + self.append(_other.get(i)); + } + + return self; + } + + ///@function merged(other) + ///@description like merge() method, but without modifying the original array + static merged = function(_other) { + var ans = self.copy(); + _other.forEach(function(item) { + ans.append(item); + }) + + return ans; + } + + ///@function __merge(other) + ///@description an internal function, used for MergeSorting. + /// Not for you to use. (unless you know what you're doing) :] + static __merge = function(func, _other) { + var ans = array_create(size + _other.size); + var i = 0; + var j = 0; + var k = 0; + while(i < size && j < _other.size) { + //if self.get(i) < _other.get(j) { + if func(self.get(i), _other.get(j)) { + ans[k] = self.get(i); + i++; + } + else { + ans[k] = _other.get(j); + j++; + } + + k++ + } + + while(i < size) { + ans[k] = self.get(i); + i++; + k++; + } + + while(j < _other.size) { + ans[k] = _other.get(j); + j++; + k++; + } + + return array_to_Array(ans); + } + + ///@note Does not affect the original array!! (due to the internal recursive way it works) + /// !!! This is an internal function! You probably want to use the version without '__' !!! + /// (unless you know what you're doing) + static __mergeSort = function(func, l, r) { + if is_undefined(func) + func = SORT_ASCENDING + if is_undefined(l) + l = 0; + if is_undefined(r) + r = size; + + + if (r - l <= 1) || size <= 1 + return slice(l, r); + //return self; + + var mid = (l + r - 1) / 2; + + if (size % 2 == 0) { + var L = slice(l, mid).__mergeSort(func); + var R = slice(mid+1, r).__mergeSort(func); + } + else { + var L = slice(l, mid).__mergeSort(func); + var R = slice(mid, r).__mergeSort(func); + } + + var _merged = L.__merge(func, R); + + return _merged; + } + + ///@function __mergeSort(l, r, func) + ///@description Sorts the array using merge sort algorithm + /// In theory this should be fast, but my implementation is slower than bubble sort :) + /// So actually there's no reason to use this... + ///@param {function} func - a function, used to compare values. See .sort() for explanation + ///@param {real} l - the index to start the sort from. Defaults to 0 + ///@param {real} r - the index to end the sort on (including). Defaults to array.size + static mergeSort = function(func, l, r) { + return __mergeSort(func, l, r) + } + ///@function number(value) ///@description Returns the amount of elements equal to given value in the array ///@note IMPORTANT! Don't try to use this with data structures, as results may be unpredictable @@ -403,7 +576,7 @@ function Array() constructor { ///@function pop() ///@description removes a value from the end of the array and returns it static pop = function() { - ans = last(); + var ans = last(); if(empty()) { __throw( "Error: trying to pop value from empty Array"); return undefined; @@ -417,7 +590,7 @@ function Array() constructor { ///@function popBack() ///@description removes a value from the beginning of the array and returns it static popBack = function() { - ans = first(); + var ans = first(); remove(0); return ans; @@ -443,18 +616,137 @@ function Array() constructor { insert(0, val); } - ///@function getRandom() - ///@description Returns a random element from the array - static getRandom = function() { - var idx = irandom(size-1) - if empty() { - var ans = undefined + // An internal function, used for QuickSort + static __partition = function(func, l, r) { + //show_debug_message(slice(l, r-1)) + var i = l-1; + var j = l; + var piv = get(r); + + for(j = l; j < r; ++j) { + //if get(j) <= piv { + if func(get(j), piv) { + i++; + swap(i, j); + } } - else { - var ans = get(idx) + + swap(i+1, j); + + return i; + } + + ///@function quickSort(func, l, r) + ///@param {function} func + ///@param {int} l + ///@param {int} r + static quickSort = function(func, l, r) { // including r + if is_undefined(func) + func = SORT_ASCENDING + if is_undefined(l) + l = 0 + if is_undefined(r) + r = size-1 + + if (l < r-1) { + var pivot = __partition(func, l, r); + + quickSort(func, l, pivot); + quickSort(func, pivot+1, r); } - return ans + return self; + } + + ///@function radixSort() + ///@description sorts the array using radix sort algorithm + static radixSort = function(digits) { + + static getDigit = function(num, digit) { // digit from right to left + repeat(digit) { + num = num div 10; + } + return (num % 10); + } + + for(var digit = 0; digit < digits; ++digit) { + // 0-9 indexies representing each possible digit + static counters = array_create(10, 0); + static output = array_create(size, -1); + + for(var i = 9; i >= 0; --i) + counters[i] = 0; + + for(var i = size-1; i >= 0; --i) + output[i] = -1; + + for(var i = 0; i < size; ++i) { + var dig = getDigit(content[i], digit); + counters[dig]++; + } + + // sum + var len = array_length(counters) + for(var i = 1; i < len; ++i) { + counters[i] += counters[i - 1]; // get positions + } + + for(var i = size - 1; i >= 0; --i) { + var dig = getDigit(content[i], digit); + var pos = counters[dig]; + + if pos != 0 + pos--; + + while(output[pos] != -1) + pos--; + + output[pos] = content[i]; + } + + //array_copy(content, 0, output, 0, array_length(output)); + content = output; + } + + return self; + } + + ///@function remove(pos) + ///@description removes the value at given position + ///@param {real} pos + static remove = function(pos) { + if(pos < 0) + pos += size; + + if(size == 0) { + __throw("Error: trying to remove value from an empty Array"); + return self; + } + else if(pos < 0 or pos > size - 1) { + __throw( "Error: index "+string(pos)+" is out of range [0, "+string(size-1)+"]"); + return self; + } + + var part1 = slice(0, pos); + var part2 = slice(pos+1); + + part1.concat(part2); + + content = part1.content; + size--; + + return self; + } + + ///@function removeValue(value) + ///@description removes a selected value from the array + ///@param {any} value + static removeValue = function(value) { + var idx = find(value); + if (idx > -1) + remove(idx); + + return self; } ///@function resize(size) @@ -477,12 +769,13 @@ function Array() constructor { } ///@function reverse() - ///@description reverses the array, affecting it + ///@description reverses the array (overrides its contents) static reverse = function() { - ans = new Array(); - forEach(function(element, pos) { - ans.set(size-pos-1, element); - }); + var ans = new Array(); + //forEach(function(element, pos) { + // ans.set(size-pos-1, element); + //}); + findAnswer() content = ans.content; return self; @@ -491,10 +784,14 @@ function Array() constructor { ///@function reversed() ///@description Returns reversed version of the array, without affecting the original static reversed = function() { - ans = new Array(); - forEach(function(element, pos) { - ans.set(size-pos-1, element); - }); + var ans = new Array(); + //forEach(function(element, pos) { + // ans.set(size-pos-1, element); + //}); + for(var i = 0; i < size; ++i) { + var element = get(i) + ans.set(size-i-1, element) + } return ans; } @@ -527,7 +824,7 @@ function Array() constructor { if(is_undefined(_end)) _end = size; - ans = new Array(); + var ans = new Array(); if(_begin > _end) { @@ -544,6 +841,18 @@ function Array() constructor { return ans; } + ///@function some(predicate) + ///@description Returns whether there's an element in the Array that matches the predicate function + ///@param {function} predicate + static some = function(predicate) { + for(var i = 0; i < size; i++) { + var val = get(i) + if (predicate(val, i)) + return true; + } + return false; + } + ///@function sort(func, *startpos, *endpos) ///@description Bubble sorts through the array in given range, comparing values using provided function. ///Function gets (a, b) as input and must return True if A has more priority than B and False otherwise. @@ -552,6 +861,9 @@ function Array() constructor { ///@param {real} *startpos Default - 0 ///@param {real} *endpos Default - size static sort = function(compare, _begin, _end) { + if (is_undefined(compare)) + compare = SORT_ASCENDING; + if(is_undefined(_begin)) _begin = 0; @@ -611,20 +923,21 @@ function Array() constructor { ///NOTE: Works only with strings or numbars and only if all the elements are the same type. static sum = function() { if(is_string(get(0))) - ans = ""; + var ans = ""; else if(is_numeric(get(0))) - ans = 0; + var ans = 0; else { __throw( "TypeError: trying to sum up elements, that aren't strings or reals"); return undefined; } - forEach(function(el) { - if(typeof(el) != typeof(ans)) + for(var i = 0; i < size; ++i) { + var el = get(i); + if (typeof(el) != typeof(ans)) __throw( "TypeError: Array elements aren't the same type: got "+typeof(el)+", "+typeof(ans)+" expected."); ans += el; - }); + } return ans; } @@ -644,15 +957,54 @@ function Array() constructor { ///@function unique() ///@description Returns a copy of this Array object, deleting all duplicates static unique = function() { - ans = new Array(); + var ans = new Array(); + + //forEach(function(x) { + // if(!ans.exists(x)) + // ans.append(x); + //}); + for(var i = 0; i < size; ++i) { + if (!ans.exists(get(i))) + ans.push(get(i)); + } - forEach(function(x) { - if(!ans.exists(x)) - ans.append(x); - }); + return ans; + } + + + ///@function where(func) + ///@description Loops through the array and passes each value into a function. + /// Returns a new array with only values, that returned true. + /// Function func gets (x, *pos) as input + /// Note: Clean function. Does not affect the original array! + ///@param {function} func + static where = function(_func) { + func = _func; + var ans = new Array(); + + for(var i = 0; i < size; ++i) { + if(func(get(i), i)) + ans.append(get(i)); + } return ans; } + + static wrapIndex = function(idx) { + if (size == 0) + return idx + + while(idx >= size) { + idx -= size + } + + while (idx < 0) { + idx += size + } + + return idx + } + for(var i = 0; i < argument_count; i++) append(argument[i]) @@ -704,31 +1056,63 @@ function Range() : Array() constructor { } +///@function RandomArray(size, pool) +///@param {real} size +///@param {Array} pool +///@description Creates an array and fills it with random contents from the pool. +/// If pool is not provided, Range(100) is used +/// If pool is numeric, Range(pool) is used +function RandomArray(_size, pool) : Array() constructor { + if is_undefined(_size) + _size = 0; + if is_undefined(pool) + pool = new Range(100); + else if is_numeric(pool) + pool = new Range(pool); + else if is_array(pool) + pool = array_to_Array(pool); + + + repeat(_size) { + self.append(pool.getRandom()); + } + + return self; +} + + ///@function Iterator(arr) ///@description Constructs an iterator object to allow easier iteration through Array's +// actually i have no idea why you would use these function Iterator(arr) constructor { self.index = -1; self.value = undefined; self.array = arr + self.loop = false ///@function next() - next = function() { + static next = function() { index++; - try { + if (index > array.size) { value = array.get(index); } - catch(e) { - value = undefined; + else { + if (loop) { + index = 0 + value = array.get(index) + } + else { + value = undefined; + } } return value; } - get = function() { + static get = function() { return value; } - return self; } @@ -743,7 +1127,7 @@ function array_to_Array(array) { return undefined; } - ans = new Array(); + var ans = new Array(); for(var i = 0; i < array_length(array); i++) { ans.append(array[i]); @@ -768,7 +1152,7 @@ function ds_list_to_Array(list) { return undefined; } - ans = new Array(); + var ans = new Array(); for(var i = 0; i < ds_list_size(list); i++) { ans.append(list[| i]); @@ -806,7 +1190,14 @@ function ds_list_from_Array(Arr) { _list = ds_list_create() Arr.forEach(function(item) { - ds_list_add(_list, item) + //if (is_Array(item)) { + // item = ds_list_from_Array(item) + // ds_list_add(_list, item) + // ds_list_mark_as_list(_list, ds_list_size(_list)-1) + //} + //else { + ds_list_add(_list, item) + //} }) return _list } @@ -853,4 +1244,50 @@ function ds_list_from_array(arr) { ///@param {array} arr function array_to_ds_list(arr) { return ds_list_from_array(arr) -} \ No newline at end of file +} + + +// for nerds who care about optimization and use native arrays +#region non-OO arrays functions + +///@function array_exists(array, val) +///@description IMPORTANT: Used for native gm arrays, not Array Class!!! +function array_exists(array, val) { + var _len = array_length(array) + for(var i = 0; i < _len; ++i) { + if (array[i] == val) + return true + } + + return false +} + +///@function array_find(array, val) +///@description IMPORTANT: Used for native gm arrays, not Array Class!!! +function array_find(array, val) { + var _len = array_length(array) + for(var i = 0; i < _len; ++i) { + if (array[i] == val) + return i + } + + return -1 +} + +///@function array_foreach(array, func) +///@description IMPORTANT: Used for native gm arrays, not Array Class!!! +function array_foreach(array, func) { + var _len = array_length(array) + for(var i = 0; i < _len; ++i) { + func(array[i], i) + } +} + +///@function array_push(array, val) +///@description IMPORTANT: Used for native gm arrays, not Array Class!!! +function array_push(array, val) { + array[@ array_length(array)] = val +} + + +#endregion \ No newline at end of file diff --git a/Sample+Tests/scripts/SpeedTimer/SpeedTimer.gml b/Sample+Tests/scripts/SpeedTimer/SpeedTimer.gml new file mode 100644 index 0000000..dd5f80c --- /dev/null +++ b/Sample+Tests/scripts/SpeedTimer/SpeedTimer.gml @@ -0,0 +1,28 @@ +function SpeedTimer() constructor { + start_time = get_timer(); + last_time = start_time; + last_split = undefined; + running = false; + splits = new Array(); + + static startSplit = function() { + running = true; + last_time = get_timer(); + return get_timer(); + } + + static endSplit = function() { + running = false; + var _split = get_timer() - last_time; + splits.append(_split); + + return _split; + } + + static split = function() { + var ans = endSplit(); + startSplit(); + + return ans; + } +} \ No newline at end of file diff --git a/Sample+Tests/scripts/SpeedTimer/SpeedTimer.yy b/Sample+Tests/scripts/SpeedTimer/SpeedTimer.yy new file mode 100644 index 0000000..f4758e8 --- /dev/null +++ b/Sample+Tests/scripts/SpeedTimer/SpeedTimer.yy @@ -0,0 +1,12 @@ +{ + "isDnD": false, + "isCompatibility": false, + "parent": { + "name": "Scripts", + "path": "folders/Scripts.yy", + }, + "resourceVersion": "1.0", + "name": "SpeedTimer", + "tags": [], + "resourceType": "GMScript", +} \ No newline at end of file diff --git a/Sample+Tests/scripts/Tests/Tests.gml b/Sample+Tests/scripts/Tests/Tests.gml index bb84d56..30df87c 100644 --- a/Sample+Tests/scripts/Tests/Tests.gml +++ b/Sample+Tests/scripts/Tests/Tests.gml @@ -2,6 +2,9 @@ // ///@description check out ArrayClass.gml for docs +randomize(); + + function __Array_test() { show_debug_message("#### STARTING TESTS ####") @@ -26,7 +29,7 @@ function __Array_test() { array.forEach(function(num, pos) { if num == 3 { show_debug_message(string(pos) + ") " + string(num) + " is for suckers") - return 1 + ARRAY_LOOP = false // break out of forEach() } @@ -38,7 +41,7 @@ function __Array_test() { } - // Please don't delete stuff inside .forEach(), use .filter() instead + // Please don't delete stuff inside .forEach(), use .filter() or .where() instead }) show_debug_message(array) @@ -127,6 +130,9 @@ function __Array_test() { // sorting (slow, don't do every frame) show_debug_message("#### SORTING ####") + + var t = new SpeedTimer(); + array.sort(function(a, b) { return a > b // Descending }, 0, 4) // from 0 to 3 @@ -139,7 +145,6 @@ function __Array_test() { - // .sorted() and .reversed(), as well as .filter() don't modify the original array show_debug_message("#### CLEAN FUNCTIONS ####") var myarray = array.sorted(SORT_ASCENDING, 0, array.size).reversed() @@ -172,6 +177,7 @@ function __Array_test() { var uniq = array.unique() // like array but without duplicates var num = uniq.number(2) + show_debug_message(uniq) show_debug_message("Total amount of 2's: " + string(num)) @@ -241,4 +247,77 @@ function __Array_test() { ds_list_destroy(a_to_l) ds_list_destroy(A_to_l) + + + // DIFFERENT SORTING ALGORITHMS + show_debug_message("#### SORTING ALGORITHMS ####") + var t = new SpeedTimer(); + + + show_debug_message("randomly generated array:") + // generate dataset + var array = new RandomArray(20, 1000) + if array.size <= 100 + show_debug_message(array) + + + + // radix sort + show_debug_message("#### RADIX SORT ####"); + var arr = array.copy(); t.split(); // ignore array allocation time + + arr.radixSort(4); // 2875 + show_debug_message(arr); + + var time = string(t.split()); + show_debug_message("RadixSorted in: "+time); + + + + // merge sort + show_debug_message("#### MERGESORT ####"); + var arr = array.copy(); t.split(); // ignore array allocation time + + arr.mergeSort(); + show_debug_message(arr); + + var time = string(t.split()); + show_debug_message("MergeSorted in: "+time); + show_debug_message("AS YOU CAN SEE, MERGE SORT DOESN'T WORK..."); + + + + // bubble sort + show_debug_message("#### BUBBLESORT ####"); + var arr = array.copy(); t.split(); // ignore array allocation time + + arr.sort(); + show_debug_message(arr); + + var time = string(t.split()); + show_debug_message("BubbleSorted in: "+time); + + + + // quick sort + show_debug_message("#### QUICKSORT ####"); + var arr = array.copy(); t.split(); // ignore array allocation time + + arr.quickSort(); + + var time = string(t.split()); + show_debug_message("QuickSorted in: "+time); + + show_debug_message(arr) + + + //// bogosort (OMEGALUL) + //show_debug_message("#### BOGOSORT (OMG) ####"); + + //var arr = array.copy(); t.split(); + + //arr.bogosort(); + + //var time = string(t.split()); + //show_debug_message("BogoSorted in: "+time+"("+string(time / 1000000)+"s)"); } \ No newline at end of file