import java.math.*; import java.util.*; class consts { public static final int MAXSPRITES = 64; // Number of sprites in our simulation public static final int MAXVALUE = 254; // Maximum Y value for a sprite } interface sortInterface { // Return the name of the method public String name (); // Called prior to a new round of sorting public void sortInit (); // Add sprite to the sorting object // Note that sortInit should be called exactly once prior to any addSprite calls public void addSprite (int index, int y); // Sort the sprites stored in the sorting object public void sort (); // Return next sprite (in sorted order) from the sorting object public int getNextSprite (); } // The bucket sort implementation class bucketSort implements sortInterface { // Constants for this class static final int BUCKETS = 128; // Number of available buckets static final int HASH = (int) Math.ceil ( (double) consts.MAXVALUE / (double) BUCKETS); // Note 1: a major speedup can be obtained by fixing the above values and // then optimizing code for these values. A lot of the casting and Math // cals can then be eliminated. Choosing the number of buckets wisely // and then optimizing the ASM can make the sorting process blazingly fast // 128 buckets seems optimal for 32 sprites, giving the best performace times // Bare in mind that more buckets means larger memory usage // If memory is a big issue, use 64 buckets. // // Note 2: Sprite Y values may not use value 255 in this implementation // This was done for reasons of memory optimization... in real C64 life // We would be using 'bytes' and not 'int' values. However, in Java, the // closest thing to a C64 is a int since Java uses signed bytes :( // Marks a collision list in the bucket map static final int COLLISONMARKER = 254; // Marks special items in lists, tables, etc static final int MARKER = 255; // Start of variables bucketManager Bucket; int[] spriteY = new int[consts.MAXSPRITES]; int bucketIndex; int CollisionPointer; // Helper classes class collisionList { int[] spriteTable = new int[consts.MAXSPRITES]; int[] spriteYTable = new int[consts.MAXSPRITES]; int[] pointerTable = new int[consts.MAXSPRITES]; int freePointer = 0; public collisionList () { // No need to initialize the spriteTable and indexTable structures } public void addNewCollision (int spriteIndex1, int spriteY1, int spriteIndex2, int spriteY2) { // This code is written out entirely for speed optimization if (spriteY1 < spriteY2) { spriteTable[freePointer] = spriteIndex1; spriteYTable[freePointer] = spriteY1; pointerTable[freePointer] = (freePointer + 1); freePointer++; spriteTable[freePointer] = spriteIndex2; spriteYTable[freePointer] = spriteY2; pointerTable[freePointer] = MARKER; freePointer++; } else { spriteTable[freePointer] = spriteIndex2; spriteYTable[freePointer] = spriteY2; pointerTable[freePointer] = (freePointer + 1); freePointer++; spriteTable[freePointer] = spriteIndex1; spriteYTable[freePointer] = spriteY1; pointerTable[freePointer] = MARKER; freePointer++; } } public int addCollision (int Pointer, int spriteIndex, int spriteY) { // Add entry spriteTable[freePointer] = spriteIndex; spriteYTable[freePointer] = spriteY; // Check if this is the new lowest value if (spriteY < spriteYTable[Pointer]) { pointerTable[freePointer] = Pointer; return freePointer++; } // Now we need to find the proper position in the linked list int indexPointer = Pointer; while (spriteYTable[pointerTable[indexPointer]] < spriteY) { // If we reach the end of the list we have find a new highest value if (pointerTable[pointerTable[indexPointer]] == MARKER) { pointerTable[pointerTable[indexPointer]] = freePointer; pointerTable[freePointer++] = MARKER; return Pointer; // Return original starting position } indexPointer = pointerTable[indexPointer]; } // We have found an in-between value at this point int prevPointer = pointerTable[indexPointer]; pointerTable[indexPointer] = freePointer; pointerTable[freePointer] = prevPointer; freePointer++; return Pointer; // Return original starting position } } class bucketManager { // Will hold the sprite entries that have been mapped ("hashed") directly int[] Table = new int[BUCKETS]; // This is the collision table itself for colliding sprites collisionList Collisions = new collisionList (); // Holds pointers to the collision table int[] collisionTable = new int[BUCKETS]; public bucketManager () { for (int i = 0; i < BUCKETS; i++) { Table[i] = MARKER; } // No need to initialize any other structures } } // Constructor public bucketSort () { Bucket = new bucketManager (); if (consts.MAXVALUE >= MARKER) { throw new RuntimeException ("Internal error (MAXVALUE is too large)"); } } // Return name public String name () { return "Bucket sort"; } // Initialize a new sorting iteration public void sortInit () { // Reset collision list Bucket.Collisions.freePointer = 0; // Reset indices for first call to getNextSprite() bucketIndex = 0; CollisionPointer = MARKER; } // Add sprite to the sorting object public void addSprite (int index, int y) { spriteY[index] = y; // Needed for possible later collision resolution int Hash = (y / HASH); // Using integer division here... if (Bucket.Table[Hash] == MARKER) { Bucket.Table[Hash] = index; } else { if (Bucket.Table[Hash] == COLLISONMARKER) { Bucket.collisionTable[Hash] = Bucket.Collisions.addCollision (Bucket. collisionTable[Hash], index, y); } else { // Create a new collison structure Bucket.collisionTable[Hash] = Bucket.Collisions.freePointer; Bucket.Collisions.addNewCollision ( Bucket.Table[Hash], spriteY[Bucket.Table[Hash]], index, y); Bucket.Table[Hash] = COLLISONMARKER; } } } // Sort sprites... but already done! public void sort () { // All the hard work is actually done in addSprite!! } // Get the next sprite in sorted order public int getNextSprite () { int Index; // If we are draining from the collision list, continue to do so... if (CollisionPointer != MARKER) { Index = Bucket.Collisions.spriteTable[CollisionPointer]; CollisionPointer = Bucket.Collisions.pointerTable[CollisionPointer]; return Index; } // Otherwise, continue to drain from the bucket table... while (Bucket.Table[bucketIndex] == MARKER) { bucketIndex++; } Index = Bucket.Table[bucketIndex]; // Clear the entry prior to return (so next sort iteration needs not to clean) Bucket.Table[bucketIndex] = MARKER; if (Index != COLLISONMARKER) { // Just return the sprite index since this is not at a collison marker bucketIndex++; return Index; } // Oops, found a collison marker... need to drain the collison list now if (Index == COLLISONMARKER) { CollisionPointer = Bucket.collisionTable[bucketIndex]; bucketIndex++; return getNextSprite (); // Fetch the first sprite from the collison list } // If we come here we have encountered an internal bug... throw new RuntimeException ("Internal error"); } } // The Ocean sort implementation class oceanSort implements sortInterface { int[] sortOrder = new int[consts.MAXSPRITES]; int[] spriteY = new int[consts.MAXSPRITES]; int sortIndex; // Constructor public oceanSort () { // Initial seed sort order for (int i = 0; i < consts.MAXSPRITES; i++) { sortOrder[i] = i; } } // Return name public String name () { return "Ocean sort"; } // Initialize a new sorting iteration public void sortInit () { sortIndex = 0; // Reset indice for first call to getNextSprite() } // Add a sprite to the sorting object public void addSprite (int index, int y) { spriteY[index] = y; } // Sort sprites... public void sort () { int Elem = (consts.MAXSPRITES - 1); for (int i = 0; i < Elem; i++) { if (spriteY[sortOrder[i]] > spriteY[sortOrder[i + 1]]) { int j = i; while (true) { int swap = sortOrder[j]; sortOrder[j] = sortOrder[j + 1]; sortOrder[j + 1] = swap; if (j == 0) { break; } j--; if (spriteY[sortOrder[j]] < spriteY[sortOrder[j + 1]]) { break; } } } } } public int getNextSprite () { return sortOrder[sortIndex++]; } } // The Ocean Bucket sort implementation // Will try to figure out how much work has to be done before actually // doing anything. If the Ocean sort looks to expensive it will simply // do a bucket sort instead :) // The Ocean sort implementation class oceanBucketSort implements sortInterface { bucketSort BucketSorter = new bucketSort (); int[] sortOrder = new int[consts.MAXSPRITES]; int[] spriteY = new int[consts.MAXSPRITES]; int sortIndex; // Constructor public oceanBucketSort () { // Initial seed sort order for (int i = 0; i < consts.MAXSPRITES; i++) { sortOrder[i] = i; } } // Return name public String name () { return "Ocean Bucket sort"; } // Method that performs a bucket sort if there are too many swaps public void RunBucketSort () { // Ready for action BucketSorter.sortInit (); // Load the bucket sort for (int i = 0; i < consts.MAXSPRITES; i++) { BucketSorter.addSprite (i, spriteY[i]); } // Sort the lot BucketSorter.sort (); // Retrieve info and update internal state for (int i = 0; i < consts.MAXSPRITES; i++) { sortOrder[i] = BucketSorter.getNextSprite (); } } // Initialize a new sorting iteration public void sortInit () { sortIndex = 0; // Reset indice for first call to getNextSprite() } // Add a sprite to the sorting object public void addSprite (int index, int y) { spriteY[index] = y; } // Sort sprites... public void sort () { int totalSwaps = 0; int Elem = (consts.MAXSPRITES - 1); for (int i = 0; i < Elem; i++) { if (spriteY[sortOrder[i]] > spriteY[sortOrder[i + 1]]) { int j = i; while (true) { totalSwaps++; // If we hit the "too much" threshold exit and do a bucket sort! // "Too much" is rated with respect to the progress already made if (totalSwaps > ( (i / 2) + 10)) { RunBucketSort (); return; } int swap = sortOrder[j]; sortOrder[j] = sortOrder[j + 1]; sortOrder[j + 1] = swap; if (j == 0) { break; } j--; if (spriteY[sortOrder[j]] < spriteY[sortOrder[j + 1]]) { break; } } } } } public int getNextSprite () { return sortOrder[sortIndex++]; } } // The Ocean sort implementation class oceanMergeSort implements sortInterface { int[] sortOrder = new int[consts.MAXSPRITES]; int[] spriteY = new int[consts.MAXSPRITES]; int sortIndex; // Constructor public oceanMergeSort () { // Initial seed sort order for (int i = 0; i < consts.MAXSPRITES; i++) { sortOrder[i] = i; } } // Return name public String name () { return "Ocean Merge sort"; } // Initialize a new sorting iteration public void sortInit () { sortIndex = 0; // Reset indice for first call to getNextSprite() } // Add a sprite to the sorting object public void addSprite (int index, int y) { spriteY[index] = y; } // private void sort (int low, int hi) { if (low >= hi) { return; } int mid = (low + hi) / 2; // Partition the list into two lists and sort them recursively sort (low, mid); sort (mid + 1, hi); // Merge the two sorted lists int end_low = mid; int start_hi = mid + 1; while ( (low <= end_low) && (start_hi <= hi)) { if (spriteY[sortOrder[low]] < spriteY[sortOrder[start_hi]]) { low++; } else { int temp = sortOrder[start_hi]; for (int i = start_hi - 1; i >= low; i--) { sortOrder[i + 1] = sortOrder[i]; } sortOrder[low] = temp; // Update pointers low++; end_low++; start_hi++; } } } // Sort sprites... public void sort () { sort (0, (consts.MAXSPRITES - 1)); } public int getNextSprite () { return sortOrder[sortIndex++]; } } // The Ocean Quick sort implementation class oceanFastQuickSort implements sortInterface { int[] sortOrder = new int[consts.MAXSPRITES]; int[] spriteY = new int[consts.MAXSPRITES]; int sortIndex; // Constructor public oceanFastQuickSort () { // Initial seed sort order for (int i = 0; i < consts.MAXSPRITES; i++) { sortOrder[i] = i; } } // Return name public String name () { return "Ocean Fast Quick sort"; } // Initialize a new sorting iteration public void sortInit () { sortIndex = 0; // Reset indice for first call to getNextSprite() } // Add a sprite to the sorting object public void addSprite (int index, int y) { spriteY[index] = y; } // private void quickSort (int left, int right) { int i, j; int temp, value; // Only do quicksort on series that are at least 4 elements long if ( (right - left) > 4) { i = ( (right + left) / 2); // Tri-Median method! if (spriteY[sortOrder[left]] > spriteY[sortOrder[i]]) { // swap temp = sortOrder[left]; sortOrder[left] = sortOrder[i]; sortOrder[i] = temp; } if (spriteY[sortOrder[left]] > spriteY[sortOrder[right]]) { // swap temp = sortOrder[left]; sortOrder[left] = sortOrder[right]; sortOrder[right] = temp; } if (spriteY[sortOrder[i]] > spriteY[sortOrder[right]]) { // swap temp = sortOrder[i]; sortOrder[i] = sortOrder[right]; sortOrder[right] = temp; } j = (right - 1); // swap temp = sortOrder[i]; sortOrder[i] = sortOrder[j]; sortOrder[j] = temp; i = left; value = spriteY[sortOrder[j]]; while (true) { // fast forward while (spriteY[sortOrder[++i]] < value) { ; } // fast reverse while (spriteY[sortOrder[--j]] > value) { ; } // stop condition if (j < i) { break; } // swap temp = sortOrder[i]; sortOrder[i] = sortOrder[j]; sortOrder[j] = temp; } // swap temp = sortOrder[i]; sortOrder[i] = sortOrder[right - 1]; sortOrder[right - 1] = temp; quickSort (left, j); quickSort (i + 1, right); } } private void insertionSort (int low, int hi) { for (int i = low + 1; i <= hi; i++) { int temp = sortOrder[i]; int j = i; while ( (j > low) && (spriteY[sortOrder[j - 1]] > spriteY[temp])) { sortOrder[j] = sortOrder[j - 1]; j--; } sortOrder[j] = temp; } } // Sort sprites... public void sort () { quickSort (0, (consts.MAXSPRITES - 1)); insertionSort (0, (consts.MAXSPRITES - 1)); } public int getNextSprite () { return sortOrder[sortIndex++]; } } // The cluster sort implementation class clusterSort implements sortInterface { // Marks special items in lists, tables, etc static final int MARKER = 255; int[] spriteY = new int[consts.MAXSPRITES]; int[] Min = new int[consts.MAXSPRITES]; int[] Next = new int[consts.MAXSPRITES + 1]; int[] Count = new int[consts.MAXSPRITES]; int[][] Cluster = new int[consts.MAXSPRITES][4]; int first; int clusterCount; int sortIndex; int sortItem; // Constructor public clusterSort () { } // Return name public String name () { return "Cluster sort"; } // Initialize a new sorting iteration public void sortInit () { } // Add a sprite enty private void add (int index) { // Now we need to find the proper position in the linked list if (spriteY[index] < spriteY[Min[first]]) { Cluster[clusterCount][0] = index; Min[clusterCount] = index; Count[clusterCount] = 1; Next[clusterCount] = first; first = clusterCount++; return; } int i = first; if (clusterCount > 1) { while (spriteY[Min[Next[i]]] < spriteY[index]) { i = Next[i]; if (Next[i] == MARKER) { break; } } } // We have found an in-between value at this point // Now check if the Cluster is full... and if so, split up in two groups if (Count[i] == 4) { Cluster[clusterCount][0] = Cluster[i][2]; Cluster[clusterCount][1] = Cluster[i][3]; Min[clusterCount] = Cluster[clusterCount][0]; Count[clusterCount] = 2; Next[clusterCount] = Next[i]; Count[i] = 2; Next[i] = clusterCount; if (spriteY[index] > spriteY[Min[clusterCount]]) { i = clusterCount; } clusterCount++; } // Add new entry to the Cluster, keeping all items sorted as the Cluster isn't full yet switch (Count[i]) { case 1: { Cluster[i][1] = index; break; } case 2: { if (spriteY[index] < spriteY[Cluster[i][1]]) { Cluster[i][2] = Cluster[i][1]; Cluster[i][1] = index; } else { Cluster[i][2] = index; } break; } case 3: { if (spriteY[index] < spriteY[Cluster[i][1]]) { Cluster[i][3] = Cluster[i][2]; Cluster[i][2] = Cluster[i][1]; Cluster[i][1] = index; } else if (spriteY[index] < spriteY[Cluster[i][2]]) { Cluster[i][3] = Cluster[i][2]; Cluster[i][2] = index; } else { Cluster[i][3] = index; } break; } } Count[i]++; } // Add a sprite to the sorting object public void addSprite (int index, int y) { spriteY[index] = y; } // Sort sprites... public void sort () { // set up the first Cluster(s) Cluster[0][0] = 0; Min[0] = 0; Count[0] = 1; Next[0] = MARKER; clusterCount = 1; first = 0; for (int i = 1; i < consts.MAXSPRITES; i++) { add (i); } sortIndex = first; // Reset indices for first call to getNextSprite() sortItem = 0; } // Get the next sprite... public int getNextSprite () { // This is the next sprite int index = Cluster[sortIndex][sortItem]; // Update indices for next call to getNextSprite() if (--Count[sortIndex] > 0) { sortItem++; } else { sortIndex = Next[sortIndex]; sortItem = 0; } return index; } } // The insertion bucket sort implementation class insertionBucketSort implements sortInterface { static final int BUCKETS = 64; // Number of available buckets static final int HASH = (int) Math.ceil ( (double) consts.MAXVALUE / (double) BUCKETS); int[] spriteY = new int[consts.MAXSPRITES]; int[][] Bucket = new int[BUCKETS][consts.MAXSPRITES]; int[] Count = new int[BUCKETS]; int sortIndex; int sortItem; // Constructor public insertionBucketSort () { } // Return name public String name () { return "Insertion Bucket sort"; } // Initialize a new sorting iteration public void sortInit () { sortIndex = 0; // Reset indices for first call to getNextSprite() sortItem = 0; } // Add a sprite to the sorting object public void addSprite (int index, int y) { spriteY[index] = y; int Hash = (y / HASH); // Using integer division here... Bucket[Hash][Count[Hash]++] = index; } // Sort sprites... public void sort () { // Run a simple insertion sort per bucket for (int b = 0; b < BUCKETS; b++) { int Elem = (Count[b] - 1); for (int i = 0; i < Elem; i++) { if (spriteY[Bucket[b][i]] > spriteY[Bucket[b][i + 1]]) { int j = i; while (true) { int swap = Bucket[b][j]; Bucket[b][j] = Bucket[b][j + 1]; Bucket[b][j + 1] = swap; if (j == 0) { break; } j--; if (spriteY[Bucket[b][j]] < spriteY[Bucket[b][j + 1]]) { break; } } } } } } // Get the next sprite... public int getNextSprite () { // fast forward to next filled bucket while (Count[sortIndex] == 0) { sortIndex++; } // This is the next sprite int index = Bucket[sortIndex][sortItem]; // Update indices for next call to getNextSprite() if (--Count[sortIndex] > 0) { sortItem++; } else { sortIndex++; sortItem = 0; } return index; } } // Internal representation of a sprite class spriteObject { int y; int gamePatternIndex; // This attribute is only used for the game pattern test... public spriteObject () { } } // Class that manages sprites class spriteManager { spriteObject[] Sprite = new spriteObject[consts.MAXSPRITES]; int[] gamePatternY = { 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 15, 17, 19, 22, 24, 26, 29, 31, 34, 37, 40, 43, 46, 49, 52, 55, 59, 62, 66, 69, 73, 76, 80, 84, 88, 91, 95, 99, 103, 107, 111, 115, 119, 123, 127, 131, 135, 139, 143, 147, 151, 155, 159, 163, 166, 170, 174, 178, 181, 185, 188, 192, 195, 199, 202, 205, 208, 211, 214, 217, 220, 223, 225, 228, 230, 232, 235, 237, 239, 241, 242, 244, 246, 247, 248, 249, 250, 251, 252, 253, 253, 254, 254, 254, 254, 254, 254, 253, 253, 252, 251, 250, 249, 248, 247, 246, 244, 242, 241, 239, 237, 235, 232, 230, 228, 225, 223, 220, 217, 214, 211, 208, 205, 202, 199, 195, 192, 188, 185, 181, 178, 174, 170, 166, 163, 159, 155, 151, 147, 143, 139, 135, 131, 127, 123, 119, 115, 111, 107, 103, 99, 95, 91, 88, 84, 80, 76, 73, 69, 66, 62, 59, 55, 52, 49, 46, 43, 40, 37, 34, 31, 29, 26, 24, 22, 19, 17, 15, 13, 12, 10, 8, 7, 6, 5, 4, 3, 2, 1, 1, 0, 0, 0, 0}; public spriteManager () { for (int i = 0; i < consts.MAXSPRITES; i++) { Sprite[i] = new spriteObject (); } } public void setRandomY () { for (int i = 0; i < consts.MAXSPRITES; i++) { Sprite[i].y = (int) (Math.random () * consts.MAXVALUE); } } public void setIncreasingY () { for (int i = 0; i < consts.MAXSPRITES; i++) { Sprite[i].y = (i * (int) Math.ceil ( (double) consts.MAXVALUE / (double) consts.MAXSPRITES)); } } public void setDecreasingY () { for (int i = 0; i < consts.MAXSPRITES; i++) { Sprite[i].y = (consts.MAXVALUE - (i * (int) Math.ceil ( (double) consts.MAXVALUE / (double) consts.MAXSPRITES))); } } public void initGamePatternY () { for (int i = 0; i < consts.MAXSPRITES; i++) { Sprite[i].gamePatternIndex = (int) (Math.random () * gamePatternY.length); } } public void setGamePatternY () { for (int i = 0; i < consts.MAXSPRITES; i++) { Sprite[i].y = (gamePatternY[Sprite[i].gamePatternIndex] * (consts.MAXVALUE / 254)); Sprite[i].gamePatternIndex = ( (Sprite[i].gamePatternIndex + 1) % gamePatternY.length); } } } // Class that runs sorting tests for given a specific sorting object public class spriteSortTest { // Indicates number of test runs static final int MAXTESTITERATIONS = 100000; spriteManager sManager = new spriteManager (); sortInterface sort; // constructor public spriteSortTest (sortInterface sort) { this.sort = sort; } // move sprites to the given sorting object public void insertSpritesInSort () { for (int i = 0; i < consts.MAXSPRITES; i++) { sort.addSprite (i, sManager.Sprite[i].y); } } // drain sprites from the given sorting object public void drainSpritesFromSort () { for (int i = 0; i < consts.MAXSPRITES; i++) { int sprite = sort.getNextSprite (); } } // basic test to see if the given sorting object works OK public void functionalTest () { // Do test runs to determine if the sorting object runs correctly for (int t = 0; t < 1000; t++) { sManager.setRandomY (); sort.sortInit (); insertSpritesInSort (); sort.sort (); ArrayList originalList = new ArrayList (); ArrayList sortedList = new ArrayList (); for (int i = 0; i < consts.MAXSPRITES; i++) { originalList.add (new Integer (sManager.Sprite[i].y)); } int minY = 0; int curY; for (int i = 0; i < consts.MAXSPRITES; i++) { curY = sManager.Sprite[sort.getNextSprite ()].y; sortedList.add (new Integer (curY)); if (curY >= minY) { minY = curY; } else { throw new RuntimeException ("Sort order malfunction"); } } if (!sortedList.containsAll (originalList)) { throw new RuntimeException ("Sort did not return all added elements"); } } } // speed test for a given sort object using completely random sprite Y values public void randomYSort () { for (int t = 0; t < MAXTESTITERATIONS; t++) { sManager.setRandomY (); sort.sortInit (); insertSpritesInSort (); sort.sort (); drainSpritesFromSort (); } } // speed test for a given sort object using extremes of Sprite Y values public void extremesOfYSort () { for (int t = 0; t < (MAXTESTITERATIONS / 2); t++) { // Prevent 'memory' advantages by alternating between // increasing and decreasing sprite Y values... sManager.setIncreasingY (); sort.sortInit (); insertSpritesInSort (); sort.sort (); drainSpritesFromSort (); sManager.setDecreasingY (); sort.sortInit (); insertSpritesInSort (); sort.sort (); drainSpritesFromSort (); } } // speed test for a given sort object using typical 'game pattern' Y values public void gamePatternYSort () { final int MAXREINIT = 1000; for (int i = 0; i < MAXREINIT; i++) { sManager.initGamePatternY (); for (int t = 0; t < (MAXTESTITERATIONS / MAXREINIT); t++) { sManager.setGamePatternY (); sort.sortInit (); insertSpritesInSort (); sort.sort (); drainSpritesFromSort (); } } } // run all the tests for a given sort object public void run () { System.out.println ("Sorting " + consts.MAXSPRITES + " sprites in " + MAXTESTITERATIONS + " test runs for the << " + sort.name () + " >> sorting method"); System.out.println ("Running the functional test"); functionalTest (); System.out.println ("Functional test completed succesfully"); System.out.println ("Completely random Y"); long start = System.currentTimeMillis (); randomYSort (); long stop = System.currentTimeMillis (); System.out.println ("Elapsed: " + (stop - start)); System.out.println ("Extremes of Y"); start = System.currentTimeMillis (); extremesOfYSort (); stop = System.currentTimeMillis (); System.out.println ("Elapsed: " + (stop - start)); System.out.println ("Gaming pattern Y"); start = System.currentTimeMillis (); gamePatternYSort (); stop = System.currentTimeMillis (); System.out.println ("Elapsed: " + (stop - start)); } // main entry point public static void main (String[] args) throws Exception { spriteSortTest test1 = new spriteSortTest (new bucketSort ()); test1.run(); spriteSortTest test2 = new spriteSortTest (new oceanSort ()); test2.run(); spriteSortTest test3 = new spriteSortTest (new oceanBucketSort ()); test3.run(); spriteSortTest test4 = new spriteSortTest (new oceanMergeSort ()); test4.run(); spriteSortTest test5 = new spriteSortTest (new oceanFastQuickSort ()); test5.run(); spriteSortTest test6 = new spriteSortTest (new clusterSort ()); test6.run (); spriteSortTest test7 = new spriteSortTest (new insertionBucketSort ()); test7.run (); } }