Funkin/source/funkin/util/tools/ArraySortTools.hx
Eric 42d8d55067 Unit Test Suite (#119)
* Initial test suite

* Fix some build warnings

* Implemented working unit tests with coverage

* Reduced some warnings

* Fix a mac-specific issue

* Add 2 additional unit test classes.

* Multiple new unit tests

* Some fixins

* Remove auto-generated file

* WIP on hiding ignored tests

* Added list of debug hotkeys

* Remove old website

* Remove empty file

* Add more unit tests

* Fix bug where arrows would nudge BF

* Fix bug where ctrl/alt would flash capsules

* Fixed bug where bf-old easter egg broke

* Remove duplicate lines

* More test-related stuff

* Some code cleanup

* Add mocking and a test assets folder

* More TESTS!

* Update Hmm...

* Update artist on Monster

* More minor fixes to individual functions

* 1.38% unit test coverage!

* Even more tests? :O

* More unit test work

* Rework migration for BaseRegistry

* gameover fix

* Fix an issue with Lime

* Fix issues with version parsing on data files

* 100 total unit tests!

* Added even MORE unit tests!

* Additional test tweaks :3

* Fixed tests on windows by updating libraries.

* Set versions for flixel-ui and hamcrest

---------

Co-authored-by: Cameron Taylor <cameron.taylor.ninja@gmail.com>
2023-08-22 04:27:30 -04:00

157 lines
5.1 KiB
Haxe

package funkin.util.tools;
/**
* Contains code for sorting arrays using various algorithms.
* @see https://algs4.cs.princeton.edu/20sorting/
*/
class ArraySortTools
{
/**
* Sorts the input array using the merge sort algorithm.
* Stable and guaranteed to run in linearithmic time `O(n log n)`,
* but less efficient in "best-case" situations.
*
* @param input The array to sort in-place.
* @param compare The comparison function to use.
*/
public static function mergeSort<T>(input:Array<T>, compare:CompareFunction<T>):Void
{
if (input == null || input.length <= 1) return;
if (compare == null) throw 'No comparison function provided.';
// Haxe implements merge sort by default.
haxe.ds.ArraySort.sort(input, compare);
}
/**
* Sorts the input array using the quick sort algorithm.
* More efficient on smaller arrays, but is inefficient `O(n^2)` in "worst-case" situations.
* Not stable; relative order of equal elements is not preserved.
*
* @see https://stackoverflow.com/questions/33884057/quick-sort-stackoverflow-error-for-large-arrays
* Fix for stack overflow issues.
* @param input The array to sort in-place.
* @param compare The comparison function to use.
*/
public static function quickSort<T>(input:Array<T>, compare:CompareFunction<T>):Void
{
if (input == null || input.length <= 1) return;
if (compare == null) throw 'No comparison function provided.';
quickSortInner(input, 0, input.length - 1, compare);
}
/**
* Internal recursive function for the quick sort algorithm.
* Written with ChatGPT!
*/
static function quickSortInner<T>(input:Array<T>, low:Int, high:Int, compare:CompareFunction<T>):Void
{
// When low == high, the array is empty or too small to sort.
// EDIT: Recurse on the smaller partition, and loop for the larger partition.
while (low < high)
{
// Designate the first element in the array as the pivot, then partition the array around it.
// Elements less than the pivot will be to the left, and elements greater than the pivot will be to the right.
// Return the index of the pivot.
var pivot:Int = quickSortPartition(input, low, high, compare);
if ((pivot) - low <= high - (pivot + 1))
{
quickSortInner(input, low, pivot, compare);
low = pivot + 1;
}
else
{
quickSortInner(input, pivot + 1, high, compare);
high = pivot;
}
}
}
/**
* Internal function for sorting a partition of an array in the quick sort algorithm.
* Written with ChatGPT!
*/
static function quickSortPartition<T>(input:Array<T>, low:Int, high:Int, compare:CompareFunction<T>):Int
{
// Designate the first element in the array as the pivot.
var pivot:T = input[low];
// Designate two pointers, used to divide the array into two partitions.
var i:Int = low - 1;
var j:Int = high + 1;
while (true)
{
// Move the left pointer to the right until it finds an element greater than the pivot.
do
{
i++;
}
while (compare(input[i], pivot) < 0);
// Move the right pointer to the left until it finds an element less than the pivot.
do
{
j--;
}
while (compare(input[j], pivot) > 0);
// If i and j have crossed, the array has been partitioned, and the pivot will be at the index j.
if (i >= j) return j;
// Else, swap the elements at i and j, and start over.
// This slowly moves the pivot towards the middle of the partition,
// while moving elements less than the pivot to the left and elements greater than the pivot to the right.
var temp:T = input[i];
input[i] = input[j];
input[j] = temp;
}
// Don't expect to get here.
return -1;
}
/**
* Sorts the input array using the insertion sort algorithm.
* Stable and is very fast on nearly-sorted arrays,
* but is inefficient `O(n^2)` in "worst-case" situations.
*
* @param input The array to sort in-place.
* @param compare The comparison function to use.
*/
public static function insertionSort<T>(input:Array<T>, compare:CompareFunction<T>):Void
{
if (input == null || input.length <= 1) return;
if (compare == null) throw 'No comparison function provided.';
// Iterate through the array, starting at the second element.
for (i in 1...input.length)
{
// Store the current element.
var current:T = input[i];
// Store the index of the previous element.
var j:Int = i - 1;
// While the previous element is greater than the current element,
// move the previous element to the right and move the index to the left.
while (j >= 0 && compare(input[j], current) > 0)
{
input[j + 1] = input[j];
j--;
}
// Insert the current element into the array.
input[j + 1] = current;
}
}
}
/**
* A comparison function.
* Returns a negative number if the first argument is less than the second,
* a positive number if the first argument is greater than the second,
* or zero if the two arguments are equal.
*/
typedef CompareFunction<T> = T->T->Int;