diff --git a/.classpath b/.classpath index a948582b..7b88b967 100644 --- a/.classpath +++ b/.classpath @@ -1,13 +1,7 @@ - - - - - - - + diff --git a/.gitignore b/.gitignore index 5241a722..cee99345 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -*.class \ No newline at end of file +*.class +/bin/ \ No newline at end of file diff --git a/LICENSE b/LICENSE index c8c17f8b..3926e52f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ MIT License Copyright (c) 2019 w0rthy -Copyright (c) 2019 MusicTheorist +Copyright (c) 2020 MusicTheorist Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index e596d4ba..e06f4f94 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,21 @@ # w0rthy's Array Visualizer, Revamped [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=Q5QLCFZ8G7WY6¤cy_code=USD&source=url) -76 sorting algorithms demonstrated through 10 unique graphic designs +**DEPRECATED** - Visit the new home of ArrayV over here where I'll be contributing from time to time! https://github.com/Gaming32/ArrayV-v4.0 +I'll be working on a brand new algorithm visualizer of my own over the next few months, so stay tuned... Visit our community Discord for updates!! + +Over 75 sorting algorithms animated with 12 unique graphic designs + +Follow the project's development behind-the-scenes in our Discord: https://discord.com/invite/2xGkKC2 This new version of the program features additions inspired by Timo Bingmann's "The Sound of Sorting" and w0rthy's updates to the original visualizer. -To build (After -cp, use ";" with Windows and ":" with Mac/Linux): +To compile (After -cp, use ";" with Windows and ":" with Mac/Linux): ``` ant java -cp bin;lib/classgraph-4.8.47.jar main.ArrayVisualizer ``` +To build a runnable jar, simply run Apache Ant inside the 'dist' directory! ### Features: - 40+ new sorting algorithms @@ -23,6 +29,65 @@ java -cp bin;lib/classgraph-4.8.47.jar main.ArrayVisualizer - Toggle Timo Bingmann's "end sweep" animation - Refactored / optimized code +## 6/8/2020 - Version 3.5 +- NEW VISUALS: Sine Wave and Wave Dots!! +- New sort: Bogobogosort +- The bogo shuffle method is now unbiased +- MultipleSortThreads further refactored +- Visuals, VisualStyles enum, and Renderer significantly refactored (more to come!) + +## 6/4/2020 - Version 3.2 +- New sort: Optimized Cocktail Shaker Sort +- Significant refactoring for MultipleSortThreads and RunAllSorts +- "Run All" button approx. time simplified +- Modified delays for Binary Gnomesort +- Documentation of GCC's median-of-three pivot selection in Introsort + +## 6/3/2020 - Version 3.12 +- Counting Sort fixed +- Optimized Bubblesort now optimized for already sorted inputs +- Speeds for Quicksorts and Weave Merge during "Run All Sorts" improved + +## 6/2/2020 - Version 3.11 +- Minor update to MIT license +- Fixed typo in Flipped Min Heapsort +- Improved highlights on Heapsorts (Already sorted heaps now display redundant comparisons) +- Bug fix for Patiencesort on reversed arrays +- Quicksorts exhibiting worst-case behavior during "Run All Sorts" run much faster +- Same tweak as above to Weave Merge Sort + +## 5/30/2020 - Version 3.1 +- Error messages with detailed information will now appear within the program! +- Sound effects are now consistent on all platforms +- New sort: "Flipped Min Heap Sort" by 'landfillbaby'! +- Minor changes to code organization +- New webhook to my Discord server! Check it out here: https://discord.com/invite/2xGkKC2 + +## 5/22/2020 - Version 3.01 +- Quick bug fix to the "Linked Dots" visual; + The first line is no longer horizontal. + +## 5/21/2020 - Version 3.0 is now released! +- Sound effects are much more pleasant at slower speeds +- Revamped "Run All Sorts" (It is now easier to create your own sequence of sorts!) +- More accurate delay algorithm +- Improved random shuffle algorithm (now with 0% bias!) +- Cleaner statistics +- Sort an array up to 16,384 (2^14) numbers! +- The "green sweep" animation also verifies an array is properly sorted after watching a sort. + If a sort fails, a warning message pops up, highlighting where the first out-of-order item is. +- Minor tweak to the sort time method. It should be a slight bit more accurate now. +- Slowsort and Sillysort's comparisons are now shown. +- Gravity Sort has a more detailed visual now +- Pancake Sorting is fixed +- Counting Sort is fixed +- Holy Grail Sort is enabled, but just note that it's a mock algorithm; not finished yet. +- "Auxillary" typo fixed; program now says 'Writes to Auxiliary Array(s)' +- Bug fixes and minor tweaks + - Minor fixes to "Skip Sort" button + - Weird static line bug with linked dots squashed + - Other miscellaneous fixes and changes here and there + ## 10/19/2019 - Version 2.1 - Both Odd-Even Mergesorts now display comparisons - PDQSort's Insertion Sorts have been slowed down @@ -74,7 +139,6 @@ java -cp bin;lib/classgraph-4.8.47.jar main.ArrayVisualizer **KNOWN BUGS:** - Certain sorts (comb sort, radix sorts) cause the program to forget the current speed - Certain sorts do not work with the "Skip Sort" button -- Linked Dots visual has an extra, static line - Missing soundfont - SkaSort and HolyGrailSort produce errors -- this is normal, they aren't finished yet - No circular pointer -- will be fixed soon @@ -96,14 +160,12 @@ java -cp bin;lib/classgraph-4.8.47.jar main.ArrayVisualizer - Organize list of sorts into more categories - Run All Sorts in specific category - Subheadings for customizable sorts (e.g. display the number of buckets during a bucket sort) -- Justified statistics(??) -- Sort an array up to 16,384 (2^14) numbers - "Many Similar" distribution ((i/5) * 5, as an example) +- "Pipe organ" distribution (half ascending, half descending) - Fixed circular pointer with much cleaner math - Toogle between pointer and black bar with circular visuals - Refactor/reorganize prompts and frames - Cleaner: - - Counting Sort - Tree Sort - getters/setters - method parameters diff --git a/bin/SortPrompt.form b/bin/SortPrompt.form deleted file mode 100644 index 08d82518..00000000 --- a/bin/SortPrompt.form +++ /dev/null @@ -1,138 +0,0 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/bin/UtilFrame.form b/bin/UtilFrame.form deleted file mode 100644 index 13edae8e..00000000 --- a/bin/UtilFrame.form +++ /dev/null @@ -1,123 +0,0 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/bin/ViewPrompt.form b/bin/ViewPrompt.form deleted file mode 100644 index 9860af11..00000000 --- a/bin/ViewPrompt.form +++ /dev/null @@ -1,169 +0,0 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/build.xml b/build.xml index aafdcb33..9b54fdea 100644 --- a/build.xml +++ b/build.xml @@ -10,39 +10,29 @@ - - - - + - - - + - - - + - - - + - @@ -57,6 +47,7 @@ + diff --git a/dist/arrayVisualizer.jar b/dist/arrayVisualizer.jar index 18954343..a22f4497 100644 Binary files a/dist/arrayVisualizer.jar and b/dist/arrayVisualizer.jar differ diff --git a/dist/build.xml b/dist/build.xml new file mode 100644 index 00000000..7ee04433 --- /dev/null +++ b/dist/build.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dist/jar-in-jar-loader.zip b/dist/jar-in-jar-loader.zip new file mode 100644 index 00000000..7e5a3ab3 Binary files /dev/null and b/dist/jar-in-jar-loader.zip differ diff --git a/lib/classgraph-4.8.47-javadoc.jar b/lib/classgraph-4.8.47-javadoc.jar deleted file mode 100644 index 62aed633..00000000 Binary files a/lib/classgraph-4.8.47-javadoc.jar and /dev/null differ diff --git a/lib/classgraph-4.8.47-sources.jar b/lib/classgraph-4.8.47-sources.jar deleted file mode 100644 index 0542dbc8..00000000 Binary files a/lib/classgraph-4.8.47-sources.jar and /dev/null differ diff --git a/src/frames/ArrayFrame.java b/src/frames/ArrayFrame.java index aa2c99c3..2ed88a0c 100644 --- a/src/frames/ArrayFrame.java +++ b/src/frames/ArrayFrame.java @@ -90,7 +90,7 @@ public void reposition(){ private void initComponents() { this.jLabel1 = new javax.swing.JLabel(); - this.jSlider = new javax.swing.JSlider(SwingConstants.VERTICAL, 1, 12, 11); + this.jSlider = new javax.swing.JSlider(SwingConstants.VERTICAL, 1, 14, 11); jLabel1.setText("Array Size"); @@ -109,6 +109,8 @@ private void initComponents() { labels.put(10, new JLabel("1024")); labels.put(11, new JLabel("2048")); labels.put(12, new JLabel("4096")); + labels.put(13, new JLabel("8192")); + labels.put(14, new JLabel("16384")); jSlider.setMajorTickSpacing(1); jSlider.setLabelTable(labels); @@ -120,6 +122,7 @@ private void initComponents() { public void stateChanged(ChangeEvent event) { if(ArrayManager.isLengthMutable()) { ArrayVisualizer.setCurrentLength((int) Math.pow(2, jSlider.getValue())); + //ArrayVisualizer.setEqualItems((int) Math.pow(2, jSlider.getValue())); ArrayManager.initializeArray(array); } else jSlider.setValue(ArrayVisualizer.getLogBaseTwoOfLength()); diff --git a/src/frames/UtilFrame.java b/src/frames/UtilFrame.java index e58297c1..bd62ec7c 100644 --- a/src/frames/UtilFrame.java +++ b/src/frames/UtilFrame.java @@ -382,11 +382,26 @@ else if(!this.abstractFrame.isVisible()) { } if(speedPromptAllowed) { - try{ - Delays.setSleepRatio(Double.parseDouble(JOptionPane.showInputDialog(null, "Modify the visual's speed below (Ex. 10 = Ten times faster)", Delays.getSleepRatio()))); - } - catch(Exception e) { //TODO: Disable exception on Dialog cancel - System.out.println("Not a number! (" + e.getMessage() + ")"); + boolean showPrompt = true; + while(showPrompt) { + try { + double oldRatio = Delays.getSleepRatio(); + String userInput = JOptionPane.showInputDialog(null, "Modify the visual's speed below (Ex. 10 = Ten times faster)", oldRatio); + if(userInput == null) { + showPrompt = false; + } + else { + double newRatio = Double.parseDouble(userInput); + if(newRatio == 0) throw new Exception("Divide by zero"); + Delays.setSleepRatio(newRatio); + Delays.updateCurrentDelay(oldRatio, Delays.getSleepRatio()); + showPrompt = false; + } + } + catch(Exception e) { + showPrompt = true; + JOptionPane.showMessageDialog(null, "Not a number! (" + e.getMessage() + ")", "Error", JOptionPane.ERROR_MESSAGE); + } } } }//GEN-LAST:event_jButton3ActionPerformed @@ -404,7 +419,6 @@ private void jCheckBox3ActionPerformed() {//GEN-FIRST:event_jCheckBox3ActionPerf }//GEN-LAST:event_jCheckBox3ActionPerformed private void jButton4ActionPerformed() {//GEN-FIRST:event_jButton4ActionPerformed - Delays.setSleepRatio(Double.MAX_VALUE); Delays.changeSkipped(true); }//GEN-LAST:event_jButton4ActionPerformed @@ -418,10 +432,10 @@ private void jButton5ActionPerformed() {//GEN-FIRST:event_jButton4ActionPerforme private void jCheckBox5ActionPerformed() {//GEN-FIRST:event_jButton4ActionPerformed if(jCheckBox5.isSelected()) { - Sounds.changeVolume(0.01); + Sounds.toggleSofterSounds(true); } else { - Sounds.changeVolume(1); + Sounds.toggleSofterSounds(false); } }//GEN-LAST:event_jCheckBox5ActionPerformed diff --git a/src/main/ArrayManager.java b/src/main/ArrayManager.java index a194cddc..dd66e1bb 100644 --- a/src/main/ArrayManager.java +++ b/src/main/ArrayManager.java @@ -1,5 +1,8 @@ package main; +import javax.swing.JOptionPane; + +import templates.JErrorPane; import utils.Delays; import utils.Highlights; import utils.Shuffles; @@ -65,9 +68,11 @@ public void toggleMutableLength(boolean Bool) { this.MUTABLE = Bool; } + //TODO: Fix minimum to zero public void initializeArray(int[] array) { + int equalFactor = ArrayVisualizer.getEqualItems(); for (int i = 0; i < array.length; i++) { - array[i] = i; + array[i] = (i / equalFactor) * equalFactor; } } @@ -106,6 +111,8 @@ public void shuffleArray(int[] array, int currentLen, ArrayVisualizer ArrayVisua double sleepRatio; switch(ArrayVisualizer.getLogBaseTwoOfLength()) { + case 14: sleepRatio = 16d; break; + case 13: sleepRatio = 8d; break; case 12: sleepRatio = 4d; break; case 11: sleepRatio = 2d; break; case 10: sleepRatio = 3/2d; break; @@ -135,7 +142,7 @@ public void refreshArray(int[] array, int currentLen, ArrayVisualizer ArrayVisua try { Thread.sleep(1000); } catch (InterruptedException e) { - e.printStackTrace(); + JErrorPane.invokeErrorMessage(e); } ArrayVisualizer.resetAllStatistics(); @@ -149,7 +156,7 @@ public void refreshArray(int[] array, int currentLen, ArrayVisualizer ArrayVisua try { Thread.sleep(500); } catch (InterruptedException e) { - e.printStackTrace(); + JErrorPane.invokeErrorMessage(e); } ArrayVisualizer.resetAllStatistics(); diff --git a/src/main/ArrayVisualizer.java b/src/main/ArrayVisualizer.java index 408de023..1f0f745a 100644 --- a/src/main/ArrayVisualizer.java +++ b/src/main/ArrayVisualizer.java @@ -20,13 +20,19 @@ import frames.ArrayFrame; import frames.UtilFrame; +import templates.Visual; import utils.Delays; -import utils.Renderer; import utils.Highlights; import utils.Reads; +import utils.Renderer; import utils.Sounds; import utils.Timer; import utils.Writes; +import visuals.Bars; +import visuals.Circular; +import visuals.Hoops; +import visuals.Mesh; +import visuals.Pixels; import visuals.VisualStyles; /* TO-DO LIST: @@ -35,16 +41,15 @@ * - CLEAN UP GETTERS AND SETTERS * - CLEAN UP METHOD PARAMETERS * - SHOW/HIDE BASIC SORTS, ADVANCED SORTS, AND OBSCURE SORTS + * - GIVE COMPARE METHODS DELAY AND MARK ARGUMENTS * - Implement: * - - Entering in your own set of data - * - - Justified statistics? - * - - Up to 2^14 numbers. + * - - Pass ArrayVisualizer as "observer object" to sorts + * - - Pass formatter/symbols from ArrayVisualizer into utils * - Fix: * - - Circular pointer * - - Combsort / Radix Sorts not complying with "Skip Sort" * - - "Skip Sort" / changing array size saving previous speed - * - - Counting Sort - * - - "0th" Linked Dot * - - .dls file in soundfont dir * - - 1080p in OBS(?) * - Create: @@ -54,6 +59,7 @@ * - - options to choose timsort minrun * - - subheadings for sort customizations (e.g. number of buckets for all bucket sorts) * - - toggle between pointer and black bar + * - - SINE WAVE VISUAL!!! * - Make: * - - "Many Similar" distribution ((i / 5) * 5, as an example) * - - Better names/clean up code in frames/prompts @@ -66,11 +72,10 @@ * - - run all sorts in specific category * - - option for custom parts for intro sorts * - - option for simple shatter rate??? - * - - Timo Bingmann's green sweep also *verify* a sorted array * - Finish: * - - SkaSort * - - HolyGrailSort - * - - Run All/Run All Sorts in Category + * - - Run All Sorts in Category * - Cleanup: * - - Treesort */ @@ -133,15 +138,16 @@ final public class ArrayVisualizer { final boolean OBS = false; // Change to true if you want 1080p for recording with OBS final private int MIN_ARRAY_VAL = 2; - final private int MAX_ARRAY_VAL = 4096; + final private int MAX_ARRAY_VAL = 16384; final int[] array = new int[this.MAX_ARRAY_VAL]; - private String[][] ComparisonSorts; //First row of Comparison/DistributionSorts arrays consists of class names - private String[][] DistributionSorts; //Second row consists of user-friendly names + private String[][] ComparisonSorts; // First row of Comparison/DistributionSorts arrays consists of class names + private String[][] DistributionSorts; // Second row consists of user-friendly names private String[] InvalidSorts; private volatile int currentLen; + private volatile int equalItems; private ArrayManager ArrayManager; private SortAnalyzer SortAnalyzer; @@ -149,6 +155,8 @@ final public class ArrayVisualizer { private UtilFrame UtilFrame; private ArrayFrame ArrayFrame; + private Visual[] visualClasses; + private Thread sortingThread; private Thread visualsThread; @@ -173,6 +181,7 @@ final public class ArrayVisualizer { private volatile boolean PIXELDRAW; private volatile boolean RAINBOW; private volatile boolean SPIRALDRAW; + private volatile boolean WAVEDRAW; private volatile int cx; private volatile int cy; @@ -195,10 +204,11 @@ final public class ArrayVisualizer { public ArrayVisualizer() { this.currentLen = 2048; + this.equalItems = 1; - this.Delays = new Delays(); - this.Highlights = new Highlights(this.MAX_ARRAY_VAL); + this.Highlights = new Highlights(this, this.MAX_ARRAY_VAL); this.Sounds = new Sounds(this.array, this); + this.Delays = new Delays(this); this.Timer = new Timer(); this.Reads = new Reads(this); this.Renderer = new Renderer(this); @@ -207,23 +217,23 @@ public ArrayVisualizer() { this.ArrayManager = new ArrayManager(this); this.SortAnalyzer = new SortAnalyzer(this); - SortAnalyzer.analyzeSorts(); - this.ComparisonSorts = SortAnalyzer.getComparisonSorts(); - this.DistributionSorts = SortAnalyzer.getDistributionSorts(); - this.InvalidSorts = SortAnalyzer.getInvalidSorts(); + this.SortAnalyzer.analyzeSorts(); + this.ComparisonSorts = this.SortAnalyzer.getComparisonSorts(); + this.DistributionSorts = this.SortAnalyzer.getDistributionSorts(); + this.InvalidSorts = this.SortAnalyzer.getInvalidSorts(); this.category = ""; this.heading = ""; this.typeFace = new Font("Times New Roman", Font.PLAIN, (int) (640 / (1280.0 * 25))); this.formatter = (DecimalFormat) NumberFormat.getInstance(Locale.US); - this.symbols = formatter.getDecimalFormatSymbols(); + this.symbols = this.formatter.getDecimalFormatSymbols(); this.formatter.setRoundingMode(RoundingMode.HALF_UP); this.UtilFrame = new UtilFrame(this.array, this); this.ArrayFrame = new ArrayFrame(this.array, this); - UtilFrame.reposition(this.ArrayFrame); + this.UtilFrame.reposition(this.ArrayFrame); this.SHUFFLEANIM = true; this.ANALYZE = false; @@ -242,41 +252,61 @@ public ArrayVisualizer() { this.ch = 0; this.cw = 0; - ArrayManager.initializeArray(this.array); + this.ArrayManager.initializeArray(this.array); + + //TODO: Overhaul visual code to properly reflect Swing (JavaFX?) style and conventions //DRAW THREAD this.visualsThread = new Thread() { @Override public void run() { - Renderer.initializeVisuals(ArrayVisualizer.this, ArrayVisualizer.this.VisualStyles); + utils.Renderer.initializeVisuals(ArrayVisualizer.this); + + Graphics background = ArrayVisualizer.this.window.getGraphics(); + background.setColor(Color.BLACK); + + ArrayVisualizer.this.visualClasses = new Visual[5]; + ArrayVisualizer.this.visualClasses[0] = new Bars(ArrayVisualizer.this); + ArrayVisualizer.this.visualClasses[1] = new Circular(ArrayVisualizer.this); + ArrayVisualizer.this.visualClasses[2] = new Hoops(ArrayVisualizer.this); + ArrayVisualizer.this.visualClasses[3] = new Mesh(ArrayVisualizer.this); + ArrayVisualizer.this.visualClasses[4] = new Pixels(ArrayVisualizer.this); while(true) { - Renderer.updateVisuals(ArrayVisualizer.this); - Renderer.drawVisual(ArrayVisualizer.this.VisualStyles, array, ArrayVisualizer.this, mainRender, extraRender, Highlights); - - int coltmp = 255; - mainRender.setColor(new Color(coltmp,coltmp,coltmp)); - if(TEXTDRAW) { - Font f = mainRender.getFont(); - mainRender.setFont(typeFace); - mainRender.drawString(category + ": " + heading, 15, (int)(cw/1280.0*40)+30); - mainRender.drawString(formatter.format(currentLen) + " Numbers", 15, (int)(cw/1280.0*65)+30); - mainRender.drawString(String.format("Delay: " + formatter.format(Delays.getCurrentDelay()) + "ms"), 15, (int)(cw/1280.0*105)+30); - mainRender.drawString(String.format("Visual Time: " + Timer.getVisualTime()), 15, (int)(cw/1280.0*130)+30); - mainRender.drawString(String.format("Estimated Real Time: " + Timer.getRealTime()), 15, (int)(cw/1280.0*155)+30); - mainRender.drawString(Reads.getComparisons(), 15, (int)(cw/1280.0*195)+30); - mainRender.drawString(Writes.getSwaps(), 15, (int)(cw/1280.0*220)+30); - mainRender.drawString(Writes.getReversals(), 15, (int)(cw/1280.0*245)+30); - mainRender.drawString(Writes.getWrites(), 15, (int)(cw/1280.0*270)+30); - mainRender.drawString(Writes.getTempWrites(), 15, (int)(cw/1280.0*295)+30); - mainRender.setFont(f); + ArrayVisualizer.this.Renderer.updateVisuals(ArrayVisualizer.this); + ArrayVisualizer.this.Renderer.drawVisual(ArrayVisualizer.this.VisualStyles, ArrayVisualizer.this.array, ArrayVisualizer.this, ArrayVisualizer.this.Highlights); + + if(ArrayVisualizer.this.TEXTDRAW) { + Font f = ArrayVisualizer.this.mainRender.getFont(); + ArrayVisualizer.this.mainRender.setFont(ArrayVisualizer.this.typeFace); + ArrayVisualizer.this.mainRender.setColor(Color.BLACK); + ArrayVisualizer.this.mainRender.drawString(ArrayVisualizer.this.category + ": " + ArrayVisualizer.this.heading, 17, (int)(ArrayVisualizer.this.cw/1280.0*30)+32); + ArrayVisualizer.this.mainRender.drawString(ArrayVisualizer.this.formatter.format(ArrayVisualizer.this.currentLen) + " Numbers", 17, (int)(ArrayVisualizer.this.cw/1280.0*55)+32); + ArrayVisualizer.this.mainRender.drawString(String.format("Delay: " + ArrayVisualizer.this.Delays.displayCurrentDelay() + "ms"), 17, (int)(ArrayVisualizer.this.cw/1280.0*95)+32); + ArrayVisualizer.this.mainRender.drawString(String.format("Visual Time: " + ArrayVisualizer.this.Timer.getVisualTime()), 17, (int)(ArrayVisualizer.this.cw/1280.0*120)+32); + ArrayVisualizer.this.mainRender.drawString(String.format("Sort Time: " + ArrayVisualizer.this.Timer.getRealTime()), 17, (int)(ArrayVisualizer.this.cw/1280.0*145)+32); + ArrayVisualizer.this.mainRender.drawString(ArrayVisualizer.this.Reads.displayComparisons(), 17, (int)(ArrayVisualizer.this.cw/1280.0*185)+32); + ArrayVisualizer.this.mainRender.drawString(ArrayVisualizer.this.Writes.getSwaps(), 17, (int)(ArrayVisualizer.this.cw/1280.0*210)+32); + ArrayVisualizer.this.mainRender.drawString(ArrayVisualizer.this.Writes.getReversals(), 17, (int)(ArrayVisualizer.this.cw/1280.0*235)+32); + ArrayVisualizer.this.mainRender.drawString(ArrayVisualizer.this.Writes.getWrites(), 17, (int)(ArrayVisualizer.this.cw/1280.0*275)+32); + ArrayVisualizer.this.mainRender.drawString(ArrayVisualizer.this.Writes.getTempWrites(), 17, (int)(ArrayVisualizer.this.cw/1280.0*300)+32); + ArrayVisualizer.this.mainRender.setColor(Color.WHITE); + ArrayVisualizer.this.mainRender.drawString(ArrayVisualizer.this.category + ": " + ArrayVisualizer.this.heading, 15, (int)(ArrayVisualizer.this.cw/1280.0*30)+30); + ArrayVisualizer.this.mainRender.drawString(ArrayVisualizer.this.formatter.format(ArrayVisualizer.this.currentLen) + " Numbers", 15, (int)(ArrayVisualizer.this.cw/1280.0*55)+30); + ArrayVisualizer.this.mainRender.drawString(String.format("Delay: " + ArrayVisualizer.this.Delays.displayCurrentDelay() + "ms"), 15, (int)(ArrayVisualizer.this.cw/1280.0*95)+30); + ArrayVisualizer.this.mainRender.drawString(String.format("Visual Time: " + ArrayVisualizer.this.Timer.getVisualTime()), 15, (int)(ArrayVisualizer.this.cw/1280.0*120)+30); + ArrayVisualizer.this.mainRender.drawString(String.format("Sort Time: " + ArrayVisualizer.this.Timer.getRealTime()), 15, (int)(ArrayVisualizer.this.cw/1280.0*145)+30); + ArrayVisualizer.this.mainRender.drawString(ArrayVisualizer.this.Reads.displayComparisons(), 15, (int)(ArrayVisualizer.this.cw/1280.0*185)+30); + ArrayVisualizer.this.mainRender.drawString(ArrayVisualizer.this.Writes.getSwaps(), 15, (int)(ArrayVisualizer.this.cw/1280.0*210)+30); + ArrayVisualizer.this.mainRender.drawString(ArrayVisualizer.this.Writes.getReversals(), 15, (int)(ArrayVisualizer.this.cw/1280.0*235)+30); + ArrayVisualizer.this.mainRender.drawString(ArrayVisualizer.this.Writes.getWrites(), 15, (int)(ArrayVisualizer.this.cw/1280.0*275)+30); + ArrayVisualizer.this.mainRender.drawString(ArrayVisualizer.this.Writes.getTempWrites(), 15, (int)(ArrayVisualizer.this.cw/1280.0*300)+30); + ArrayVisualizer.this.mainRender.setFont(f); } - Graphics background = window.getGraphics(); - background.setColor(Color.BLACK); - background.drawImage(img, 0, 0, null); + background.drawImage(ArrayVisualizer.this.img, 0, 0, null); }}}; - Sounds.startAudioThread(); + this.Sounds.startAudioThread(); this.drawWindows(); } @@ -308,6 +338,10 @@ public Writes getWrites() { return this.Writes; } + public Visual[] getVisuals() { + return this.visualClasses; + } + public UtilFrame getUtilFrame() { return this.UtilFrame; } @@ -326,7 +360,7 @@ public void setSortingThread(Thread thread) { this.sortingThread = thread; } public void runSortingThread() { - sortingThread.start(); + this.sortingThread.start(); } public int getMinimumLength() { @@ -337,12 +371,12 @@ public int getMaximumLength() { } public void resetAllStatistics() { - Reads.resetStatistics(); - Writes.resetStatistics(); - Timer.manualSetTime(0); + this.Reads.resetStatistics(); + this.Writes.resetStatistics(); + this.Timer.manualSetTime(0); } - // These next three methods should be part of ArrayManager + // These next five methods should be part of ArrayManager public int getCurrentLength() { return this.currentLen; } @@ -350,6 +384,13 @@ public void setCurrentLength(int newLength) { this.currentLen = newLength; } + public int getEqualItems() { + return this.equalItems; + } + public void setEqualItems(int newCount) { + this.equalItems = newCount; + } + public int getLogBaseTwoOfLength() { return (int) (Math.log(this.currentLen) / Math.log(2)); } @@ -380,10 +421,10 @@ public JFrame getMainWindow() { } public void setWindowHeight() { - this.ch = window.getHeight(); + this.ch = this.window.getHeight(); } public void setWindowWidth() { - this.cw = window.getWidth(); + this.cw = this.window.getWidth(); } // TODO: @@ -391,16 +432,16 @@ public void setWindowWidth() { // AND WINDOW HEIGHT/WIDTH/X/Y SHOULD CORRESPOND TO WINDOW FIELD public int currentHeight() { - return window.getHeight(); + return this.window.getHeight(); } public int currentWidth() { - return window.getWidth(); + return this.window.getWidth(); } public int currentX() { - return window.getX(); + return this.window.getX(); } public int currentY() { - return window.getY(); + return this.window.getY(); } public int windowHeight() { @@ -423,7 +464,7 @@ public int windowYCoordinate() { } public void createVolatileImage() { - this.img = window.createVolatileImage(cw, ch); + this.img = this.window.createVolatileImage(this.cw, this.ch); } public void setThickStroke(Stroke stroke) { this.thickStroke = stroke; @@ -434,28 +475,39 @@ public Stroke getThickStroke() { public Stroke getDefaultStroke() { return new BasicStroke(3f * (this.currentWidth() / 1280f)); } + public Graphics2D getMainRender() { + return this.mainRender; + } + public Graphics2D getExtraRender() { + return this.extraRender; + } public void setMainRender() { - this.mainRender = (Graphics2D) img.getGraphics(); + this.mainRender = (Graphics2D) this.img.getGraphics(); } public void setExtraRender() { - this.extraRender = (Graphics2D) img.getGraphics(); + this.extraRender = (Graphics2D) this.img.getGraphics(); + } + public void updateVisuals() { + for(Visual visual : this.visualClasses) { + visual.updateRender(this); + } } public void resetMainStroke() { - mainRender.setStroke(this.getDefaultStroke()); + this.mainRender.setStroke(this.getDefaultStroke()); } public void renderBackground() { - mainRender.setColor(new Color(0, 0, 0)); // Pure black - mainRender.fillRect(0, 0, img.getWidth(null), img.getHeight(null)); + this.mainRender.setColor(new Color(0, 0, 0)); // Pure black + this.mainRender.fillRect(0, 0, this.img.getWidth(null), this.img.getHeight(null)); } public void updateCoordinates() { - this.cx = window.getX(); - this.cy = window.getY(); + this.cx = this.window.getX(); + this.cy = this.window.getY(); } public void updateDimensions() { - this.cw = window.getWidth(); - this.ch = window.getHeight(); + this.cw = this.window.getWidth(); + this.ch = this.window.getHeight(); } public void updateFontSize() { this.typeFace = new Font("Times New Roman",Font.PLAIN,(int)(this.cw/1280.0*25)); @@ -472,52 +524,89 @@ public int halfCircle() { return (this.currentLen / 2); } - public synchronized void fancyFinish() { - Highlights.toggleFancyFinish(true); - Highlights.resetFancyFinish(); + //TODO: This method is *way* too long. Break it apart. + public synchronized void verifySortAndSweep() { + this.Highlights.toggleFancyFinish(true); + this.Highlights.resetFancyFinish(); - Delays.setSleepRatio(1); + this.Delays.setSleepRatio(1); double sleepRatio = 0; switch(this.getLogBaseTwoOfLength()) { - case 12: sleepRatio = 1; break; - case 11: sleepRatio = 2; break; - case 10: sleepRatio = 4; break; - case 9: sleepRatio = 6; break; - case 8: sleepRatio = 8; break; - case 7: sleepRatio = 16; break; - case 6: sleepRatio = 24; break; + case 14: sleepRatio = 0.25; break; + case 13: sleepRatio = 0.5; break; + case 12: sleepRatio = 1; break; + case 11: sleepRatio = 2; break; + case 10: sleepRatio = 4; break; + case 9: sleepRatio = 6; break; + case 8: sleepRatio = 8; break; + case 7: sleepRatio = 16; break; + case 6: sleepRatio = 24; break; case 5: - case 4: sleepRatio = 32; break; + case 4: sleepRatio = 32; break; case 3: case 2: default: sleepRatio = 64; } + long tempComps = this.Reads.getComparisons(); + this.Reads.setComparisons(0); + + String temp = this.heading; + this.heading = "Verifying sort..."; + for(int i = 0; i < this.currentLen + this.getLogBaseTwoOfLength(); i++) { - if(i < this.currentLen) Highlights.markArray(1, i); - Highlights.incrementFancyFinishPosition(); + if(i < this.currentLen) this.Highlights.markArray(1, i); + this.Highlights.incrementFancyFinishPosition(); - Delays.sleep(sleepRatio / this.getLogBaseTwoOfLength()); + if(i < this.currentLen - 1) { + if(this.Reads.compare(this.array[i], this.array[i + 1]) == 1) { + this.Highlights.clearMark(1); + + this.Sounds.toggleSound(false); + this.Highlights.toggleFancyFinish(false); + + for(int j = i + 1; j < this.currentLen; j++) { + this.Highlights.markArray(j, j); + this.Delays.sleep(sleepRatio / this.getLogBaseTwoOfLength()); + } + + JOptionPane.showMessageDialog(this.window, "The sort was unsuccessful;\nIndices " + i + " and " + (i + 1) + " are out of order!", "Error", JOptionPane.OK_OPTION, null); + + this.Highlights.clearAllMarks(); + + i = this.currentLen + this.getLogBaseTwoOfLength(); + + this.Sounds.toggleSound(true); + } + } + + if(this.Highlights.fancyFinishEnabled()) { + this.Delays.sleep(sleepRatio / this.getLogBaseTwoOfLength()); + } } - Highlights.clearMark(1); + this.Highlights.clearMark(1); - Highlights.toggleFancyFinish(false); - Highlights.resetFancyFinish(); + this.heading = temp; + this.Reads.setComparisons(tempComps); + + if(this.Highlights.fancyFinishActive()) { + this.Highlights.toggleFancyFinish(false); + } + this.Highlights.resetFancyFinish(); } public void endSort() { - Timer.disableRealTimer(); - Highlights.clearAllMarks(); + this.Timer.disableRealTimer(); + this.Highlights.clearAllMarks(); - if(Highlights.fancyFinishEnabled()) { - double speed = Delays.getSleepRatio(); - this.fancyFinish(); - Delays.setSleepRatio(speed); - - Highlights.clearAllMarks(); - } + double speed = this.Delays.getSleepRatio(); + this.verifySortAndSweep(); + this.Delays.setSleepRatio(speed); + this.Delays.changeSkipped(false); + + this.Highlights.clearAllMarks(); } public void togglePointer(boolean Bool) { @@ -544,6 +633,9 @@ public void toggleStatistics(boolean Bool) { public void toggleColor(boolean Bool) { this.COLOR = Bool; } + public void toggleWave(boolean Bool) { + this.WAVEDRAW = Bool; + } public void setVisual(VisualStyles choice) { this.VisualStyles = choice; @@ -557,8 +649,8 @@ public void setCurrentGap(int gap) { } public void repositionFrames() { - ArrayFrame.reposition(); - UtilFrame.reposition(ArrayFrame); + this.ArrayFrame.reposition(); + this.UtilFrame.reposition(this.ArrayFrame); } public boolean rainbowEnabled() { @@ -579,6 +671,9 @@ public boolean pixelsEnabled() { public boolean linesEnabled() { return this.LINEDRAW; } + public boolean waveEnabled() { + return this.WAVEDRAW; + } public DecimalFormat getNumberFormat() { return this.formatter; @@ -589,40 +684,40 @@ private void drawWindows() { this.category = "Select a Sort"; // For recording with OBS (don't ask where these numbers came from. I don't get it myself) - if(OBS) { + if(this.OBS) { int x = (int) (1920 * (double) (1920 / 1916)); int y = (int) (1080 * (double) (1080 / 1020)); - window.setSize(new Dimension(x, y)); + this.window.setSize(new Dimension(x, y)); } else { // Consider changing back to discrete 16:9 dimension Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - window.setSize((int) (screenSize.getWidth() / 2d), (int) (screenSize.getHeight() / 2d)); + this.window.setSize((int) (screenSize.getWidth() / 2d), (int) (screenSize.getHeight() / 2d)); } - window.setLocation(0, 0); - window.setVisible(true); - window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - window.setTitle("w0rthy's Array Visualizer - " + (ComparisonSorts[0].length + DistributionSorts[0].length) + " Sorting Algorithms with 10 Different Visual Styles"); - window.setBackground(Color.BLACK); + this.window.setLocation(0, 0); + this.window.setVisible(true); + this.window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + this.window.setTitle("w0rthy's Array Visualizer - " + (this.ComparisonSorts[0].length + this.DistributionSorts[0].length) + " Sorting Algorithms with 12 Different Visual Styles"); + this.window.setBackground(Color.BLACK); - symbols.setGroupingSeparator(','); - formatter.setDecimalFormatSymbols(symbols); + this.symbols.setGroupingSeparator(','); + this.formatter.setDecimalFormatSymbols(this.symbols); //TODO: Consider removing insets from window size - this.cw = window.getWidth(); - this.ch = window.getHeight(); + this.cw = this.window.getWidth(); + this.ch = this.window.getHeight(); - visualsThread.start(); + this.visualsThread.start(); - UtilFrame.setVisible(true); - ArrayFrame.setVisible(true); + this.UtilFrame.setVisible(true); + this.ArrayFrame.setVisible(true); if(this.InvalidSorts != null) { String output = ""; - for(int i = 0; i < InvalidSorts.length; i++) { - output += InvalidSorts[i] + "\n"; + for(int i = 0; i < this.InvalidSorts.length; i++) { + output += this.InvalidSorts[i] + "\n"; } - JOptionPane.showMessageDialog(window, "The following algorithms were not loaded due to errors:\n" + output); + JOptionPane.showMessageDialog(this.window, "The following algorithms were not loaded due to errors:\n" + output, "Warning", JOptionPane.WARNING_MESSAGE); } } diff --git a/src/main/SortAnalyzer.java b/src/main/SortAnalyzer.java index b33e1b43..e3b99824 100644 --- a/src/main/SortAnalyzer.java +++ b/src/main/SortAnalyzer.java @@ -4,10 +4,12 @@ import java.util.ArrayList; import java.util.List; +import javax.swing.JOptionPane; + import io.github.classgraph.ClassGraph; import io.github.classgraph.ClassInfo; import io.github.classgraph.ScanResult; - +import templates.JErrorPane; import templates.Sort; import utils.Delays; import utils.Highlights; @@ -71,7 +73,7 @@ public void analyzeSorts() { Class sortClass = Class.forName(sortFiles.get(i).getName()); Constructor newSort = sortClass.getConstructor(new Class[] {Delays.class, Highlights.class, Reads.class, Writes.class}); Sort sort = (Sort) newSort.newInstance(this.Delays, this.Highlights, this.Reads, this.Writes); - + try { if(verifySort(sort)) { if(sort.comparisonBased()) { @@ -95,10 +97,8 @@ public void analyzeSorts() { e.printStackTrace(); } } - } catch (SecurityException e) { - e.printStackTrace(); - } catch (IllegalArgumentException e) { - e.printStackTrace(); + } catch (SecurityException | IllegalArgumentException e) { + JErrorPane.invokeErrorMessage(e); } } diff --git a/src/prompts/ShufflePrompt.java b/src/prompts/ShufflePrompt.java index b6144d30..ea471a72 100644 --- a/src/prompts/ShufflePrompt.java +++ b/src/prompts/ShufflePrompt.java @@ -5,10 +5,12 @@ package prompts; import javax.swing.JFrame; +import javax.swing.JOptionPane; import frames.UtilFrame; import main.ArrayManager; import templates.Frame; +import templates.JErrorPane; import utils.Shuffles; /* @@ -108,7 +110,7 @@ public void valueChanged(javax.swing.event.ListSelectionEvent evt) { try { jList1ValueChanged(evt); } catch (Exception e) { - e.printStackTrace(); + JErrorPane.invokeErrorMessage(e); } } }); diff --git a/src/prompts/SortPrompt.java b/src/prompts/SortPrompt.java index 1dc03b3c..37f835f6 100644 --- a/src/prompts/SortPrompt.java +++ b/src/prompts/SortPrompt.java @@ -9,9 +9,10 @@ import frames.UtilFrame; import main.ArrayVisualizer; import templates.Frame; +import templates.JErrorPane; +import threads.RunAllSorts; import threads.RunComparisonSort; import threads.RunDistributionSort; -import threads.RunSelectionSorts; /* * @@ -138,8 +139,7 @@ public void valueChanged(javax.swing.event.ListSelectionEvent evt) { jScrollPane2.setViewportView(this.jList1); - //TODO: Better time estimate - jButton1.setText("Run All (approx. " + (int) Math.max(Math.ceil(30 * (ArrayVisualizer.getCurrentLength() / 2048d)), 2) + " minutes)"); + jButton1.setText("Run All (approx. 30-60 minutes)"); jButton1.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -187,34 +187,10 @@ private void jButton1ActionPerformed() {//GEN-FIRST:event_jButton1ActionPerforme @Override public void run(){ try { - /* - RunMergeSorts sortThread = new RunMergeSorts(ArrayVisualizer); - sortThread.ReportMergeSorts(array); - */ - - RunSelectionSorts sortThread2 = new RunSelectionSorts(ArrayVisualizer); - sortThread2.ReportSelectionSorts(array); - - - /* - RunExchangeSorts sortThread1 = new RunExchangeSorts(ArrayVisualizer); - sortThread1.ReportExchangeSorts(array); - while(ArrayVisualizer.getSortingThread() != null) { - sleep(1000); - } - RunSelectionSorts sortThread2 = new RunSelectionSorts(ArrayVisualizer); - sortThread2.ReportSelectionSorts(array); - while(ArrayVisualizer.getSortingThread() != null) { - sleep(1000); - } - RunInsertionSorts sortThread3 = new RunInsertionSorts(ArrayVisualizer); - sortThread3.ReportInsertionSorts(array); - */ - - //RunAllSorts.RunAllSorts(); + RunAllSorts RunAllSorts = new RunAllSorts(ArrayVisualizer); + RunAllSorts.reportAllSorts(array); } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); + JErrorPane.invokeErrorMessage(e); } } }.start(); @@ -232,8 +208,7 @@ public void run(){ RunDistributionSort sortThread = new RunDistributionSort(ArrayVisualizer); sortThread.ReportDistributiveSort(array, selection); } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); + JErrorPane.invokeErrorMessage(e); } } }.start(); diff --git a/src/prompts/ViewPrompt.java b/src/prompts/ViewPrompt.java index b2d76efe..92c6043d 100644 --- a/src/prompts/ViewPrompt.java +++ b/src/prompts/ViewPrompt.java @@ -10,6 +10,10 @@ import main.ArrayVisualizer; import templates.Frame; import visuals.VisualStyles; +import javax.swing.JButton; +import javax.swing.GroupLayout.Alignment; +import javax.swing.GroupLayout; +import javax.swing.LayoutStyle.ComponentPlacement; /* * @@ -81,6 +85,8 @@ private void initComponents() { this.spiralDots= new javax.swing.JButton(); this.rainbow = new javax.swing.JButton(); this.hoops = new javax.swing.JButton(); + this.sineWave = new javax.swing.JButton(); + this.waveDots = new javax.swing.JButton(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setResizable(false); @@ -166,58 +172,77 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { spiralDotsActionPerformed(evt); } }); - + + sineWave.setText("Sine Wave"); + sineWave.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + sineWaveActionPerformed(evt); + } + }); + waveDots.setText("Wave Dots"); + waveDots.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + waveDotsActionPerformed(evt); + } + }); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); - getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER, true) - .addGroup(layout.createSequentialGroup() - .addGap(18, 18, 18) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, true) - .addComponent(this.barGraph, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(this.rainbow, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(this.colorCircle, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(this.disparity, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(this.disparityDots, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, true) - .addComponent(this.dotGraph, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(this.triangleMesh, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(this.spiral, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(this.hoops, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(this.spiralDots, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGap(18, 18, 18)) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER, true) - .addComponent(this.jLabel1)) - ); + layout.createParallelGroup(Alignment.CENTER) + .addComponent(jLabel1) + .addGroup(Alignment.LEADING, layout.createSequentialGroup() + .addGap(18) + .addGroup(layout.createParallelGroup(Alignment.LEADING) + .addComponent(barGraph, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 105, Short.MAX_VALUE) + .addComponent(rainbow, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 105, Short.MAX_VALUE) + .addComponent(colorCircle, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 105, Short.MAX_VALUE) + .addComponent(disparity, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(disparityDots, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 105, Short.MAX_VALUE) + .addComponent(sineWave, GroupLayout.DEFAULT_SIZE, 105, Short.MAX_VALUE)) + .addPreferredGap(ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(Alignment.LEADING) + .addComponent(waveDots, GroupLayout.DEFAULT_SIZE, 101, Short.MAX_VALUE) + .addComponent(dotGraph, GroupLayout.DEFAULT_SIZE, 101, Short.MAX_VALUE) + .addComponent(triangleMesh, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(spiral, GroupLayout.DEFAULT_SIZE, 101, Short.MAX_VALUE) + .addComponent(hoops, GroupLayout.DEFAULT_SIZE, 101, Short.MAX_VALUE) + .addComponent(spiralDots, GroupLayout.DEFAULT_SIZE, 101, Short.MAX_VALUE)) + .addGap(18)) + ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER, true) + layout.createParallelGroup(Alignment.CENTER) .addGroup(layout.createSequentialGroup() - .addGap(7, 7, 7) - .addComponent(this.jLabel1) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE, true) - .addComponent(this.barGraph, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(this.dotGraph, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE, true) - .addComponent(this.rainbow, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(this.triangleMesh, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE, true) - .addComponent(this.colorCircle, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(this.hoops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE, true) - .addComponent(this.disparity, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(this.spiral, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE, true) - .addComponent(this.disparityDots, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(this.spiralDots, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addContainerGap(18, Short.MAX_VALUE)) - ); + .addGap(7) + .addComponent(jLabel1) + .addPreferredGap(ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(barGraph) + .addComponent(dotGraph)) + .addPreferredGap(ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(rainbow) + .addComponent(triangleMesh)) + .addPreferredGap(ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(colorCircle) + .addComponent(hoops)) + .addPreferredGap(ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(disparity) + .addComponent(spiral)) + .addPreferredGap(ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(Alignment.BASELINE) + .addComponent(disparityDots) + .addComponent(spiralDots)) + .addPreferredGap(ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(Alignment.LEADING) + .addComponent(sineWave) + .addComponent(waveDots)) + .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + getContentPane().setLayout(layout); pack(); }// //GEN-END:initComponents @@ -228,6 +253,7 @@ private void setAllFieldsFalse(){ ArrayVisualizer.togglePixels(false); ArrayVisualizer.toggleRainbow(false); ArrayVisualizer.toggleSpiral(false); + ArrayVisualizer.toggleWave(false); } private void barGraphActionPerformed(java.awt.event.ActionEvent evt) { @@ -306,6 +332,21 @@ private void spiralDotsActionPerformed(java.awt.event.ActionEvent evt) { UtilFrame.jButton2ResetText(); dispose(); } + private void sineWaveActionPerformed(java.awt.event.ActionEvent evt) { + setAllFieldsFalse(); + ArrayVisualizer.setVisual(VisualStyles.BARS); + ArrayVisualizer.toggleWave(true); + UtilFrame.jButton2ResetText(); + dispose(); + } + private void waveDotsActionPerformed(java.awt.event.ActionEvent evt) { + setAllFieldsFalse(); + ArrayVisualizer.setVisual(VisualStyles.PIXELS); + ArrayVisualizer.togglePixels(true); + ArrayVisualizer.toggleWave(true); + UtilFrame.jButton2ResetText(); + dispose(); + } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton barGraph; @@ -318,7 +359,7 @@ private void spiralDotsActionPerformed(java.awt.event.ActionEvent evt) { private javax.swing.JButton disparityDots; private javax.swing.JButton rainbow; private javax.swing.JButton hoops; + private javax.swing.JButton sineWave; + private javax.swing.JButton waveDots; private javax.swing.JLabel jLabel1; - // End of variables declaration//GEN-END:variables - } \ No newline at end of file diff --git a/src/sorts/AmericanFlagSort.java b/src/sorts/AmericanFlagSort.java index a81e5f0e..ed2c16cc 100644 --- a/src/sorts/AmericanFlagSort.java +++ b/src/sorts/AmericanFlagSort.java @@ -143,6 +143,7 @@ private void sort(int[] array, int start, int length, int divisor) { @Override public void runSort(int[] array, int currentLen, int bucketCount) { this.NUMBER_OF_BUCKETS = bucketCount; + this.setRunAllID("American Flag Sort, " + this.NUMBER_OF_BUCKETS + " Buckets"); int numberOfDigits = this.getMaxNumberOfDigits(array, currentLen); // Max number of digits int max = 1; diff --git a/src/sorts/BadSort.java b/src/sorts/BadSort.java index 05597961..9ef47de9 100644 --- a/src/sorts/BadSort.java +++ b/src/sorts/BadSort.java @@ -31,7 +31,6 @@ public BadSort(Delays delayOps, Highlights markOps, Reads readOps, Writes writeO public void runSort(int[] array, int currentLen, int bucketCount) { for (int i = 0; i < currentLen; i++) { int shortest = i; - Highlights.markArray(3, shortest); Delays.sleep(0.05); for (int j = i; j < currentLen; j++) { @@ -53,7 +52,7 @@ public void runSort(int[] array, int currentLen, int bucketCount) { break; } } - Writes.swap(array, i, shortest, 1, true, false); + Writes.swap(array, i, shortest, 0.05, true, false); } } } \ No newline at end of file diff --git a/src/sorts/BinaryGnomeSort.java b/src/sorts/BinaryGnomeSort.java index 4c21dbda..eca2b99e 100644 --- a/src/sorts/BinaryGnomeSort.java +++ b/src/sorts/BinaryGnomeSort.java @@ -32,10 +32,10 @@ public void runSort(int[] array, int length, int bucketCount) { int mid = lo + ((hi - lo) / 2); Highlights.markArray(1, lo); - Highlights.markArray(2, mid); - Highlights.markArray(3, hi); + Highlights.markArray(3, mid); + Highlights.markArray(2, hi); - Delays.sleep(0.025); + Delays.sleep(1); if (Reads.compare(num, array[mid]) < 0) { // do NOT shift equal elements past each other; this maintains stability! hi = mid; @@ -48,7 +48,7 @@ public void runSort(int[] array, int length, int bucketCount) { // item has to go into position lo Highlights.clearMark(1); - Highlights.clearMark(3); + Highlights.clearMark(2); int j = i; while (j > lo) { diff --git a/src/sorts/BinaryInsertionSort.java b/src/sorts/BinaryInsertionSort.java index 32c37044..5c0d0bec 100644 --- a/src/sorts/BinaryInsertionSort.java +++ b/src/sorts/BinaryInsertionSort.java @@ -54,6 +54,6 @@ public void customBinaryInsert(int[] array, int start, int end, double sleep) { @Override public void runSort(int[] array, int currentLength, int bucketCount) { - this.binaryInsertSort(array, 0, currentLength, 0.05, 0.015); + this.binaryInsertSort(array, 0, currentLength, 1, 0.05); } } \ No newline at end of file diff --git a/src/sorts/BogoBogoSort.java b/src/sorts/BogoBogoSort.java new file mode 100644 index 00000000..4445add5 --- /dev/null +++ b/src/sorts/BogoBogoSort.java @@ -0,0 +1,41 @@ +package sorts; + +import templates.BogoSorting; + +public final class BogoBogoSort extends BogoSorting { + public BogoBogoSort(utils.Delays delayOps, utils.Highlights markOps, utils.Reads readOps, utils.Writes writeOps) { + super(delayOps, markOps, readOps, writeOps); + + this.setSortPromptID("Bogobogo"); + this.setRunAllID("Bogobogo Sort"); + this.setReportSortID("Bogobogosort"); + this.setCategory("Distributive Sorts"); + this.isComparisonBased(false); //Comparisons are not used to swap elements + this.isBucketSort(false); + this.isRadixSort(false); + this.isUnreasonablySlow(true); + this.setUnreasonableLimit(8); + this.isBogoSort(true); + } + + @Override + public void runSort(int[] array, int currentLength, int bucketCount) { + int bogoLength = 2; + boolean arrayNotSorted = true; + + while(arrayNotSorted) { + if(bogoIsSorted(array, bogoLength)) { + if(bogoLength == currentLength) { + arrayNotSorted = false; + } + else { + bogoLength++; + } + } + else { + bogoLength = 2; + } + if(arrayNotSorted) bogoSwap(array, bogoLength, 0); + } + } +} \ No newline at end of file diff --git a/src/sorts/BottomUpMergeSort.java b/src/sorts/BottomUpMergeSort.java index 813434b0..4486049e 100644 --- a/src/sorts/BottomUpMergeSort.java +++ b/src/sorts/BottomUpMergeSort.java @@ -11,7 +11,8 @@ public BottomUpMergeSort(Delays delayOps, Highlights markOps, Reads readOps, Wri super(delayOps, markOps, readOps, writeOps); this.setSortPromptID("Bottom-Up Merge"); - this.setRunAllID("Bottom-Up Merge Sort w/ Binary Insert (std::stable_sort)"); + //this.setRunAllID("Bottom-Up Merge Sort w/ Binary Insert (std::stable_sort)"); + this.setRunAllID("Bottom-Up Merge Sort [std::stable_sort]"); this.setReportSortID("Bottom-Up Mergesort w/ Binary Insert"); this.setCategory("Hybrid Sorts"); this.isComparisonBased(true); @@ -119,10 +120,12 @@ private void stableSort (int[] a, int n) { // Sort a[0:n-1] using merge sort. int s = 16; // segment size int[] b = new int [n]; + int i; - for(int i = 0; i <= n - 16; i += 16) { + for(i = 0; i <= n - 16; i += 16) { binaryInserter.customBinaryInsert(a, i, i + 16, 0.35); } + binaryInserter.customBinaryInsert(a, i, n, 0.35); while (s < n) { diff --git a/src/sorts/BubbleSort.java b/src/sorts/BubbleSort.java index cb9df361..3cffb038 100644 --- a/src/sorts/BubbleSort.java +++ b/src/sorts/BubbleSort.java @@ -62,7 +62,7 @@ public void runSort(int[] array, int length, int bucketCount) { Highlights.markArray(1, i); Highlights.markArray(2, i + 1); - Delays.sleep(0.025); + Delays.sleep(0.05); } } } diff --git a/src/sorts/CocktailBogoSort.java b/src/sorts/CocktailBogoSort.java index a1c7259b..00a1de2e 100644 --- a/src/sorts/CocktailBogoSort.java +++ b/src/sorts/CocktailBogoSort.java @@ -39,12 +39,12 @@ public void runSort(int[] array, int currentLen, int bucketCount) { } if(minSorted) { - Highlights.markArray(1, minIterator); + //Highlights.markArray(1, minIterator); minIterator++; minSorted = false; } if(maxSorted) { - Highlights.markArray(2, maxIterator); + //Highlights.markArray(2, maxIterator); maxIterator--; maxSorted = false; } diff --git a/src/sorts/CocktailMergeSort.java b/src/sorts/CocktailMergeSort.java index 93e2da9e..ca099844 100644 --- a/src/sorts/CocktailMergeSort.java +++ b/src/sorts/CocktailMergeSort.java @@ -57,7 +57,7 @@ public void runSort(int[] array, int currentLength, int bucketCount) { Highlights.clearAllMarks(); - this.timSortInstance = new TimSorting(array, currentLength, this.Highlights, this.Reads, this.Writes); + this.timSortInstance = new TimSorting(array, currentLength, this.Delays, this.Highlights, this.Reads, this.Writes); TimSorting.sort(this.timSortInstance, array, currentLength); } } diff --git a/src/sorts/CocktailShakerSort.java b/src/sorts/CocktailShakerSort.java index e0ae5260..34e20f8d 100644 --- a/src/sorts/CocktailShakerSort.java +++ b/src/sorts/CocktailShakerSort.java @@ -59,7 +59,7 @@ private void cocktailShaker(int[] array, int start, int end, double sleep) { Highlights.markArray(1, j); Highlights.markArray(2, j + 1); - Delays.sleep(0.01); + Delays.sleep(sleep / 2); } for(int j = end + start - i - 1; j > i; j--){ if(Reads.compare(array[j], array[j - 1]) == -1) { @@ -69,7 +69,7 @@ private void cocktailShaker(int[] array, int start, int end, double sleep) { Highlights.markArray(1, j); Highlights.markArray(2, j - 1); - Delays.sleep(0.01); + Delays.sleep(sleep / 2); } i++; @@ -82,6 +82,6 @@ public void customSort(int[] array, int start, int end) { @Override public void runSort(int[] array, int length, int bucketCount) { - this.cocktailShaker(array, 0, length, 0.0875); + this.cocktailShaker(array, 0, length, 0.1); } } \ No newline at end of file diff --git a/src/sorts/CountingSort.java b/src/sorts/CountingSort.java index f9c5e280..1283336f 100644 --- a/src/sorts/CountingSort.java +++ b/src/sorts/CountingSort.java @@ -57,25 +57,25 @@ public void runSort(int[] array, int length, int bucketCount) { int[] output = Arrays.copyOf(array, length); int[] counts = new int[max + 1]; - for(int i = 0; i < length; i++){ - Writes.write(counts, array[i], counts[array[i]] + 1, 0.5, false, true); + for (int i = 0; i < length; i++) { + Writes.write(counts, array[i], counts[array[i]] + 1, 1, false, true); Highlights.markArray(1, i); - } - for (int i = 1; i <= max; i++) { + } + + for (int i = 1; i < counts.length; i++) { Writes.write(counts, i, counts[i] + counts[i - 1], 1, true, true); + } + + for (int i = length - 1; i >= 0; i--) { + output[counts[array[i]] - 1] = array[i]; + counts[array[i]]--; } - for(int i = length - 1; i >= 0; i--){ - Writes.write(counts, array[i], counts[array[i]] - 1, 0, false, true); - Writes.write(output, counts[array[i]], array[i], 0, false, true); - - Writes.changeTempWrites(-2); - } - //Usually counting sort returns a sorted copy of the input array. The visualization pretends that happens here. - for(int i = length - 1; i >= 0; i--) { - Writes.write(array, i, output[i], 1, false, false); - + + // Extra loop to simulate the results from the "output" array being written + // to the visual array. + for (int i = length - 1; i >= 0; i--) { + Writes.write(array, i, output[i], 1, true, false); Writes.changeTempWrites(1); - Highlights.markArray(1, i); } } } \ No newline at end of file diff --git a/src/sorts/FlashSort.java b/src/sorts/FlashSort.java index 9b2bd387..075350ad 100644 --- a/src/sorts/FlashSort.java +++ b/src/sorts/FlashSort.java @@ -6,12 +6,9 @@ import utils.Delays; import utils.Highlights; import utils.Reads; -import utils.Shuffles; import utils.Writes; final public class FlashSort extends Sort { - private Shuffles currentShuffle; - public FlashSort(Delays delayOps, Highlights markOps, Reads readOps, Writes writeOps) { super(delayOps, markOps, readOps, writeOps); @@ -27,10 +24,6 @@ public FlashSort(Delays delayOps, Highlights markOps, Reads readOps, Writes writ this.isBogoSort(false); } - public void setCurrentShuffle(Shuffles choice) { - this.currentShuffle = choice; - } - private static int indexOfIntArray(int[] array, int length, int key) { int returnvalue = -1; for (int i = 0; i < length; ++i) { @@ -273,30 +266,29 @@ else if(Reads.compare(array[length - 1], max) == 1) //skip the K == m class because it is already sorted //since all of the elements have the same value - if(!currentShuffle.equals(Shuffles.SIMILAR)) { - for(K = m - 1; K >= 1; K--) + for(K = m - 1; K >= 1; K--) + { + //determine the number of elments in the Kth class + int classSize = L[K + 1] - L[K]; + + //if the class size is larger than expected but not + //so small that insertion sort could make quick work + //of it then... + if(classSize > threshold && classSize > minElements) { - //determine the number of elments in the Kth class - int classSize = L[K + 1] - L[K]; - - //if the class size is larger than expected but not - //so small that insertion sort could make quick work - //of it then... - if(classSize > threshold && classSize > minElements) - { - //...attempt to flashsort the class. This will work - //well if the elements inside the class are uniformly - //distributed throughout the class otherwise it will - //perform badly, O(n^2) worst case, since we will have - //performed another classification and permutation step - //and not succeeded in making the problem significantly - //smaller for the next level of recursion. However, - //progress is assured since at each level the elements - //with the maximum value will get sorted. - runSort(Arrays.copyOfRange(array, FlashSort.indexOfIntArray(array, length, L[K]), FlashSort.indexOfIntArray(array, length, L[K+1])), classSize, 0); - } + //...attempt to flashsort the class. This will work + //well if the elements inside the class are uniformly + //distributed throughout the class otherwise it will + //perform badly, O(n^2) worst case, since we will have + //performed another classification and permutation step + //and not succeeded in making the problem significantly + //smaller for the next level of recursion. However, + //progress is assured since at each level the elements + //with the maximum value will get sorted. + runSort(Arrays.copyOfRange(array, L[K], L[K + 1]), classSize, 0); } } + InsertionSort insertSorter = new InsertionSort(this.Delays, this.Highlights, this.Reads, this.Writes); insertSorter.customInsertSort(array, 0, length, 0.75, false); } diff --git a/src/sorts/FlippedMinHeapSort.java b/src/sorts/FlippedMinHeapSort.java new file mode 100644 index 00000000..6313c2b5 --- /dev/null +++ b/src/sorts/FlippedMinHeapSort.java @@ -0,0 +1,67 @@ +package sorts; + +import templates.Sort; +import utils.Delays; +import utils.Highlights; +import utils.Reads; +import utils.Writes; + +/* + * +Copyright (c) rosettacode.org. +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.2 +or any later version published by the Free Software Foundation; +with no Invariant Sections, no Front-Cover Texts, and no Back-Cover +Texts. A copy of the license is included in the section entitled "GNU +Free Documentation License". + * + */ + +/* +modified by Lucy Phipps from ../templates/HeapSorting.java and MinHeapSort.java +the only real changes are subtracting every array access from (length - 1) +and removing the Writes.reverse() at the end +the rest is just compacting the code a bit +*/ + +final public class FlippedMinHeapSort extends Sort { + public FlippedMinHeapSort(Delays delayOps, Highlights markOps, Reads readOps, Writes writeOps) { + super(delayOps, markOps, readOps, writeOps); + this.setSortPromptID("Flipped Min Heap"); + this.setRunAllID("Flipped Min Heap Sort"); + this.setReportSortID("Flipped Reverse Heapsort"); + this.setCategory("Selection Sorts"); + this.isComparisonBased(true); + this.isBucketSort(false); + this.isRadixSort(false); + this.isUnreasonablySlow(false); + this.setUnreasonableLimit(0); + this.isBogoSort(false); + } + private void siftDown(int[] array, int length, int root, int dist) { + while (root <= dist / 2) { + int leaf = 2 * root; + if (leaf < dist && Reads.compare(array[length - leaf], array[length - leaf - 1]) == 1) { + leaf++; + } + Highlights.markArray(1, length - root); + Highlights.markArray(2, length - leaf); + Delays.sleep(1); + if (Reads.compare(array[length - root], array[length - leaf]) == 1) { + Writes.swap(array, length - root, length - leaf, 0, true, false); + root = leaf; + } else break; + } + } + @Override + public void runSort(int[] array, int length, int bucketCount) { + for (int i = length / 2; i >= 1; i--) { + siftDown(array, length, i, length); + } + for (int i = length; i > 1; i--) { + Writes.swap(array, length - 1, length - i, 1, true, false); + siftDown(array, length, 1, i - 1); + } + } +} \ No newline at end of file diff --git a/src/sorts/GnomeSort.java b/src/sorts/GnomeSort.java index 607ff664..6d8729aa 100644 --- a/src/sorts/GnomeSort.java +++ b/src/sorts/GnomeSort.java @@ -32,7 +32,7 @@ public void runSort(int[] array, int length, int bucketCount) { { i++; Highlights.markArray(1, i); - Delays.sleep(0.02); + Delays.sleep(0.04); } else { @@ -43,7 +43,7 @@ public void runSort(int[] array, int length, int bucketCount) { if (i > 1) { i--; Highlights.markArray(1, i); - Delays.sleep(0.01); + Delays.sleep(0.02); } } } diff --git a/src/sorts/GrailSort.java b/src/sorts/GrailSort.java index c4c83e0e..2651e1bc 100644 --- a/src/sorts/GrailSort.java +++ b/src/sorts/GrailSort.java @@ -57,7 +57,8 @@ public GrailSort(Delays delayOps, Highlights markOps, Reads readOps, Writes writ super(delayOps, markOps, readOps, writeOps); this.setSortPromptID("Grail"); - this.setRunAllID("Grail Sort (Block Merge Sort)"); + //this.setRunAllID("Grail Sort (Block Merge Sort)"); + this.setRunAllID("Grail Sort [Block Merge Sort]"); this.setReportSortID("Grailsort"); this.setCategory("Hybrid Sorts"); this.isComparisonBased(true); diff --git a/src/sorts/GravitySort.java b/src/sorts/GravitySort.java index b2019dd3..7df2ce27 100644 --- a/src/sorts/GravitySort.java +++ b/src/sorts/GravitySort.java @@ -37,7 +37,8 @@ public GravitySort(Delays delayOps, Highlights markOps, Reads readOps, Writes wr super(delayOps, markOps, readOps, writeOps); this.setSortPromptID("Gravity"); - this.setRunAllID("Gravity (Bead) Sort"); + this.setRunAllID("Gravity Sort"); + //this.setRunAllID("Gravity (Bead) Sort"); this.setReportSortID("Beadsort"); this.setCategory("Distributive Sorts"); this.isComparisonBased(false); @@ -50,7 +51,7 @@ public GravitySort(Delays delayOps, Highlights markOps, Reads readOps, Writes wr @Override public void runSort(int[] array, int length, int bucketCount) { - int max = Reads.analyzeMax(array, length, 0.25, true); + int max = Reads.analyzeMax(array, length, 1, true); int[][] abacus = new int[length][max]; for(int i = 0; i < length; i++) { @@ -60,14 +61,18 @@ public void runSort(int[] array, int length, int bucketCount) { } //apply gravity - for(int i = 0; i < abacus[0].length; i++) { + for(int i = 0; i < abacus[0].length; i++) { for(int j = 0; j < abacus.length; j++) { - if(abacus[j][i] == 1) { + Highlights.markArray(1, j); + if(abacus[j][i] == 1) { //Drop it int dropPos = j; - while(dropPos + 1 < abacus.length && abacus[dropPos][i] == 1) + Writes.startLap(); + while(dropPos + 1 < abacus.length && abacus[dropPos][i] == 1) { dropPos++; + } + Writes.stopLap(); if(abacus[dropPos][i] == 0) { Writes.multiDimWrite(abacus, j, i, 0, 0, true, true); @@ -80,13 +85,15 @@ public void runSort(int[] array, int length, int bucketCount) { for(int x = 0; x < abacus.length; x++){ count = 0; - for(int y = 0; y < abacus[0].length; y++) + Writes.startLap(); + for(int y = 0; y < abacus[0].length; y++) { count += abacus[x][y]; + } + Writes.stopLap(); - Writes.write(array, x, count, 0.002, true, false); + Writes.write(array, x, count, 0.001, true, false); } Highlights.markArray(2, length - i - 1); - Delays.sleep(0.001); } } } \ No newline at end of file diff --git a/src/sorts/HolyGrailSort.java b/src/sorts/HolyGrailSort.java index 3d63c343..4e06c63d 100644 --- a/src/sorts/HolyGrailSort.java +++ b/src/sorts/HolyGrailSort.java @@ -74,7 +74,7 @@ final public class HolyGrailSort extends HolyGrailSorting { public HolyGrailSort(Delays delayOps, Highlights markOps, Reads readOps, Writes writeOps) { super(delayOps, markOps, readOps, writeOps); - this.setSortPromptID(""); // Sort disabled + this.setSortPromptID("Holy Grail"); this.setRunAllID("Holy Grail Sort (Block Merge Sort)"); this.setReportSortID("Holygrailsort"); this.setCategory("Hybrid Sorts"); diff --git a/src/sorts/InPlaceLSDRadixSort.java b/src/sorts/InPlaceLSDRadixSort.java index 2b381bcd..0c973d5d 100644 --- a/src/sorts/InPlaceLSDRadixSort.java +++ b/src/sorts/InPlaceLSDRadixSort.java @@ -33,13 +33,12 @@ of this software and associated documentation files (the "Software"), to deal */ final public class InPlaceLSDRadixSort extends Sort { - private int buckets = 2; // default choice - public InPlaceLSDRadixSort(Delays delayOps, Highlights markOps, Reads readOps, Writes writeOps) { super(delayOps, markOps, readOps, writeOps); this.setSortPromptID("In-Place LSD Radix"); - this.setRunAllID("In-Place LSD Radix Sort, Base " + buckets); + //this.setRunAllID("In-Place LSD Radix Sort, Base 2"); + this.setRunAllID("In-Place LSD Radix Sort, Base 10"); this.setReportSortID("In-Place LSD Radix Sort"); this.setCategory("Distributive Sorts"); this.isComparisonBased(false); @@ -52,12 +51,12 @@ public InPlaceLSDRadixSort(Delays delayOps, Highlights markOps, Reads readOps, W @Override public void runSort(int[] array, int length, int bucketCount) { - this.buckets = bucketCount; + this.setRunAllID("In-Place LSD Radix Sort, Base " + bucketCount); int pos = 0; int[] vregs = new int[bucketCount-1]; - int maxpower = Reads.analyzeMaxLog(array, length, bucketCount, 0.25, true); + int maxpower = Reads.analyzeMaxLog(array, length, bucketCount, 0.5, true); for(int p = 0; p <= maxpower; p++){ for(int i = 0; i < vregs.length; i++) { @@ -77,7 +76,7 @@ public void runSort(int[] array, int length, int bucketCount) { for(int j = 0; j < vregs.length;j++) Highlights.markArray(j + 1, vregs[j]); - Writes.multiSwap(array, pos, vregs[digit - 1], 0.00075, false, false); + Writes.multiSwap(array, pos, vregs[digit - 1], bucketCount / 10000d, false, false); for(int j = digit - 1; j > 0; j--) { Writes.write(vregs, j - 1, vregs[j - 1] - 1, 0, false, true); diff --git a/src/sorts/IntroSort.java b/src/sorts/IntroSort.java index 0224a2f1..3b14abc0 100644 --- a/src/sorts/IntroSort.java +++ b/src/sorts/IntroSort.java @@ -1,5 +1,8 @@ package sorts; +import java.util.Arrays; + +import templates.JErrorPane; import templates.Sort; import utils.Delays; import utils.Highlights; @@ -21,7 +24,8 @@ public IntroSort(Delays delayOps, Highlights markOps, Reads readOps, Writes writ super(delayOps, markOps, readOps, writeOps); this.setSortPromptID("Intro"); - this.setRunAllID("Introspective Sort (std::sort)"); + //this.setRunAllID("Introspective Sort (std::sort)"); + this.setRunAllID("Introspective Sort [std::sort]"); this.setReportSortID("Introsort"); this.setCategory("Hybrid Sorts"); this.isComparisonBased(true); @@ -36,6 +40,33 @@ private static int floorLogBaseTwo(int a) { return (int) (Math.floor(Math.log(a) / Math.log(2))); } + // Swaps the median of arr[left], arr[mid], and arr[right] to index left. + // taken from gcc source code found here: https://gcc.gnu.org/onlinedocs/gcc-4.7.2/libstdc++/api/a01462_source.html + private int gccmedianof3(int[] arr, int left, int mid, int right) { + if (Reads.compare(arr[left], arr[mid]) < 0) { + if (Reads.compare(arr[mid], arr[right]) < 0) { + Writes.swap(arr, left, mid, 1, true, false); + } + else if (Reads.compare(arr[left], arr[right]) < 0) { + Writes.swap(arr, left, right, 1, true, false); + } + } + else if (Reads.compare(arr[left], arr[right]) < 0) { + middle = left; + Highlights.markArray(3, left); + return arr[left]; + } + else if (Reads.compare(arr[mid], arr[right]) < 0) { + Writes.swap(arr, left, right, 1, true, false); + } + else { + Writes.swap(arr, left, mid, 1, true, false); + } + middle = left; + Highlights.markArray(3, left); + return arr[left]; + } + private int medianof3(int[] arr, int left, int mid, int right) { if(Reads.compare(arr[right], arr[left]) == -1) { Writes.swap(arr, left, right, 1, true, false); @@ -94,7 +125,7 @@ private void introsortLoop (int[] a, int lo, int hi, int depthLimit) { return; } depthLimit--; - int p = partition(a, lo, hi, medianof3(a, lo, lo + ((hi - lo) / 2) + 1, hi - 1)); + int p = partition(a, lo, hi, medianof3(a, lo, lo + ((hi - lo) / 2), hi - 1)); introsortLoop(a, p, hi, depthLimit); hi = p; } diff --git a/src/sorts/LLQuickSort.java b/src/sorts/LLQuickSort.java index 7d18b5dd..b948b261 100644 --- a/src/sorts/LLQuickSort.java +++ b/src/sorts/LLQuickSort.java @@ -27,10 +27,12 @@ private int partition(int[] array, int lo, int hi) { int i = lo; for(int j = lo; j < hi; j++) { + Highlights.markArray(1, j); if(Reads.compare(array[j], pivot) < 0) { Writes.swap(array, i, j, 1, true, false); i++; } + Delays.sleep(1); } Writes.swap(array, i, hi, 1, true, false); return i; diff --git a/src/sorts/LSDRadixSort.java b/src/sorts/LSDRadixSort.java index 547aca11..5a6a1d3c 100644 --- a/src/sorts/LSDRadixSort.java +++ b/src/sorts/LSDRadixSort.java @@ -39,7 +39,7 @@ public LSDRadixSort(Delays delayOps, Highlights markOps, Reads readOps, Writes w super(delayOps, markOps, readOps, writeOps); this.setSortPromptID("LSD Radix"); - this.setRunAllID("Least Significant Digit Radix Sort"); + this.setRunAllID("Least Significant Digit Radix Sort, Base 4"); this.setReportSortID("Least Significant Digit Radixsort"); this.setCategory("Distributive Sorts"); this.isComparisonBased(false); @@ -52,7 +52,9 @@ public LSDRadixSort(Delays delayOps, Highlights markOps, Reads readOps, Writes w @Override public void runSort(int[] array, int length, int bucketCount) { - int highestpower = Reads.analyzeMaxLog(array, length, bucketCount, 0.25, true); + this.setRunAllID("Least Significant Digit Radix Sort, Base " + bucketCount); + + int highestpower = Reads.analyzeMaxLog(array, length, bucketCount, 0.5, true); @SuppressWarnings("unchecked") ArrayList[] registers = new ArrayList[bucketCount]; @@ -67,20 +69,10 @@ public void runSort(int[] array, int length, int bucketCount) { int digit = Reads.getDigit(array[i], p, bucketCount); registers[digit].add(array[i]); - Writes.mockWrite(length, digit, array[i], 0.5); - } - - double tempSleep = Delays.getSleepRatio(); - - if(!Delays.skipped()) { - Delays.setSleepRatio((Math.log(length) / Math.log(2)) / 4); + Writes.mockWrite(length, digit, array[i], 1); } - Writes.fancyTranscribe(array, length, registers); - - if(!Delays.skipped()) { - Delays.setSleepRatio(tempSleep); - } + Writes.fancyTranscribe(array, length, registers, bucketCount * 0.8); } } } \ No newline at end of file diff --git a/src/sorts/LessBogoSort.java b/src/sorts/LessBogoSort.java index bca26dad..813322a3 100644 --- a/src/sorts/LessBogoSort.java +++ b/src/sorts/LessBogoSort.java @@ -30,7 +30,7 @@ public void runSort(int[] array, int currentLen, int bucketCount) { while(!this.isMinSorted(array, currentLen, iterator)) { this.bogoSwap(array, currentLen, iterator); } - Highlights.markArray(1, iterator); + //Highlights.markArray(1, iterator); iterator++; } } diff --git a/src/sorts/MSDRadixSort.java b/src/sorts/MSDRadixSort.java index daa53138..52b49190 100644 --- a/src/sorts/MSDRadixSort.java +++ b/src/sorts/MSDRadixSort.java @@ -39,7 +39,8 @@ public MSDRadixSort(Delays delayOps, Highlights markOps, Reads readOps, Writes w super(delayOps, markOps, readOps, writeOps); this.setSortPromptID("MSD Radix"); - this.setRunAllID("Most Significant Digit Radix Sort"); + //this.setRunAllID("Most Significant Digit Radix Sort"); + this.setRunAllID("Most Significant Digit Radix Sort, Base 4"); this.setReportSortID("Most Significant Digit Radixsort"); this.setCategory("Distributive Sorts"); this.isComparisonBased(false); @@ -69,23 +70,13 @@ private void radixMSD(int[] array, int length, int min, int max, int radix, int int digit = Reads.getDigit(array[i], pow, radix); registers[digit].add(array[i]); - Writes.mockWrite(length, digit, array[i], 0.5); + Writes.mockWrite(length, digit, array[i], 1); } Highlights.clearMark(2); Highlights.clearMark(3); - double tempSleep = Delays.getSleepRatio(); - - if(!Delays.skipped()) { - Delays.setSleepRatio((Math.log(length) / Math.log(2)) / 6); - } - - Writes.transcribeMSD(array, registers, 0, min, true, false); - - if(!Delays.skipped()) { - Delays.setSleepRatio(tempSleep); - } + Writes.transcribeMSD(array, registers, 0, min, 0.8, true, false); int sum = 0; for(int i = 0; i < registers.length; i++) { @@ -99,7 +90,7 @@ private void radixMSD(int[] array, int length, int min, int max, int radix, int @Override public void runSort(int[] array, int length, int bucketCount) { - int highestpower = Reads.analyzeMaxLog(array, length, bucketCount, 0.25, true); + int highestpower = Reads.analyzeMaxLog(array, length, bucketCount, 0.5, true); radixMSD(array, length, 0, length, bucketCount, highestpower); } diff --git a/src/sorts/OptimizedDualPivotQuickSort.java b/src/sorts/OptimizedDualPivotQuickSort.java index e3f7102c..6c530e59 100644 --- a/src/sorts/OptimizedDualPivotQuickSort.java +++ b/src/sorts/OptimizedDualPivotQuickSort.java @@ -16,7 +16,8 @@ public OptimizedDualPivotQuickSort(Delays delayOps, Highlights markOps, Reads re super(delayOps, markOps, readOps, writeOps); this.setSortPromptID("Opti. Dual-Pivot Quick"); - this.setRunAllID("Optimized Dual-Pivot Quick Sort"); + //this.setRunAllID("Optimized Dual-Pivot Quick Sort"); + this.setRunAllID("Optimized Dual-Pivot Quick Sort [Arrays.sort]"); this.setReportSortID("Optimized Dual-Pivot Quicksort"); this.setCategory("Hybrid Sorts"); this.isComparisonBased(true); @@ -33,7 +34,7 @@ private void dualPivot(int[] array, int left, int right, int divisor) { // insertion sort for tiny array if(length < 27) { Highlights.clearMark(2); - insertSorter.customInsertSort(array, left, right + 1, 0.75, false); + insertSorter.customInsertSort(array, left, right + 1, 1, false); return; } @@ -74,8 +75,11 @@ private void dualPivot(int[] array, int left, int right, int divisor) { else if(Reads.compare(array[k], pivot2) == 1) { while(k < great && Reads.compare(array[great], pivot2) == 1) { great--; + Highlights.markArray(3, great); + Delays.sleep(1); } Writes.swap(array, k, great--, 1, true, false); + Highlights.clearMark(3); if(Reads.compare(array[k], pivot1) == -1) { Writes.swap(array, k, less++, 1, true, false); diff --git a/src/sorts/PancakeSort.java b/src/sorts/PancakeSort.java index b63a9b59..852fed1d 100644 --- a/src/sorts/PancakeSort.java +++ b/src/sorts/PancakeSort.java @@ -20,8 +20,8 @@ public PancakeSort(Delays delayOps, Highlights markOps, Reads readOps, Writes wr super(delayOps, markOps, readOps, writeOps); this.setSortPromptID("Pancake"); - this.setRunAllID("Pancake Sort"); - this.setReportSortID("Pancake Sorting"); + this.setRunAllID("Pancake Sorting"); + this.setReportSortID("Pancake Sort"); this.setCategory("Miscellaneous Sorts"); this.isComparisonBased(true); this.isBucketSort(false); @@ -32,7 +32,7 @@ public PancakeSort(Delays delayOps, Highlights markOps, Reads readOps, Writes wr } private boolean sorted(int[] array, int length) { - for(int i = 0; i < length - 1; i++) { + for(int i = 0; i < length; i++) { Highlights.markArray(1, i); Delays.sleep(0.025); @@ -49,6 +49,7 @@ private int findMax(int[] arr, int end) { if (Reads.compare(arr[i], max) == 1) { max = arr[i]; index = i; + Highlights.markArray(2, i); } Delays.sleep(0.025); @@ -61,7 +62,6 @@ private int findMax(int[] arr, int end) { public void runSort(int[] array, int length, int bucketCount) { for (int i = length - 1; i >= 0; i--) { if(!this.sorted(array, i)) { - if(i + 1 != length) Highlights.markArray(3, i + 1); int index = this.findMax(array, i); if(index == 0) { diff --git a/src/sorts/PatienceSort.java b/src/sorts/PatienceSort.java index 908df65c..c02494e3 100644 --- a/src/sorts/PatienceSort.java +++ b/src/sorts/PatienceSort.java @@ -81,7 +81,7 @@ public void runSort(int[] array, int length, int bucketCount) { Pile newPile = new Pile(); Highlights.markArray(2, x); - Writes.mockWrite(length, newPile.size(), array[x], 1); + Writes.mockWrite(length, Math.min(newPile.size(), length - 1), array[x], 1); newPile.push(array[x]); @@ -91,11 +91,11 @@ public void runSort(int[] array, int length, int bucketCount) { } if (i < 0) i = ~i; if (i != piles.size()) { - Writes.mockWrite(length, piles.get(i).size(), array[x], 0); + Writes.mockWrite(length, Math.min(piles.get(i).size(), length - 1), array[x], 0); piles.get(i).push(array[x]); } else { - Writes.mockWrite(length, piles.size(), newPile.get(0), 0); + Writes.mockWrite(length, Math.min(piles.size(), length - 1), newPile.get(0), 0); piles.add(newPile); } } @@ -106,16 +106,14 @@ public void runSort(int[] array, int length, int bucketCount) { PriorityQueue heap = new PriorityQueue<>(piles); for (int c = 0; c < length; c++) { - Writes.mockWrite(length, heap.size(), 0, 0); + Writes.mockWrite(length, Math.min(heap.size(), length - 1), 0, 0); Pile smallPile = heap.poll(); - Writes.mockWrite(length, smallPile.size(), 0, 0); - Writes.write(array, c, smallPile.pop(), 1, false, false); - - Highlights.markArray(1, c); + Writes.mockWrite(length, Math.min(smallPile.size(), length - 1), 0, 0); + Writes.write(array, c, smallPile.pop(), 1, true, false); if (!smallPile.isEmpty()) { - Writes.mockWrite(length, heap.size(), smallPile.get(0), 0); + Writes.mockWrite(length, Math.min(heap.size(), length - 1), smallPile.get(0), 0); heap.offer(smallPile); } } diff --git a/src/sorts/RecursiveCombSort.java b/src/sorts/RecursiveCombSort.java index 876e9470..2f51344c 100644 --- a/src/sorts/RecursiveCombSort.java +++ b/src/sorts/RecursiveCombSort.java @@ -9,6 +9,7 @@ /* * MIT License +Copyright (c) 2019 w0rthy Copyright (c) 2019 PiotrGrochowski Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -94,4 +95,4 @@ private void finishrecucomb(int[] array, int start, int end, int gap, double sle public void runSort(int[] array, int length, int bucketCount) { this.recursivecomb(array, 0, length, 1, 1); } -} +} \ No newline at end of file diff --git a/src/sorts/RotateMergeSort.java b/src/sorts/RotateMergeSort.java index 426d1a43..36e42298 100644 --- a/src/sorts/RotateMergeSort.java +++ b/src/sorts/RotateMergeSort.java @@ -49,7 +49,8 @@ public RotateMergeSort(Delays delayOps, Highlights markOps, Reads readOps, Write super(delayOps, markOps, readOps, writeOps); this.setSortPromptID("Rotate Merge"); - this.setRunAllID("In-Place Merge Sort with Rotations"); + this.setRunAllID("Rotate Merge Sort"); + //this.setRunAllID("In-Place Merge Sort with Rotations"); this.setReportSortID("In-Place Rotate Mergesort"); this.setCategory("Merge Sorts"); this.isComparisonBased(true); diff --git a/src/sorts/SillySort.java b/src/sorts/SillySort.java index 70f1201d..25a0eecb 100644 --- a/src/sorts/SillySort.java +++ b/src/sorts/SillySort.java @@ -28,12 +28,12 @@ public SillySort(Delays delayOps, Highlights markOps, Reads readOps, Writes writ private void sillySort(int[] array, int i, int j) { int m; + Delays.sleep(1); + if (i < j) { /* find the middle of the array */ m = i + ((j - i) / 2); - Highlights.markArray(3, m); - /* * use this function (recursively) to find put the minimum elements of * each half into the first elements of each half diff --git a/src/sorts/SkaSort.java b/src/sorts/SkaSort_disabled.java similarity index 100% rename from src/sorts/SkaSort.java rename to src/sorts/SkaSort_disabled.java diff --git a/src/sorts/SlowSort.java b/src/sorts/SlowSort.java index 96ad2297..7be2b1d7 100644 --- a/src/sorts/SlowSort.java +++ b/src/sorts/SlowSort.java @@ -25,13 +25,13 @@ public SlowSort(Delays delayOps, Highlights markOps, Reads readOps, Writes write } private void slowSort(int[] A, int i, int j) { - if (i >= j) { + Delays.sleep(1); + + if (i >= j) { return; } - + int m = i + ((j - i) / 2); - - Highlights.markArray(3, m); this.slowSort(A, i, m); this.slowSort(A, m + 1, j); diff --git a/src/sorts/SmartBubbleSort.java b/src/sorts/SmartBubbleSort.java index d097f0ec..1352d402 100644 --- a/src/sorts/SmartBubbleSort.java +++ b/src/sorts/SmartBubbleSort.java @@ -50,16 +50,19 @@ public SmartBubbleSort(Delays delayOps, Highlights markOps, Reads readOps, Write @Override public void runSort(int[] array, int length, int bucketCount) { - for(int i = length - 1; i > 0; i--){ + for(int i = length - 1; i > 0; i--) { + boolean sorted = true; for(int j = 0; j < i; j++) { if(Reads.compare(array[j], array[j + 1]) == 1){ Writes.swap(array, j, j + 1, 0.075, true, false); + sorted = false; } Highlights.markArray(1, j); Highlights.markArray(2, j + 1); Delays.sleep(0.025); } + if(sorted) break; } } } \ No newline at end of file diff --git a/src/sorts/SmartCocktailSort.java b/src/sorts/SmartCocktailSort.java new file mode 100644 index 00000000..df688c6c --- /dev/null +++ b/src/sorts/SmartCocktailSort.java @@ -0,0 +1,90 @@ +package sorts; + +import templates.Sort; +import utils.Delays; +import utils.Highlights; +import utils.Reads; +import utils.Writes; + +/* + * +MIT License + +Copyright (c) 2019 w0rthy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + * + */ + +final public class SmartCocktailSort extends Sort { + public SmartCocktailSort(Delays delayOps, Highlights markOps, Reads readOps, Writes writeOps) { + super(delayOps, markOps, readOps, writeOps); + + this.setSortPromptID("Smart Cocktail"); + this.setRunAllID("Optimized Cocktail Shaker Sort"); + this.setReportSortID("Optimized Cocktail Shaker Sort"); + this.setCategory("Exchange Sorts"); + this.isComparisonBased(true); + this.isBucketSort(false); + this.isRadixSort(false); + this.isUnreasonablySlow(false); + this.setUnreasonableLimit(0); + this.isBogoSort(false); + } + + private void smartCocktailShaker(int[] array, int start, int end, double sleep) { + int i = start; + while(i < ((end / 2) + start)) { + boolean sorted = true; + for(int j = i; j < end + start - i - 1; j++) { + if(Reads.compare(array[j], array[j + 1]) == 1) { + Writes.swap(array, j, j + 1, sleep, true, false); + sorted = false; + } + + Highlights.markArray(1, j); + Highlights.markArray(2, j + 1); + + Delays.sleep(sleep / 2); + } + for(int j = end + start - i - 1; j > i; j--){ + if(Reads.compare(array[j], array[j - 1]) == -1) { + Writes.swap(array, j, j - 1, sleep, true, false); + sorted = false; + } + + Highlights.markArray(1, j); + Highlights.markArray(2, j - 1); + + Delays.sleep(sleep / 2); + } + if(sorted) break; + else i++; + } + } + + public void customSort(int[] array, int start, int end) { + this.smartCocktailShaker(array, start, end, 1); + } + + @Override + public void runSort(int[] array, int length, int bucketCount) { + this.smartCocktailShaker(array, 0, length, 0.1); + } +} \ No newline at end of file diff --git a/src/sorts/SmartGnomeSort.java b/src/sorts/SmartGnomeSort.java index 17d30689..f65aab3c 100644 --- a/src/sorts/SmartGnomeSort.java +++ b/src/sorts/SmartGnomeSort.java @@ -23,19 +23,25 @@ public SmartGnomeSort(Delays delayOps, Highlights markOps, Reads readOps, Writes } // Taken from https://en.wikipedia.org/wiki/Gnome_sort - private void smartGnomeSort(int[] array, int upperBound) { + private void smartGnomeSort(int[] array, int upperBound, double sleep) { int pos = upperBound; while(pos > 0 && Reads.compare(array[pos - 1], array[pos]) == 1) { - Writes.swap(array, pos - 1, pos, 0.05, true, false); + Writes.swap(array, pos - 1, pos, sleep, true, false); pos--; } } + public void customSort(int[] array, int low, int high, double sleep) { + for(int i = low + 1; i < high; i++) { + smartGnomeSort(array, i, sleep); + } + } + @Override public void runSort(int[] array, int length, int bucketCount) { for(int i = 1; i < length; i++) { - smartGnomeSort(array, i); + smartGnomeSort(array, i, 0.05); } } } \ No newline at end of file diff --git a/src/sorts/SqrtSort.java b/src/sorts/SqrtSort.java index fcdd358d..88cf0d2d 100644 --- a/src/sorts/SqrtSort.java +++ b/src/sorts/SqrtSort.java @@ -69,7 +69,8 @@ public SqrtSort(Delays delayOps, Highlights markOps, Reads readOps, Writes write super(delayOps, markOps, readOps, writeOps); this.setSortPromptID("Sqrt"); - this.setRunAllID("Square Root Sort (Block Merge Sort"); + //this.setRunAllID("Square Root Sort (Block Merge Sort)"); + this.setRunAllID("Square Root Sort [Block Merge Sort]"); this.setReportSortID("Sqrtsort"); this.setCategory("Hybrid Sorts"); this.isComparisonBased(true); diff --git a/src/sorts/TimSort.java b/src/sorts/TimSort.java index 6409a925..abf33192 100644 --- a/src/sorts/TimSort.java +++ b/src/sorts/TimSort.java @@ -47,7 +47,7 @@ public TimSort(Delays delayOps, Highlights markOps, Reads readOps, Writes writeO @Override public void runSort(int[] array, int currentLength, int bucketCount) { - this.timSortInstance = new TimSorting(array, currentLength, this.Highlights, this.Reads, this.Writes); + this.timSortInstance = new TimSorting(array, currentLength, this.Delays, this.Highlights, this.Reads, this.Writes); TimSorting.sort(this.timSortInstance, array, currentLength); } diff --git a/src/sorts/TimeSort.java b/src/sorts/TimeSort.java index f108f3fd..50b39f69 100644 --- a/src/sorts/TimeSort.java +++ b/src/sorts/TimeSort.java @@ -46,7 +46,8 @@ public TimeSort(Delays delayOps, Highlights markOps, Reads readOps, Writes write super(delayOps, markOps, readOps, writeOps); this.setSortPromptID("Time"); - this.setRunAllID("Time Sort"); + //this.setRunAllID("Time Sort"); + this.setRunAllID("Time Sort, Mul 10"); this.setReportSortID("Timesort"); this.setCategory("Distributive Sorts"); this.isComparisonBased(false); diff --git a/src/sorts/TournamentSort.java b/src/sorts/TournamentSort.java index f4dc0a03..66aeb9df 100644 --- a/src/sorts/TournamentSort.java +++ b/src/sorts/TournamentSort.java @@ -150,8 +150,7 @@ private void sort(int[] arr, int currentLen) { for (int i = 0; i < currentLen; i++) { Integer selected = copy.get(i); - Writes.write(arr, i, selected, 1, false, false); - Highlights.markArray(1, i); + Writes.write(arr, i, selected, 1, true, false); } } diff --git a/src/sorts/TreeSort.java b/src/sorts/TreeSort.java index f3ad41bb..3e2bc4b9 100644 --- a/src/sorts/TreeSort.java +++ b/src/sorts/TreeSort.java @@ -6,13 +6,12 @@ import utils.Reads; import utils.Writes; -//TODO: Code's an absolute mess. Refactor it at some point. final public class TreeSort extends Sort { public TreeSort(Delays delayOps, Highlights markOps, Reads readOps, Writes writeOps) { super(delayOps, markOps, readOps, writeOps); this.setSortPromptID("Tree"); - this.setRunAllID("Tree Sort"); + this.setRunAllID("Tree Sort (Unbalanced)"); this.setReportSortID("Treesort"); this.setCategory("Insertion Sorts"); this.isComparisonBased(true); @@ -24,122 +23,73 @@ public TreeSort(Delays delayOps, Highlights markOps, Reads readOps, Writes write } // Code retrieved from https://www.geeksforgeeks.org/tree-sort/ - - // Java program to - // implement Tree Sort - final class TreeSorter - { - - // Class containing left and - // right child of current - // node and key value - final class Node - { - int key; - Node left, right; - - public Node(int item) - { - key = item; - left = right = null; - } - } - - // Root of BST - Node root; - - //Index for final result - int index; - - //Field to store current length - int length; - - // Constructor - TreeSorter() - { - root = null; - } + + final private class Node { + int key; + Node left, right; - //Method has to be inside TreeSort to access Node class directly - public Node treeWrite(Node element, int at) { - Node node = new Node(0); - - if(at < length) Highlights.markArray(1, at - 1); - - Writes.changeTempWrites(1); - - Writes.startLap(); - - node = element; - - Writes.stopLap(); - - Delays.sleep(0.25); - - return node; - } - - // This method mainly - // calls insertRec() - void insert(int key) - { - this.root = treeWrite(insertRec(root, key, 1), 1); - } + public Node(int item) { + key = item; + left = right = null; + } + } + + private Node root; + private int index, length; - /* A recursive function to - insert a new key in BST */ - Node insertRec(Node root, int key, int depth) - { + private Node treeWrite(Node element, int at) { + Node node = new Node(0); + + if(at > 0 && at < this.length) Highlights.markArray(1, at - 1); + Writes.changeTempWrites(1); + Writes.startLap(); + node = element; + Writes.stopLap(); + + Delays.sleep(0.25); + + return node; + } - /* If the tree is empty, - return a new node */ - if (root == null) - { - root = treeWrite(new Node(key), 1); - return root; - } + private void insert(int key) { + this.root = this.treeWrite(insertRec(this.root, key, 1), 1); + } + + private Node insertRec(Node root, int key, int depth) { + if (root == null) { + root = treeWrite(new Node(key), 1); + return root; + } - /* Otherwise, recur - down the tree */ - if (Reads.compare(key, root.key) == -1) - root.left = treeWrite(insertRec(root.left, key, depth * 2), depth * 2); - else if (Reads.compare(key, root.key) == 1) - root.right = treeWrite(insertRec(root.right, key, (depth * 2) + 1), (depth * 2) + 1); + if (Reads.compare(key, root.key) == -1) + root.left = treeWrite(insertRec(root.left, key, depth * 2), depth * 2); + else if (Reads.compare(key, root.key) == 1) + root.right = treeWrite(insertRec(root.right, key, (depth * 2) + 1), (depth * 2) + 1); - /* return the root */ - return root; - } + return root; + } - // A function to do - // inorder traversal of BST - void inorderRec(Node root, int[] array) - { - if (root != null) - { - inorderRec(root.left, array); - Writes.write(array, this.index++, root.key, 1, true, false); - inorderRec(root.right, array); - } - } + private void traverseRec(Node root, int[] array) { + if (root != null) { + this.traverseRec(root.left, array); + Writes.write(array, this.index++, root.key, 1, true, false); + this.traverseRec(root.right, array); + } + } - void treeins(int arr[], int length) - { - for(int i = 0; i < length; i++) - { - Highlights.markArray(2, i); - insert(arr[i]); - } - Highlights.clearMark(2); - } - - } + private void treeIns(int arr[]) { + for(int i = 0; i < this.length; i++) { + Highlights.markArray(2, i); + this.insert(arr[i]); + } + Highlights.clearMark(2); + } @Override public void runSort(int[] array, int currentLength, int bucketCount) { - TreeSorter tree = new TreeSorter(); - tree.length = currentLength; - tree.treeins(array, tree.length); - tree.index = 0; - tree.inorderRec(tree.root, array); + this.length = currentLength; + this.treeIns(array); + this.index = 0; + this.traverseRec(this.root, array); } } \ No newline at end of file diff --git a/src/sorts/WikiSort.java b/src/sorts/WikiSort.java index 60bfff00..a47fe131 100644 --- a/src/sorts/WikiSort.java +++ b/src/sorts/WikiSort.java @@ -59,7 +59,8 @@ public WikiSort(Delays delayOps, Highlights markOps, Reads readOps, Writes write super(delayOps, markOps, readOps, writeOps); this.setSortPromptID("Wiki"); - this.setRunAllID("Wiki Sort (Block Merge Sort)"); + //this.setRunAllID("Wiki Sort (Block Merge Sort)"); + this.setRunAllID("Wiki Sort [Block Merge Sort]"); this.setReportSortID("Wikisort"); this.setCategory("Hybrid Sorts"); this.isComparisonBased(true); @@ -75,7 +76,7 @@ public void runSort(int[] array, int currentLength, int bucketCount) { this.cache = 0; this.insertionSort = new InsertionSort(this.Delays, this.Highlights, this.Reads, this.Writes); - this.wikiSortInstance = new WikiSorting(this.insertionSort, this.Highlights, this.Reads, this.Writes, this.cache); + this.wikiSortInstance = new WikiSorting(this.insertionSort, this.Delays, this.Highlights, this.Reads, this.Writes, this.cache); WikiSorting.sort(this.wikiSortInstance, array, currentLength); } diff --git a/src/soundfont/SFXFetcher.java b/src/soundfont/SFXFetcher.java new file mode 100644 index 00000000..25ec52a9 --- /dev/null +++ b/src/soundfont/SFXFetcher.java @@ -0,0 +1,15 @@ +package soundfont; + +import java.io.InputStream; + +final public class SFXFetcher { + private InputStream sfxFile; + + public SFXFetcher() { + this.sfxFile = this.getClass().getResourceAsStream("sfx.sf2"); + } + + public InputStream getSFXFile() { + return this.sfxFile; + } +} \ No newline at end of file diff --git a/src/soundfont/sfx.sf2 b/src/soundfont/sfx.sf2 new file mode 100644 index 00000000..6445a80a Binary files /dev/null and b/src/soundfont/sfx.sf2 differ diff --git a/src/templates/BinaryInsertionSorting.java b/src/templates/BinaryInsertionSorting.java index 70a110d3..6e28953b 100644 --- a/src/templates/BinaryInsertionSorting.java +++ b/src/templates/BinaryInsertionSorting.java @@ -43,7 +43,9 @@ protected void binaryInsertSort(int[] array, int start, int end, double compSlee while (lo < hi) { int mid = lo + ((hi - lo) / 2); // avoid int overflow! + Highlights.markArray(1, lo); Highlights.markArray(2, mid); + Highlights.markArray(3, hi); Delays.sleep(compSleep); @@ -55,6 +57,8 @@ protected void binaryInsertSort(int[] array, int start, int end, double compSlee } } + Highlights.clearMark(3); + // item has to go into position lo int j = i - 1; diff --git a/src/templates/BogoSorting.java b/src/templates/BogoSorting.java index 706a3c32..55ae58d9 100644 --- a/src/templates/BogoSorting.java +++ b/src/templates/BogoSorting.java @@ -37,12 +37,12 @@ protected BogoSorting(Delays delayOps, Highlights markOps, Reads readOps, Writes } private static int randomPosition(int length, int offset) { - return (int) ((Math.random() * (length - offset)) + offset); + return (int) (Math.random() * (length - offset)); } protected void bogoSwap(int[] array, int length, int offset){ for(int i = offset; i < length; i++) { - Writes.swap(array, i, BogoSorting.randomPosition(length, offset), 0, true, false); + Writes.swap(array, i, BogoSorting.randomPosition(length, i) + i, 0, true, false); } } @@ -60,8 +60,8 @@ protected boolean bogoIsSorted(int[] array, int length){ protected boolean isMinSorted(int[] array, int length, int offset) { Highlights.clearAllMarks(); - Highlights.markArray(2, offset); - Highlights.markArray(3, length); + //Highlights.markArray(2, offset); + //Highlights.markArray(3, length); for(int i = offset + 1; i < length; i++) { Highlights.markArray(1, i); @@ -77,8 +77,8 @@ protected boolean isMinSorted(int[] array, int length, int offset) { protected boolean isMaxSorted(int[] array, int minIterator, int maxIterator) { Highlights.clearAllMarks(); - Highlights.markArray(2, minIterator); - Highlights.markArray(3, maxIterator); + //Highlights.markArray(2, minIterator); + //Highlights.markArray(3, maxIterator); for(int i = maxIterator; i >= minIterator; i--) { Highlights.markArray(1, i); diff --git a/src/templates/CombSorting.java b/src/templates/CombSorting.java index 980331f9..ce22b5f3 100644 --- a/src/templates/CombSorting.java +++ b/src/templates/CombSorting.java @@ -75,7 +75,7 @@ protected void combSort(ArrayVisualizer ArrayVisualizer, int[] array, int length //ArrayVisualizer.setCurrentGap(gap); if(gap == 1) - Delays.setSleepRatio(10); + Delays.setSleepRatio(3); } swapped = false; diff --git a/src/templates/GrailSorting.java b/src/templates/GrailSorting.java index ca975090..7a3027d4 100644 --- a/src/templates/GrailSorting.java +++ b/src/templates/GrailSorting.java @@ -1,6 +1,6 @@ package templates; -import sorts.InsertionSort; +import sorts.SmartGnomeSort; import utils.Delays; import utils.Highlights; import utils.Reads; @@ -50,11 +50,11 @@ this software and associated documentation files (the "Software"), to deal in /* */ /*********************************************************/ -final class GrailState { +final class GrailPair { private int leftOverLen; private int leftOverFrag; - protected GrailState(int len, int frag) { + protected GrailPair(int len, int frag) { this.leftOverLen = len; this.leftOverFrag = frag; } @@ -69,7 +69,7 @@ protected int getLeftOverFrag() { } public abstract class GrailSorting extends Sort { - private InsertionSort insertSorter; + private SmartGnomeSort grailInsertSorter; final private int grailStaticBufferLen = 32; //Buffer length changed due to less numbers in this program being sorted than what Mr. Astrelin used for testing. @@ -84,7 +84,7 @@ protected int getStaticBuffer() { private void grailSwap(int[] arr, int a, int b) { Writes.swap(arr, a, b, 1, true, false); } - + private void grailMultiSwap(int[] arr, int a, int b, int swapsLeft) { while(swapsLeft != 0) { this.grailSwap(arr, a++, b++); @@ -107,7 +107,7 @@ private void grailRotate(int[] array, int pos, int lenA, int lenB) { } private void grailInsertSort(int[] arr, int pos, int len) { - insertSorter.customInsertSort(arr, pos, len, 0.25, false); + grailInsertSorter.customSort(arr, pos, len, 0.75); } //boolean argument determines direction @@ -126,7 +126,7 @@ private int grailBinSearch(int[] arr, int pos, int len, int keyPos, boolean isLe right = mid; } else left = mid; } - Highlights.markArray(1, mid); + Highlights.markArray(1, pos + mid); } return right; } @@ -138,7 +138,7 @@ private int grailFindKeys(int[] arr, int pos, int len, int numKeys) { while(dist < len && foundKeys < numKeys) { //Binary Search left int loc = this.grailBinSearch(arr, pos + firstKey, foundKeys, pos + dist, true); - if(loc == foundKeys || Reads.compare(arr[pos + dist], arr[pos + (firstKey + loc)]) != 0) { + if(loc == foundKeys || Reads.compare(arr[pos + dist], arr[pos + (firstKey + loc)]) != 0) { this.grailRotate(arr, pos + firstKey, foundKeys, dist - (firstKey + foundKeys)); firstKey = dist - foundKeys; this.grailRotate(arr, pos + (firstKey + loc), foundKeys - loc, 1); @@ -218,11 +218,11 @@ private void grailMergeBuffersLeft(int[] arr, int keysPos, int midkey, int pos, leftOverLen = blockLen; } else { if(havebuf) { - GrailState results = this.grailSmartMergeWithBuffer(arr, pos + restToProcess, leftOverLen, leftOverFrag, blockLen); + GrailPair results = this.grailSmartMergeWithBuffer(arr, pos + restToProcess, leftOverLen, leftOverFrag, blockLen); leftOverLen = results.getLeftOverLen(); leftOverFrag = results.getLeftOverFrag(); } else { - GrailState results = this.grailSmartMergeWithoutBuffer(arr, pos + restToProcess, leftOverLen, leftOverFrag, blockLen); + GrailPair results = this.grailSmartMergeWithoutBuffer(arr, pos + restToProcess, leftOverLen, leftOverFrag, blockLen); leftOverLen = results.getLeftOverLen(); leftOverFrag = results.getLeftOverFrag(); } @@ -297,8 +297,8 @@ private void grailMergeRight(int[] arr, int pos, int leftLen, int rightLen, int } //returns the leftover length, then the leftover fragment - private GrailState grailSmartMergeWithoutBuffer(int[] arr, int pos, int leftOverLen, int leftOverFrag, int regBlockLen) { - if(regBlockLen == 0) return new GrailState(leftOverLen, leftOverFrag); + private GrailPair grailSmartMergeWithoutBuffer(int[] arr, int pos, int leftOverLen, int leftOverFrag, int regBlockLen) { + if(regBlockLen == 0) return new GrailPair(leftOverLen, leftOverFrag); int len1 = leftOverLen; int len2 = regBlockLen; @@ -321,7 +321,7 @@ private GrailState grailSmartMergeWithoutBuffer(int[] arr, int pos, int leftOver len2 -= foundLen; } if(len2 == 0) { - return new GrailState(len1, leftOverFrag); + return new GrailPair(len1, leftOverFrag); } do { pos++; @@ -329,11 +329,11 @@ private GrailState grailSmartMergeWithoutBuffer(int[] arr, int pos, int leftOver } while(len1 != 0 && Reads.compare(arr[pos], arr[pos + len1]) - typeFrag < 0); } } - return new GrailState(len2, typeFrag); + return new GrailPair(len2, typeFrag); } //returns the leftover length, then the leftover fragment - private GrailState grailSmartMergeWithBuffer(int[] arr, int pos, int leftOverLen, int leftOverFrag, int blockLen) { + private GrailPair grailSmartMergeWithBuffer(int[] arr, int pos, int leftOverLen, int leftOverFrag, int blockLen) { int dist = 0 - blockLen, left = 0, right = leftOverLen, leftEnd = right, rightEnd = right + blockLen; int typeFrag = 1 - leftOverFrag; // 1 if inverted @@ -356,14 +356,14 @@ private GrailState grailSmartMergeWithBuffer(int[] arr, int pos, int leftOverLen length = rightEnd - right; fragment = typeFrag; } - return new GrailState(length, fragment); + return new GrailPair(length, fragment); } /***** Sort With Extra Buffer *****/ //returns the leftover length, then the leftover fragment - private GrailState grailSmartMergeWithXBuf(int[] arr, int pos, int leftOverLen, int leftOverFrag, int blockLen) { + private GrailPair grailSmartMergeWithXBuf(int[] arr, int pos, int leftOverLen, int leftOverFrag, int blockLen) { int dist = 0 - blockLen, left = 0, right = leftOverLen, leftEnd = right, rightEnd = right + blockLen; int typeFrag = 1 - leftOverFrag; // 1 if inverted @@ -388,7 +388,7 @@ private GrailState grailSmartMergeWithXBuf(int[] arr, int pos, int leftOverLen, length = rightEnd - right; fragment = typeFrag; } - return new GrailState(length, fragment); + return new GrailPair(length, fragment); } // arr[dist..-1] - free, arr[0, leftEnd - 1] ++ arr[leftEnd, leftEnd + rightEnd - 1] @@ -448,7 +448,7 @@ private void grailMergeBuffersLeftWithXBuf(int[] arr, int keysPos, int midkey, i restToProcess = processIndex; leftOverLen = regBlockLen; } else { - GrailState results = this.grailSmartMergeWithXBuf(arr, pos + restToProcess, leftOverLen, leftOverFrag, regBlockLen); + GrailPair results = this.grailSmartMergeWithXBuf(arr, pos + restToProcess, leftOverLen, leftOverFrag, regBlockLen); leftOverLen = results.getLeftOverLen(); leftOverFrag = results.getLeftOverFrag(); } @@ -581,7 +581,7 @@ private void grailCombineBlocks(int[] arr, int keyPos, int pos, int len, int bui for(int rightIndex = index; rightIndex < blockCount; rightIndex++) { int rightComp = Reads.compare(arr[blockPos + leftIndex * regBlockLen], - arr[blockPos + rightIndex * regBlockLen]); + arr[blockPos + rightIndex * regBlockLen]); if(rightComp > 0 || (rightComp == 0 && Reads.compare(arr[keyPos + leftIndex], arr[keyPos + rightIndex]) > 0)) { leftIndex = rightIndex; } @@ -652,7 +652,7 @@ protected void grailLazyStableSort(int[] arr, int pos, int len) { } protected void grailCommonSort(int[] arr, int pos, int len, int[] buffer, int bufferPos, int bufferLen) { - insertSorter = new InsertionSort(this.Delays, this.Highlights, this.Reads, this.Writes); + this.grailInsertSorter = new SmartGnomeSort(Delays, Highlights, Reads, Writes); if(len <= 16) { this.grailInsertSort(arr, pos, len); diff --git a/src/templates/HeapSorting.java b/src/templates/HeapSorting.java index 79cdd5d8..c0f2dfa5 100644 --- a/src/templates/HeapSorting.java +++ b/src/templates/HeapSorting.java @@ -33,8 +33,11 @@ private void siftDown(int[] array, int root, int dist, int start, double sleep, if (leaf < dist && Reads.compare(array[start + leaf - 1], array[start + leaf]) == compareVal) { leaf++; } + Highlights.markArray(1, start + root - 1); + Highlights.markArray(2, start + leaf - 1); + Delays.sleep(sleep); if (Reads.compare(array[start + root - 1], array[start + leaf - 1]) == compareVal) { - Writes.swap(array, start + root - 1, start + leaf - 1, sleep, true, false); + Writes.swap(array, start + root - 1, start + leaf - 1, 0, true, false); root = leaf; } else break; diff --git a/src/templates/HolyGrailSorting.java b/src/templates/HolyGrailSorting.java index f59f898b..b0678998 100644 --- a/src/templates/HolyGrailSorting.java +++ b/src/templates/HolyGrailSorting.java @@ -109,52 +109,52 @@ private void grailMultiSwap(int[] arr, int a, int b, int swapsLeft) { // Copy element at pos, shift elements from pos + 1 to pos + len to the left by 1, // and paste copied element at pos + len. - private void grailForwardShift(int[] array, int pos, int len) { - int temp = array[pos]; + private void grailForwardShift(int[] array, int index, int shiftsLeft) { + int temp = array[index]; - while(len > 0) { - Writes.write(array, pos, array[pos + 1], 1, true, false); - pos++; - len--; + while(shiftsLeft > 0) { + Writes.write(array, index, array[index + 1], 1, true, false); + index++; + shiftsLeft--; } - Writes.write(array, pos, temp, 1, true, false); + Writes.write(array, index, temp, 1, true, false); } // Copy element at pos + len, shift elements from pos to pos + len - 1 to the right by 1, // and paste copied element at pos. - private void grailBackwardShift(int[] array, int pos, int len) { - int temp = array[pos + len]; + private void grailBackwardShift(int[] array, int index, int shiftsLeft) { + int temp = array[index + shiftsLeft]; - while(len > 0) { - Writes.write(array, pos + len, array[pos + len - 1], 1, true, false); - len--; + while(shiftsLeft > 0) { + Writes.write(array, index + shiftsLeft, array[(index - 1) + shiftsLeft], 1, true, false); + shiftsLeft--; } - Writes.write(array, pos, temp, 1, true, false); + Writes.write(array, index, temp, 1, true, false); } - private void grailRotate(int[] array, int pos, int indexA, int indexB) { - while(indexA != 0 && indexB != 0) { - if(indexA <= indexB) { - if(indexA != 1) { - this.grailMultiSwap(array, pos, pos + indexA, indexA); - pos += indexA; - indexB -= indexA; + private void grailRotate(int[] array, int leftIndex, int rightIndex, int target) { + while(rightIndex != 0 && target != 0) { + if(rightIndex <= target) { + if(rightIndex != 1) { + this.grailMultiSwap(array, leftIndex, leftIndex + rightIndex, rightIndex); + leftIndex += rightIndex; + target -= rightIndex; } else { Highlights.clearMark(2); - this.grailForwardShift(array, pos, indexB); - indexB = 0; + this.grailForwardShift(array, leftIndex, target); + target = 0; } } else { - if(indexB != 1) { - this.grailMultiSwap(array, pos + (indexA - indexB), pos + indexA, indexB); - indexA -= indexB; + if(target != 1) { + this.grailMultiSwap(array, leftIndex + (rightIndex - target), leftIndex + rightIndex, target); + rightIndex -= target; } else { Highlights.clearMark(2); - this.grailBackwardShift(array, pos, indexA); - indexA = 0; + this.grailBackwardShift(array, leftIndex, rightIndex); + rightIndex = 0; } } } @@ -204,10 +204,12 @@ private int grailBinSearch(int[] arr, int pos, int len, int keyPos, boolean isLe right = mid; } else left = mid; } + Highlights.markArray(1, pos + mid); } return right; } + //TODO: *Somehow* make this more efficient. // cost: 2 * len + numKeys^2 / 2 private int grailFindKeys(int[] arr, int pos, int len, int numKeys) { int dist = 1, foundKeys = 1, firstKey = 0; // first key is always here @@ -230,6 +232,19 @@ private int grailFindKeys(int[] arr, int pos, int len, int numKeys) { return foundKeys; } + private boolean grailCheckOddPairs(int[] arr, int pos, int len) { + for(int dist = 2; dist < (len - 2); dist += 2) { + Highlights.markArray(1, pos + dist - 1); + Highlights.markArray(2, pos + dist); + Delays.sleep(1); + + if(Reads.compare(arr[pos + (dist - 1)], arr[pos + dist]) > 0) { + return false; + } + } + return true; + } + // cost: min(len1, len2)^2 + max(len1, len2) private void grailMergeWithoutBuffer(int[] arr, int pos, int len1, int len2) { if(len1 < len2) { @@ -295,11 +310,11 @@ private void grailMergeBuffersLeft(int[] arr, int keysPos, int midkey, int pos, leftOverLen = blockLen; } else { if(havebuf) { - GrailState results = this.grailSmartMergeWithBuffer(arr, pos + restToProcess, leftOverLen, leftOverFrag, blockLen); + GrailPair results = this.grailSmartMergeWithBuffer(arr, pos + restToProcess, leftOverLen, leftOverFrag, blockLen); leftOverLen = results.getLeftOverLen(); leftOverFrag = results.getLeftOverFrag(); } else { - GrailState results = this.grailSmartMergeWithoutBuffer(arr, pos + restToProcess, leftOverLen, leftOverFrag, blockLen); + GrailPair results = this.grailSmartMergeWithoutBuffer(arr, pos + restToProcess, leftOverLen, leftOverFrag, blockLen); leftOverLen = results.getLeftOverLen(); leftOverFrag = results.getLeftOverFrag(); } @@ -374,8 +389,8 @@ private void grailMergeRight(int[] arr, int pos, int leftLen, int rightLen, int } //returns the leftover length, then the leftover fragment - private GrailState grailSmartMergeWithoutBuffer(int[] arr, int pos, int leftOverLen, int leftOverFrag, int regBlockLen) { - if(regBlockLen == 0) return new GrailState(leftOverLen, leftOverFrag); + private GrailPair grailSmartMergeWithoutBuffer(int[] arr, int pos, int leftOverLen, int leftOverFrag, int regBlockLen) { + if(regBlockLen == 0) return new GrailPair(leftOverLen, leftOverFrag); int len1 = leftOverLen; int len2 = regBlockLen; @@ -398,7 +413,7 @@ private GrailState grailSmartMergeWithoutBuffer(int[] arr, int pos, int leftOver len2 -= foundLen; } if(len2 == 0) { - return new GrailState(len1, leftOverFrag); + return new GrailPair(len1, leftOverFrag); } do { pos++; @@ -406,11 +421,11 @@ private GrailState grailSmartMergeWithoutBuffer(int[] arr, int pos, int leftOver } while(len1 != 0 && Reads.compare(arr[pos], arr[pos + len1]) - typeFrag < 0); } } - return new GrailState(len2, typeFrag); + return new GrailPair(len2, typeFrag); } //returns the leftover length, then the leftover fragment - private GrailState grailSmartMergeWithBuffer(int[] arr, int pos, int leftOverLen, int leftOverFrag, int blockLen) { + private GrailPair grailSmartMergeWithBuffer(int[] arr, int pos, int leftOverLen, int leftOverFrag, int blockLen) { int dist = 0 - blockLen, left = 0, right = leftOverLen, leftEnd = right, rightEnd = right + blockLen; int typeFrag = 1 - leftOverFrag; // 1 if inverted @@ -433,14 +448,14 @@ private GrailState grailSmartMergeWithBuffer(int[] arr, int pos, int leftOverLen length = rightEnd - right; fragment = typeFrag; } - return new GrailState(length, fragment); + return new GrailPair(length, fragment); } /***** Sort With Extra Buffer *****/ //returns the leftover length, then the leftover fragment - private GrailState grailSmartMergeWithXBuf(int[] arr, int pos, int leftOverLen, int leftOverFrag, int blockLen) { + private GrailPair grailSmartMergeWithXBuf(int[] arr, int pos, int leftOverLen, int leftOverFrag, int blockLen) { int dist = 0 - blockLen, left = 0, right = leftOverLen, leftEnd = right, rightEnd = right + blockLen; int typeFrag = 1 - leftOverFrag; // 1 if inverted @@ -465,7 +480,7 @@ private GrailState grailSmartMergeWithXBuf(int[] arr, int pos, int leftOverLen, length = rightEnd - right; fragment = typeFrag; } - return new GrailState(length, fragment); + return new GrailPair(length, fragment); } // arr[dist..-1] - free, arr[0, leftEnd - 1] ++ arr[leftEnd, leftEnd + rightEnd - 1] @@ -525,7 +540,7 @@ private void grailMergeBuffersLeftWithXBuf(int[] arr, int keysPos, int midkey, i restToProcess = processIndex; leftOverLen = regBlockLen; } else { - GrailState results = this.grailSmartMergeWithXBuf(arr, pos + restToProcess, leftOverLen, leftOverFrag, regBlockLen); + GrailPair results = this.grailSmartMergeWithXBuf(arr, pos + restToProcess, leftOverLen, leftOverFrag, regBlockLen); leftOverLen = results.getLeftOverLen(); leftOverFrag = results.getLeftOverFrag(); } @@ -555,7 +570,7 @@ private void grailMergeBuffersLeftWithXBuf(int[] arr, int keysPos, int midkey, i // output: first buildLen elements are buffer, blocks 2 * buildLen and last subblock sorted // if array is already sorted, return false - private void grailBuildBlocks(int[] arr, int pos, int len, int buildLen, + private boolean grailBuildBlocks(int[] arr, int pos, int len, int buildLen, int[] extbuf, int bufferPos, int extBufLen) { int buildBuf = buildLen < extBufLen ? buildLen : extBufLen; @@ -593,15 +608,34 @@ private void grailBuildBlocks(int[] arr, int pos, int len, int buildLen, Writes.arraycopy(extbuf, bufferPos, arr, pos + len, buildBuf, 1, true, false); } else { + boolean evenPairsSorted = true; + for(int dist = 1; dist < len; dist += 2) { extraDist = 0; - if(Reads.compare(arr[pos + (dist - 1)], arr[pos + dist]) > 0) extraDist = 1; + if(Reads.compare(arr[pos + (dist - 1)], arr[pos + dist]) > 0) { + evenPairsSorted = false; + extraDist = 1; + } this.grailSwap(arr, pos + (dist - 3), pos + (dist - 1 + extraDist)); this.grailSwap(arr, pos + (dist - 2), pos + (dist - extraDist)); } - if(len % 2 != 0) this.grailSwap(arr, pos + (len - 1), pos + (len - 3)); + if(len % 2 != 0) this.grailSwap(arr, pos + (len - 1), pos + (len - 1) - 2); pos -= 2; part = 2; + + if(evenPairsSorted) { + pos += 2; + if(this.grailCheckOddPairs(arr, pos, len)) { + while((len - 1) - 2 >= 0) { + this.grailSwap(arr, pos + (len - 1), pos + ((len--) - 1) - 2); + } + if(Reads.compare(arr[pos], arr[pos + 1]) > 0) { + this.grailSwap(arr, pos, pos + 1); + } + return false; + } + pos -= 2; + } } for(; part < buildLen; part *= 2) { @@ -629,6 +663,8 @@ private void grailBuildBlocks(int[] arr, int pos, int len, int buildLen, leftOverPos -= 2 * buildLen; this.grailMergeRight(arr, pos + leftOverPos, buildLen, buildLen, buildLen); } + + return true; } // keys are on the left of arr. Blocks of length buildLen combined. We'll combine them in pairs @@ -826,14 +862,14 @@ protected void grailCommonSort(int[] arr, int pos, int len, int[] buffer, int bu boolean continueSort = true; if(bufferEnabled) { - //continueSort = - this.grailBuildBlocks(arr, pos + dist, len - dist, buildLen, buffer, bufferPos, bufferLen); + continueSort = this.grailBuildBlocks(arr, pos + dist, len - dist, buildLen, buffer, bufferPos, bufferLen); } else { - //continueSort = - this.grailBuildBlocks(arr, pos + dist, len - dist, buildLen, null, bufferPos, 0); + continueSort = this.grailBuildBlocks(arr, pos + dist, len - dist, buildLen, null, bufferPos, 0); } - + + System.out.println(continueSort); + if(continueSort) { boolean mergeForward = true; @@ -869,9 +905,11 @@ protected void grailCommonSort(int[] arr, int pos, int len, int[] buffer, int bu Highlights.clearMark(2); } - } - this.grailInsertSort(arr, pos, dist); + this.grailInsertSort(arr, pos, dist); + } + + //TODO: O(n) best-case DOES NOT WORK for key counts LESS THAN (2 * sqrt(n)) this.grailMergeWithoutBuffer(arr, pos, dist, len - dist); /* diff --git a/src/templates/JEnhancedOptionPane.java b/src/templates/JEnhancedOptionPane.java new file mode 100644 index 00000000..1fddea90 --- /dev/null +++ b/src/templates/JEnhancedOptionPane.java @@ -0,0 +1,32 @@ +package templates; + +import java.awt.HeadlessException; + +import javax.swing.JDialog; +import javax.swing.JOptionPane; +import javax.swing.UIManager; + +//Many thanks to Freek de Bruijn on StackOverflow for providing a custom JOptionPane. +//https://stackoverflow.com/questions/14407804/how-to-change-the-default-text-of-buttons-in-joptionpane-showinputdialog?noredirect=1&lq=1 +final public class JEnhancedOptionPane extends JOptionPane { + /** + * + */ + private static final long serialVersionUID = 1L; + + public static String showInputDialog(final Object message, final Object[] options) throws HeadlessException { + final JOptionPane pane = new JOptionPane(message, QUESTION_MESSAGE, + OK_CANCEL_OPTION, null, + options, null); + pane.setWantsInput(true); + pane.setComponentOrientation((getRootFrame()).getComponentOrientation()); + pane.setMessageType(QUESTION_MESSAGE); + pane.selectInitialValue(); + final String title = UIManager.getString("OptionPane.inputDialogTitle", null); + final JDialog dialog = pane.createDialog(null, title); + dialog.setVisible(true); + dialog.dispose(); + final Object value = pane.getInputValue(); + return (value == UNINITIALIZED_VALUE) ? null : (String) value; + } +} \ No newline at end of file diff --git a/src/templates/JErrorPane.java b/src/templates/JErrorPane.java new file mode 100644 index 00000000..5d76f4cd --- /dev/null +++ b/src/templates/JErrorPane.java @@ -0,0 +1,32 @@ +package templates; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import javax.swing.JOptionPane; +import javax.swing.JTextArea; + +final public class JErrorPane extends JOptionPane { + /** + * + */ + private static final long serialVersionUID = 1L; + + public volatile static boolean errorMessageActive = false; + + public static void invokeErrorMessage(Exception e) { + errorMessageActive = true; + + StringWriter exceptionString = new StringWriter(); + e.printStackTrace(new PrintWriter(exceptionString)); + String printException = exceptionString.toString(); + + JTextArea error = new JTextArea(); + error.setText(printException); + error.setCaretPosition(0); + error.setEditable(false); + + JOptionPane.showMessageDialog(null, error, "Error", JOptionPane.ERROR_MESSAGE); + errorMessageActive = false; + } +} \ No newline at end of file diff --git a/src/templates/MergeSorting.java b/src/templates/MergeSorting.java index 16bd95f4..38679195 100644 --- a/src/templates/MergeSorting.java +++ b/src/templates/MergeSorting.java @@ -49,7 +49,7 @@ private void merge(int[] array, int start, int mid, int end, boolean binary) { return; } else if(end - start == 32 && binary) { - binaryInserter.customBinaryInsert(array, start, end, 0.25); + binaryInserter.customBinaryInsert(array, start, end, 0.333); } else { int[] tmp = new int[end - start]; @@ -60,30 +60,28 @@ else if(end - start == 32 && binary) { for(int nxt = 0; nxt < tmp.length; nxt++){ if(low >= mid && high >= end) break; + Highlights.markArray(1, low); + Highlights.markArray(2, high); + if(low < mid && high >= end){ - Writes.write(tmp, nxt, array[low++], 0, false, true); + Highlights.clearMark(2); + Writes.write(tmp, nxt, array[low++], 1, false, true); } else if(low >= mid && high < end){ - Writes.write(tmp, nxt, array[high++], 0, false, true); + Highlights.clearMark(1); + Writes.write(tmp, nxt, array[high++], 1, false, true); } - else if(Reads.compare(array[low], array[high]) == -1){ - Writes.write(tmp, nxt, array[low++], 0, false, true); + else if(Reads.compare(array[low], array[high]) <= 0){ + Writes.write(tmp, nxt, array[low++], 1, false, true); } else{ - Writes.write(tmp, nxt, array[high++], 0, false, true); + Writes.write(tmp, nxt, array[high++], 1, false, true); } - - Highlights.markArray(1, low); - Highlights.markArray(2, high); - - Delays.sleep(1); } - Highlights.clearMark(2); for(int i = 0; i < tmp.length; i++){ - Writes.write(array, start + i, tmp[i], 1, false, false); - Highlights.markArray(1, start + i); + Writes.write(array, start + i, tmp[i], 1, true, false); } } } @@ -92,7 +90,7 @@ protected void mergeSort(int[] array, int length, boolean binary) { binaryInserter = new BinaryInsertionSort(this.Delays, this.Highlights, this.Reads, this.Writes); if(length < 32 && binary) { - binaryInserter.customBinaryInsert(array, 0, length, 0.25); + binaryInserter.customBinaryInsert(array, 0, length, 0.333); return; } diff --git a/src/templates/MultipleSortThread.java b/src/templates/MultipleSortThread.java index 83d03761..141ac12c 100644 --- a/src/templates/MultipleSortThread.java +++ b/src/templates/MultipleSortThread.java @@ -22,6 +22,8 @@ public abstract class MultipleSortThread { protected volatile int sortCount; protected volatile int sortNumber; + protected volatile int categoryCount; + public MultipleSortThread(ArrayVisualizer ArrayVisualizer) { this.ArrayVisualizer = ArrayVisualizer; this.ArrayManager = ArrayVisualizer.getArrayManager(); @@ -33,8 +35,13 @@ public MultipleSortThread(ArrayVisualizer ArrayVisualizer) { this.Timer = ArrayVisualizer.getTimer(); } - protected synchronized void RunIndividualSort(Sort sort, int bucketCount, int[] array, double speed) throws InterruptedException { + protected synchronized void runIndividualSort(Sort sort, int bucketCount, int[] array, int length, double speed) throws InterruptedException { Delays.setSleepRatio(2.5); + + if(length != ArrayVisualizer.getCurrentLength()) { + ArrayVisualizer.setCurrentLength(length); + } + ArrayManager.refreshArray(array, ArrayVisualizer.getCurrentLength(), this.ArrayVisualizer); ArrayVisualizer.setHeading(sort.getRunAllID() + " (Sort " + this.sortNumber + " of " + this.sortCount + ")"); @@ -49,4 +56,23 @@ protected synchronized void RunIndividualSort(Sort sort, int bucketCount, int[] this.sortNumber++; } + + protected abstract void executeSortList(int[] array) throws Exception; + protected abstract void runThread(int[] array, int current, int total, boolean runAllActive) throws Exception; + + public synchronized void reportCategorySorts(int[] array) throws Exception { + this.runThread(array, 0, 0, false); + } + + public synchronized void reportAllSorts(int[] array, int current, int total) throws Exception { + this.runThread(array, current, total, true); + } + + public int getSortCount() { + return this.sortCount; + } + + public int getCategoryCount() { + return this.categoryCount; + } } \ No newline at end of file diff --git a/src/templates/ShellSorting.java b/src/templates/ShellSorting.java index b6748f6c..a253620b 100644 --- a/src/templates/ShellSorting.java +++ b/src/templates/ShellSorting.java @@ -53,18 +53,22 @@ protected void shellSort(ArrayVisualizer ArrayVisualizer, int[] array, int lengt Highlights.markArray(1, j); Highlights.markArray(2, j - h); - - Delays.sleep(0.2); while (j >= h && Reads.compare(array[j - h], v) == 1) { + Writes.write(array, j, array[j - h], 1, false, false); + j -= h; + Highlights.markArray(1, j); - Highlights.markArray(2, j - h); - Writes.write(array, j, array[j - h], 0.5, false, false); - j -= h; + if(j - h >= 0) { + Highlights.markArray(2, j - h); + } + else { + Highlights.clearMark(2); + } } - Writes.write(array, j, v, 0.5, true, false); + Writes.write(array, j, v, 1, true, false); } } } @@ -78,18 +82,22 @@ protected void shellSort(ArrayVisualizer ArrayVisualizer, int[] array, int lengt Highlights.markArray(1, j); Highlights.markArray(2, j - h); - - Delays.sleep(0.2); while (j >= h && Reads.compare(array[j - h], v) == 1) { + Writes.write(array, j, array[j - h], 1, false, false); + j -= h; + Highlights.markArray(1, j); - Highlights.markArray(2, j - h); - Writes.write(array, j, array[j - h], 0.5, false, false); - j -= h; + if(j - h >= 0) { + Highlights.markArray(2, j - h); + } + else { + Highlights.clearMark(2); + } } - Writes.write(array, j, v, 0.5, true, false); + Writes.write(array, j, v, 1, true, false); } } } diff --git a/src/templates/TimSorting.java b/src/templates/TimSorting.java index 6c580de9..c68a98cf 100644 --- a/src/templates/TimSorting.java +++ b/src/templates/TimSorting.java @@ -1,5 +1,8 @@ package templates; +import javax.swing.text.Highlighter.Highlight; + +import utils.Delays; import utils.Highlights; import utils.Reads; import utils.Writes; @@ -57,6 +60,7 @@ */ final public class TimSorting { + private Delays Delays; private Highlights Highlights; private Reads Reads; private Writes Writes; @@ -133,10 +137,11 @@ public static int getMinRun() { * * @param a the array to be sorted */ - public TimSorting(int[] a, int currentLen, Highlights markOps, Reads readOps, Writes writeOps) { + public TimSorting(int[] a, int currentLen, Delays delayOps, Highlights markOps, Reads readOps, Writes writeOps) { this.a = a; this.len = currentLen; + this.Delays = delayOps; this.Highlights = markOps; this.Reads = readOps; this.Writes = writeOps; @@ -309,12 +314,18 @@ private static int countRunAndMakeAscending(TimSorting ts, int[] a, int lo, int // Find end of run, and reverse range if descending if (ts.Reads.compare(a[runHi++], a[lo]) < 0) { // Descending - while(runHi < hi && ts.Reads.compare(a[runHi], a[runHi - 1]) < 0) + while(runHi < hi && ts.Reads.compare(a[runHi], a[runHi - 1]) < 0) { + ts.Highlights.markArray(1, runHi); + ts.Delays.sleep(1); runHi++; + } reverseRange(ts, a, lo, runHi); } else { // Ascending - while (runHi < hi && ts.Reads.compare(a[runHi], a[runHi - 1]) >= 0) + while (runHi < hi && ts.Reads.compare(a[runHi], a[runHi - 1]) >= 0) { + ts.Highlights.markArray(1, runHi); + ts.Delays.sleep(1); runHi++; + } } return runHi - lo; } @@ -420,6 +431,9 @@ private void mergeForceCollapse() { * @param i stack index of the first of the two runs to merge */ private void mergeAt(int i) { + this.Highlights.clearMark(1); + this.Highlights.clearMark(2); + int base1 = this.runBase[i]; int len1 = this.runLen[i]; int base2 = this.runBase[i + 1]; @@ -460,6 +474,9 @@ private void mergeAt(int i) { mergeLo(this, base1, len1, base2, len2); else mergeHi(this, base1, len1, base2, len2); + + this.Highlights.clearMark(1); + this.Highlights.clearMark(2); } /** @@ -484,14 +501,24 @@ private static int gallopLeft(TimSorting ts, int key, int[] a, int base, int len int lastOfs = 0; int ofs = 1; + ts.Highlights.markArray(3, base + hint); + ts.Delays.sleep(1); + if (ts.Reads.compare(key, a[base + hint]) > 0) { // Gallop right until a[base+hint+lastOfs] < key <= a[base+hint+ofs] int maxOfs = len - hint; - while (ofs < maxOfs && ts.Reads.compare(key, a[base + hint + ofs]) > 0) { + + ts.Highlights.markArray(3, base + hint + ofs); + ts.Delays.sleep(1); + + while (ofs < maxOfs && ts.Reads.compare(key, a[base + hint + ofs]) > 0) { lastOfs = ofs; ofs = (ofs * 2) + 1; if (ofs <= 0) // int overflow ofs = maxOfs; + + ts.Highlights.markArray(3, base + hint + ofs); + ts.Delays.sleep(1); } if (ofs > maxOfs) ofs = maxOfs; @@ -502,11 +529,18 @@ private static int gallopLeft(TimSorting ts, int key, int[] a, int base, int len } else { // key <= a[base + hint] // Gallop left until a[base+hint-ofs] < key <= a[base+hint-lastOfs] final int maxOfs = hint + 1; + + ts.Highlights.markArray(3, base + hint - ofs); + ts.Delays.sleep(1); + while (ofs < maxOfs && ts.Reads.compare(key, a[base + hint - ofs]) <= 0) { lastOfs = ofs; ofs = (ofs * 2) + 1; if (ofs <= 0) // int overflow ofs = maxOfs; + + ts.Highlights.markArray(3, base + hint - ofs); + ts.Delays.sleep(1); } if (ofs > maxOfs) ofs = maxOfs; @@ -526,11 +560,15 @@ private static int gallopLeft(TimSorting ts, int key, int[] a, int base, int len while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >>> 1); + ts.Highlights.markArray(3, base + m); + ts.Delays.sleep(1); + if (ts.Reads.compare(key, a[base + m]) > 0) lastOfs = m + 1; // a[base + m] < key else ofs = m; // key <= a[base + m] } + ts.Highlights.clearMark(3); return ofs; } /** @@ -549,14 +587,25 @@ private static int gallopLeft(TimSorting ts, int key, int[] a, int base, int len private static int gallopRight(TimSorting ts, int key, int[] a, int base, int len, int hint) { int ofs = 1; int lastOfs = 0; + + ts.Highlights.markArray(3, base + hint); + ts.Delays.sleep(1); + if (ts.Reads.compare(key, a[base + hint]) < 0) { // Gallop left until a[b+hint - ofs] <= key < a[b+hint - lastOfs] int maxOfs = hint + 1; + + ts.Highlights.markArray(3, base + hint - ofs); + ts.Delays.sleep(1); + while (ofs < maxOfs && ts.Reads.compare(key, a[base + hint - ofs]) < 0) { lastOfs = ofs; ofs = (ofs * 2) + 1; if (ofs <= 0) // int overflow ofs = maxOfs; + + ts.Highlights.markArray(3, base + hint - ofs); + ts.Delays.sleep(1); } if (ofs > maxOfs) ofs = maxOfs; @@ -568,11 +617,18 @@ private static int gallopRight(TimSorting ts, int key, int[] a, int base, int le } else { // a[b + hint] <= key // Gallop right until a[b+hint + lastOfs] <= key < a[b+hint + ofs] int maxOfs = len - hint; + + ts.Highlights.markArray(3, base + hint + ofs); + ts.Delays.sleep(1); + while (ofs < maxOfs && ts.Reads.compare(key, a[base + hint + ofs]) >= 0) { lastOfs = ofs; ofs = (ofs * 2) + 1; if (ofs <= 0) // int overflow ofs = maxOfs; + + ts.Highlights.markArray(3, base + hint + ofs); + ts.Delays.sleep(1); } if (ofs > maxOfs) ofs = maxOfs; @@ -591,11 +647,15 @@ private static int gallopRight(TimSorting ts, int key, int[] a, int base, int le while (lastOfs < ofs) { int m = lastOfs + ((ofs - lastOfs) >>> 1); + ts.Highlights.markArray(3, base + m); + ts.Delays.sleep(1); + if (ts.Reads.compare(key, a[base + m]) < 0) ofs = m; // key < a[b + m] else lastOfs = m + 1; // a[b + m] <= key } + ts.Highlights.clearMark(3); return ofs; } /** @@ -618,7 +678,7 @@ private void mergeLo(TimSorting ts, int base1, int len1, int base2, int len2) { // Copy first run into temp array int[] a = this.a; // For performance int[] tmp = ensureCapacity(len1); - ts.Writes.arraycopy(a, base1, tmp, 0, len1, 0.875, true, true); + ts.Writes.arraycopy(a, base1, tmp, 0, len1, 1, true, true); int cursor1 = 0; // Indexes into tmp array int cursor2 = base2; // Indexes int a @@ -629,11 +689,11 @@ private void mergeLo(TimSorting ts, int base1, int len1, int base2, int len2) { this.Highlights.markArray(1, dest); this.Highlights.markArray(2, cursor2); if (--len2 == 0) { - ts.Writes.arraycopy(tmp, cursor1, a, dest, len1, 0.875, true, false); + ts.Writes.arraycopy(tmp, cursor1, a, dest, len1, 1, true, false); return; } if (len1 == 1) { - ts.Writes.arraycopy(a, cursor2, a, dest, len2, 0.875, true, false); + ts.Writes.arraycopy(a, cursor2, a, dest, len2, 1, true, false); this.Writes.write(a, dest + len2, tmp[cursor1], 1, false, false); // Last elt of run 1 to end of merge this.Highlights.markArray(1, dest + len2); return; @@ -675,7 +735,7 @@ private void mergeLo(TimSorting ts, int base1, int len1, int base2, int len2) { do { count1 = gallopRight(ts, a[cursor2], tmp, cursor1, len1, 0); if (count1 != 0) { - ts.Writes.arraycopy(tmp, cursor1, a, dest, count1, 0.875, true, false); + ts.Writes.arraycopy(tmp, cursor1, a, dest, count1, 1, true, false); dest += count1; cursor1 += count1; len1 -= count1; @@ -690,7 +750,7 @@ private void mergeLo(TimSorting ts, int base1, int len1, int base2, int len2) { count2 = gallopLeft(ts, tmp[cursor1], a, cursor2, len2, 0); if (count2 != 0) { - ts.Writes.arraycopy(a, cursor2, a, dest, count2, 0.875, true, false); + ts.Writes.arraycopy(a, cursor2, a, dest, count2, 1, true, false); dest += count2; cursor2 += count2; len2 -= count2; @@ -710,16 +770,15 @@ private void mergeLo(TimSorting ts, int base1, int len1, int base2, int len2) { this.minGallop = minGallop < 1 ? 1 : minGallop; // Write back to field if (len1 == 1) { - ts.Writes.arraycopy(a, cursor2, a, dest, len2, 0.875, true, false); + ts.Writes.arraycopy(a, cursor2, a, dest, len2, 1, true, false); this.Writes.write(a, dest + len2, tmp[cursor1], 1, false, false); // Last elt of run 1 to end of merge this.Highlights.markArray(1, dest + len2); } else if (len1 == 0) { throw new IllegalArgumentException( "Comparison method violates its general contract!"); } else { - ts.Writes.arraycopy(tmp, cursor1, a, dest, len1, 0.875, true, false); + ts.Writes.arraycopy(tmp, cursor1, a, dest, len1, 1, true, false); } - this.Highlights.clearMark(2); } /** @@ -737,7 +796,7 @@ private void mergeHi(TimSorting ts, int base1, int len1, int base2, int len2) { // Copy second run into temp array int[] a = this.a; // For performance int[] tmp = ensureCapacity(len2); - ts.Writes.arraycopy(a, base2, tmp, 0, len2, 0.875, true, true); + ts.Writes.arraycopy(a, base2, tmp, 0, len2, 1, true, true); int cursor1 = base1 + len1 - 1; // Indexes into a int cursor2 = len2 - 1; // Indexes into tmp array @@ -748,13 +807,13 @@ private void mergeHi(TimSorting ts, int base1, int len1, int base2, int len2) { this.Highlights.markArray(1, dest); this.Highlights.markArray(2, cursor1); if (--len1 == 0) { - ts.Writes.reversearraycopy(tmp, 0, a, dest - (len2 - 1), len2, 0.875, true, false); + ts.Writes.reversearraycopy(tmp, 0, a, dest - (len2 - 1), len2, 1, true, false); return; } if (len2 == 1) { dest -= len1; cursor1 -= len1; - ts.Writes.reversearraycopy(a, cursor1 + 1, a, dest + 1, len1, 0.875, true, false); + ts.Writes.reversearraycopy(a, cursor1 + 1, a, dest + 1, len1, 1, true, false); this.Writes.write(a, dest, tmp[cursor2], 1, false, false); this.Highlights.markArray(1, dest); return; @@ -800,7 +859,7 @@ private void mergeHi(TimSorting ts, int base1, int len1, int base2, int len2) { dest -= count1; cursor1 -= count1; len1 -= count1; - ts.Writes.reversearraycopy(a, cursor1 + 1, a, dest + 1, count1, 0.875, true, false); + ts.Writes.reversearraycopy(a, cursor1 + 1, a, dest + 1, count1, 1, true, false); if (len1 == 0) break outer; } @@ -814,7 +873,7 @@ private void mergeHi(TimSorting ts, int base1, int len1, int base2, int len2) { dest -= count2; cursor2 -= count2; len2 -= count2; - ts.Writes.reversearraycopy(tmp, cursor2 + 1, a, dest + 1, count2, 0.875, true, false); + ts.Writes.reversearraycopy(tmp, cursor2 + 1, a, dest + 1, count2, 1, true, false); if (len2 <= 1) // len2 == 1 || len2 == 0 break outer; } @@ -834,17 +893,15 @@ private void mergeHi(TimSorting ts, int base1, int len1, int base2, int len2) { if (len2 == 1) { dest -= len1; cursor1 -= len1; - ts.Writes.reversearraycopy(a, cursor1 + 1, a, dest + 1, len1, 0.875, true, false); + ts.Writes.reversearraycopy(a, cursor1 + 1, a, dest + 1, len1, 1, true, false); this.Writes.write(a, dest, tmp[cursor2], 1, false, false); // Move first elt of run2 to front of merge this.Highlights.markArray(1, dest); } else if (len2 == 0) { throw new IllegalArgumentException( "Comparison method violates its general contract!"); } else { - ts.Writes.reversearraycopy(tmp, 0, a, dest - (len2 - 1), len2, 0.875, true, false); + ts.Writes.reversearraycopy(tmp, 0, a, dest - (len2 - 1), len2, 1, true, false); } - - this.Highlights.clearMark(2); } /** * Ensures that the external array tmp has at least the specified diff --git a/src/templates/Visual.java b/src/templates/Visual.java new file mode 100644 index 00000000..a8e35fd6 --- /dev/null +++ b/src/templates/Visual.java @@ -0,0 +1,128 @@ +package templates; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; + +import main.ArrayVisualizer; +import utils.Highlights; +import utils.Renderer; + +public abstract class Visual { + protected Graphics2D mainRender; + protected Graphics2D extraRender; + + public Visual(ArrayVisualizer ArrayVisualizer) { + this.updateRender(ArrayVisualizer); + } + + public void updateRender(ArrayVisualizer ArrayVisualizer) { + this.mainRender = ArrayVisualizer.getMainRender(); + this.extraRender = ArrayVisualizer.getExtraRender(); + } + + public static Color getIntColor(int i, int length) { + return Color.getHSBColor(((float) i / length), 1.0F, 0.8F); + } + + public static void markBar(Graphics2D bar, boolean color, boolean rainbow, boolean analysis) { + if(color || rainbow) { + /* + if(analysis) bar.setColor(Color.WHITE); + else bar.setColor(Color.BLACK); + */ + if(analysis) bar.setColor(Color.LIGHT_GRAY); + else bar.setColor(Color.WHITE); + } + else if(analysis) bar.setColor(Color.BLUE); + else bar.setColor(Color.RED); + } + private static void markBarFancy(Graphics2D bar, boolean color, boolean rainbow) { + if(!color && !rainbow) bar.setColor(Color.RED); + else bar.setColor(Color.BLACK); + } + + public static void lineMark(Graphics2D line, double width, boolean color, boolean analysis) { + line.setStroke(new BasicStroke((float) (9f * (width / 1280f)))); + if(color) line.setColor(Color.BLACK); + else if(analysis) line.setColor(Color.BLUE); + else line.setColor(Color.RED); + } + //TODO: Change name to markLineFancy + public static void lineFancy(Graphics2D line, double width) { + line.setColor(Color.GREEN); + line.setStroke(new BasicStroke((float) (9f * (width / 1280f)))); + } + //TODO: Change name to clearLine + public static void lineClear(Graphics2D line, boolean color, int[] array, int i, int length, double width) { + if(color) line.setColor(getIntColor(array[i], length)); + else line.setColor(Color.WHITE); + line.setStroke(new BasicStroke((float) (3f * (width / 1280f)))); + } + + public static void setRectColor(Graphics2D rect, boolean color, boolean analysis) { + if(color) rect.setColor(Color.WHITE); + else if(analysis) rect.setColor(Color.BLUE); + else rect.setColor(Color.RED); + } + + @SuppressWarnings("fallthrough") + //The longer the array length, the more bars marked. Makes the visual easier to see when bars are thinner. + public static void colorMarkedBars(int logOfLen, int index, Highlights Highlights, Graphics2D mainRender, boolean colorEnabled, boolean rainbowEnabled, boolean analysis) { + switch(logOfLen) { + case 14: if(Highlights.containsPosition(index - 10) + || Highlights.containsPosition(index - 9) + || Highlights.containsPosition(index - 8)) markBar(mainRender, colorEnabled, rainbowEnabled, analysis); + case 13: if(Highlights.containsPosition(index - 7) + || Highlights.containsPosition(index - 6) + || Highlights.containsPosition(index - 5)) markBar(mainRender, colorEnabled, rainbowEnabled, analysis); + case 12: if(Highlights.containsPosition(index - 4) + || Highlights.containsPosition(index - 3)) markBar(mainRender, colorEnabled, rainbowEnabled, analysis); + case 11: if(Highlights.containsPosition(index - 2)) markBar(mainRender, colorEnabled, rainbowEnabled, analysis); + case 10: if(Highlights.containsPosition(index - 1)) markBar(mainRender, colorEnabled, rainbowEnabled, analysis); + default: if(Highlights.containsPosition(index)) markBar(mainRender, colorEnabled, rainbowEnabled, analysis); + } + } + + @SuppressWarnings("fallthrough") + public static void drawFancyFinish(int logOfLen, int index, int position, Graphics2D mainRender, boolean colorEnabled, boolean rainbowEnabled) { + switch(logOfLen) { + case 14: if(index == position - 13) markBarFancy(mainRender, colorEnabled, rainbowEnabled); + case 13: if(index == position - 12) markBarFancy(mainRender, colorEnabled, rainbowEnabled); + case 12: if(index == position - 11) markBarFancy(mainRender, colorEnabled, rainbowEnabled); + case 11: if(index == position - 10) markBarFancy(mainRender, colorEnabled, rainbowEnabled); + case 10: if(index == position - 9) markBarFancy(mainRender, colorEnabled, rainbowEnabled); + case 9: if(index == position - 8) markBarFancy(mainRender, colorEnabled, rainbowEnabled); + case 8: if(index == position - 7) markBarFancy(mainRender, colorEnabled, rainbowEnabled); + case 7: if(index == position - 6) markBarFancy(mainRender, colorEnabled, rainbowEnabled); + case 6: if(index == position - 5) markBarFancy(mainRender, colorEnabled, rainbowEnabled); + case 5: if(index == position - 4) markBarFancy(mainRender, colorEnabled, rainbowEnabled); + case 4: if(index == position - 3) markBarFancy(mainRender, colorEnabled, rainbowEnabled); + case 3: if(index == position - 2) markBarFancy(mainRender, colorEnabled, rainbowEnabled); + case 2: if(index == position - 1) markBarFancy(mainRender, colorEnabled, rainbowEnabled); + default: if(index == position) markBarFancy(mainRender, colorEnabled, rainbowEnabled); + } + } + + @SuppressWarnings("fallthrough") + public static void drawFancyFinishLine(int logOfLen, int index, int position, Graphics2D mainRender, double width, boolean colorEnabled) { + switch(logOfLen) { + case 14: if(index == position - 13) lineMark(mainRender, width, colorEnabled, false); + case 13: if(index == position - 12) lineMark(mainRender, width, colorEnabled, false); + case 12: if(index == position - 11) lineMark(mainRender, width, colorEnabled, false); + case 11: if(index == position - 10) lineMark(mainRender, width, colorEnabled, false); + case 10: if(index == position - 9) lineMark(mainRender, width, colorEnabled, false); + case 9: if(index == position - 8) lineMark(mainRender, width, colorEnabled, false); + case 8: if(index == position - 7) lineMark(mainRender, width, colorEnabled, false); + case 7: if(index == position - 6) lineMark(mainRender, width, colorEnabled, false); + case 6: if(index == position - 5) lineMark(mainRender, width, colorEnabled, false); + case 5: if(index == position - 4) lineMark(mainRender, width, colorEnabled, false); + case 4: if(index == position - 3) lineMark(mainRender, width, colorEnabled, false); + case 3: if(index == position - 2) lineMark(mainRender, width, colorEnabled, false); + case 2: if(index == position - 1) lineMark(mainRender, width, colorEnabled, false); + default: if(index == position) lineMark(mainRender, width, colorEnabled, false); + } + } + + public abstract void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, Highlights Highlights); +} \ No newline at end of file diff --git a/src/templates/WikiSorting.java b/src/templates/WikiSorting.java index 5fb9017a..3cedaf41 100644 --- a/src/templates/WikiSorting.java +++ b/src/templates/WikiSorting.java @@ -1,6 +1,7 @@ package templates; import sorts.InsertionSort; +import utils.Delays; import utils.Highlights; import utils.Reads; import utils.Writes; @@ -147,6 +148,8 @@ final public class WikiSorting { // just keep in mind that making it too small ruins the point (nothing will fit into it), // and making it too large also ruins the point (so much for "low memory"!) private InsertionSort InsertSort; + + private Delays Delays; private Highlights Highlights; private Reads Reads; private Writes Writes; @@ -167,8 +170,10 @@ final public class WikiSorting { // 0 – if the system simply cannot allocate any extra memory whatsoever, no memory works just fine - public WikiSorting(InsertionSort insertionSort, Highlights markOps, Reads readOps, Writes writeOps, int cacheChoice) { + public WikiSorting(InsertionSort insertionSort, Delays delayOps, Highlights markOps, Reads readOps, Writes writeOps, int cacheChoice) { this.InsertSort = insertionSort; + + this.Delays = delayOps; this.Highlights = markOps; this.Reads = readOps; this.Writes = writeOps; @@ -261,7 +266,7 @@ int FindLastBackward(int[] array, int value, Range range, int unique) { // n^2 sorting algorithm used to sort tiny chunks of the full array void InsertionSort(int[] array, Range range) { - InsertSort.customInsertSort(array, range.start, range.end, 0.25, false); + InsertSort.customInsertSort(array, range.start, range.end, 0.5, false); } // reverse a range of values within the array @@ -368,6 +373,8 @@ void MergeExternal(int[] array, Range A, Range B) { if (B.length() > 0 && A.length() > 0) { while (true) { + Highlights.markArray(3, A_index); + Highlights.markArray(4, B_index); if (Reads.compare(array[B_index], cache[A_index]) >= 0) { Writes.write(array, insert_index, cache[A_index], 1, true, false); A_index++; @@ -381,7 +388,9 @@ void MergeExternal(int[] array, Range A, Range B) { } } } - + Highlights.clearMark(3); + Highlights.clearMark(4); + // copy the remainder of A into the final array if (cache != null) { Writes.arraycopy(cache, A_index, array, insert_index, A_last - A_index, 1, true, false); @@ -397,19 +406,24 @@ void MergeInternal(int[] array, Range A, Range B, Range buffer) { if (B.length() > 0 && A.length() > 0) { while (true) { if (Reads.compare(array[B.start + B_count], array[buffer.start + A_count]) >= 0) { - Writes.swap(array, A.start + insert, buffer.start + A_count, 1, true, false); + Highlights.markArray(3, buffer.start + A_count); + Delays.sleep(1); + Writes.swap(array, A.start + insert, buffer.start + A_count, 0, true, false); A_count++; insert++; if (A_count >= A.length()) break; } else { - Writes.swap(array, A.start + insert, B.start + B_count, 1, true, false); + Highlights.markArray(3, B.start + B_count); + Delays.sleep(1); + Writes.swap(array, A.start + insert, B.start + B_count, 0, true, false); B_count++; insert++; if (B_count >= B.length()) break; } } } - + Highlights.clearMark(3); + // swap the remainder of A into the final array BlockSwap(array, buffer.start + A_count, A.start + insert, A.length() - A_count); } diff --git a/src/test/Tester.java b/src/test/Tester.java index 8ce05c90..4236e1e5 100644 --- a/src/test/Tester.java +++ b/src/test/Tester.java @@ -52,10 +52,10 @@ public static void main(String[] args) throws Exception { ArrayVisualizer av = new ArrayVisualizer(); - Delays = new Delays(); + Delays = new Delays(av); Delays.setSleepRatio(Double.MAX_VALUE); - Highlights = new Highlights(testArr.length); + Highlights = new Highlights(av, testArr.length); Highlights.toggleFancyFinishes(false); RealTimer = new Timer(); diff --git a/src/threads/RunAllSorts.java b/src/threads/RunAllSorts.java index 06a0ed74..aeda83f0 100644 --- a/src/threads/RunAllSorts.java +++ b/src/threads/RunAllSorts.java @@ -1,5 +1,11 @@ package threads; +import java.util.ArrayList; + +import main.ArrayVisualizer; +import templates.JErrorPane; +import templates.MultipleSortThread; + /* * MIT License @@ -27,417 +33,41 @@ of this software and associated documentation files (the "Software"), to deal */ final public class RunAllSorts { - public static void runAllSorts() { - return; + private ArrayVisualizer ArrayVisualizer; + private ArrayList allSortThreads; + + public RunAllSorts(ArrayVisualizer ArrayVisualizer) { + this.ArrayVisualizer = ArrayVisualizer; + this.allSortThreads = new ArrayList<>(); + this.allSortThreads.add(new RunExchangeSorts(ArrayVisualizer)); + this.allSortThreads.add(new RunSelectionSorts(ArrayVisualizer)); + this.allSortThreads.add(new RunInsertionSorts(ArrayVisualizer)); + this.allSortThreads.add(new RunMergeSorts(ArrayVisualizer)); + this.allSortThreads.add(new RunDistributionSorts(ArrayVisualizer)); + this.allSortThreads.add(new RunConcurrentSorts(ArrayVisualizer)); + this.allSortThreads.add(new RunHybridSorts(ArrayVisualizer)); + this.allSortThreads.add(new RunMiscellaneousSorts(ArrayVisualizer)); + this.allSortThreads.add(new RunImpracticalSorts(ArrayVisualizer)); } - /* - category = "Merge Sorts"; - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "Merge Sort"; - SLEEPRATIO = 1.75; - startRealTimer(); - mergeSortOOP(array, currentLen, false); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "In-Place Merge Sort"; - SLEEPRATIO = 7; - startRealTimer(); - mergeSort(array, 0, currentLen - 1); - - endSort(); - Thread.sleep(1000); - - category = "Distribution Sorts"; - - SLEEPRATIO = 2.5; - - int radix = currentLen < 256 ? currentLen / 2 : 256; - if(radix == 1) radix = 2; - - refresharray(); - heading = "American Flag Sort, " + radix + " Buckets"; - startRealTimer(); - flagSort(array, currentLen, radix); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "Bead (Gravity) Sort"; - SLEEPRATIO = Integer.MAX_VALUE; - startRealTimer(); - gravitySort(array, currentLen); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "Counting Sort"; - SLEEPRATIO = 5; - startRealTimer(); - countingSort(array, currentLen); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "Pigeonhole Sort"; - SLEEPRATIO = 5; - startRealTimer(); - pigeonSort(array, currentLen); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - - radix = currentLen == 2 ? 2 : 4; - - refresharray(); - heading = "Radix LSD Sort, Base " + radix; - SLEEPRATIO = 2; - startRealTimer(); - radixLSDsort(array, currentLen, radix); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - SOUNDMUL = 0.01; - - radix = currentLen < 16 ? currentLen / 2 : 16; - if(radix == 1) radix = 2; - - refresharray(); - heading = "In-Place Radix LSD Sort, Base " + radix; - SLEEPRATIO = 2; - startRealTimer(); - inPlaceRadixLSDSort(array, currentLen, radix); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - SOUNDMUL = storeVol; - - radix = currentLen < 8 ? currentLen / 2 : 8; - if(radix == 1) radix = 2; - - refresharray(); - heading = "Radix MSD Sort, Base " + radix; - SLEEPRATIO = 1.75; - startRealTimer(); - radixMSDSort(array, currentLen, radix); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "Flash Sort"; - SLEEPRATIO = 1.5; - startRealTimer(); - flashSort(array, currentLen); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "Shatter Sort"; - SLEEPRATIO = 1; - startRealTimer(); - shatterSort(array, currentLen, 64); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "Simple Shatter Sort"; - SLEEPRATIO = 1.5; - startRealTimer(); - simpleShatterSort(array, currentLen, 256, 4); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "Time Sort (Mul 4)"; - SLEEPRATIO = 1.5; - startRealTimer(); - timeSort(array, currentLen, 4); - - endSort(); - Thread.sleep(1000); - - category = "Concurrent Sorts"; - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "Batcher's Bitonic Sort"; - SLEEPRATIO = 4.5; - startRealTimer(); - bitonicSort(array, 0, currentLen, true); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "Batcher's Odd-Even Merge Sort"; - SLEEPRATIO = 3; - startRealTimer(); - oddEvenMergeSort(array, 0, currentLen); - - endSort(); - Thread.sleep(1000); - - category = "Hybrid Sorts"; - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "Hybrid Comb Sort (Comb/Insertion)"; - SLEEPRATIO = 3; - startRealTimer(); - combSort(array, currentLen, true); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "Binary Merge Sort (Merge/Binary Insertion)"; - SLEEPRATIO = 1.25; - startRealTimer(); - mergeSortOOP(array, currentLen, true); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "Weave Merge Sort (Merge/Insertion)"; - SLEEPRATIO = 2.5; - startRealTimer(); - weaveMergeSort(array, 0, currentLen - 1); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "TimSort"; - SLEEPRATIO = 1.5; - startRealTimer(); - timSort(array, currentLen); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "WikiSort (Block Merge Sort)"; - SLEEPRATIO = 2; - startRealTimer(); - startWikiSort(array, currentLen); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "GrailSort (Block Merge Sort)"; - SLEEPRATIO = 2; - startRealTimer(); - grailSortWithoutBuffer(array, currentLen); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "std::sort (Introsort)"; - SLEEPRATIO = 1.5; - startRealTimer(); - introSort(array, currentLen, 32, 1, 0); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "Quick Shell Sort (Introsort with Shellsort)"; - SLEEPRATIO = 1.5; - startRealTimer(); - introSort(array, currentLen, 48, 2, 12); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 2.5; - - refresharray(); - heading = "std::stable_sort (Insert/Bottom-up Merge)"; - SLEEPRATIO = 1.5; - startRealTimer(); - stableSort(array, currentLen); - - endSort(); - Thread.sleep(1000); - - category = "Miscellaneous Sorts"; - - int shortLen = (int) Math.ceil((256 * (currentLen / 2048d))); - if(shortLen == 1) shortLen = 2; - if(VISUALS == CIRCULAR && shortLen == 2) shortLen = 4; - currentLen = currentLen >= 2048 ? 256 : shortLen; - - SLEEPRATIO = 1; - - refresharray(); - heading = "Pancake Sort"; - SLEEPRATIO = 1; - startRealTimer(); - pancakeSort(array, currentLen); - - endSort(); - Thread.sleep(1000); - - category = "Impractical Sorts"; - - refresharray(); - heading = "Stooge Sort"; - SLEEPRATIO = 2.5; - startRealTimer(); - stoogeSort(array, 0, currentLen - 1); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 1; - - refresharray(); - heading = "Bad Sort"; - SLEEPRATIO = 1; - startRealTimer(); - badSort(array, currentLen); - - endSort(); - Thread.sleep(1000); - - refresharray(); - heading = "Silly Sort"; - SLEEPRATIO = 1; - startRealTimer(); - sillySort(array, 0, currentLen - 1); - - endSort(); - Thread.sleep(1000); - - refresharray(); - heading = "Slow Sort"; - SLEEPRATIO = 1; - startRealTimer(); - slowSort(array, 0, currentLen - 1); - - endSort(); - Thread.sleep(1000); - - refresharray(); - heading = "Less Bogo Sort"; - SLEEPRATIO = 300; - startRealTimer(); - lessBogoSort(array, currentLen); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 1; - - refresharray(); - heading = "Cocktail Bogo Sort"; - startRealTimer(); - SLEEPRATIO = 300; - doubleBogoSort(array, currentLen); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 1; - - refresharray(); - heading = "Bubble Bogo Sort"; - startRealTimer(); - SLEEPRATIO = 1; - bubbleBogoSort(array, currentLen); - - endSort(); - Thread.sleep(1000); - - SLEEPRATIO = 1; - - refresharray(); - heading = "Exchange Bogo Sort"; - startRealTimer(); - SLEEPRATIO = 0.35; - exchangeBogoSort(array, currentLen); - - endSort(); - Thread.sleep(1000); - - currentLen = currentLen < 8 ? currentLen : 8; - if(VISUALS == CIRCULAR && currentLen == 2) currentLen = 4; - - SLEEPRATIO = 0.01; - - refresharray(); - heading = "Bogo Sort"; - startRealTimer(); - SLEEPRATIO = 20; - bogoSort(array, currentLen); - - endSort(); - Thread.sleep(1000); - - category = "Run All"; - heading = "Done"; - MUTABLE = true; - }catch (Exception e){} - SetSound(false); + public void reportAllSorts(int[] array) throws Exception { + int totalSortCount = 0; + for(MultipleSortThread category : this.allSortThreads) { + totalSortCount += category.getSortCount(); + } + + try { + int currentSort = 1; + for(MultipleSortThread thread : this.allSortThreads) { + thread.reportAllSorts(array, currentSort, totalSortCount); + this.ArrayVisualizer.getSortingThread().join(); + currentSort += thread.getCategoryCount(); } - }; - sortingThread.start(); + } catch (Exception e) { + JErrorPane.invokeErrorMessage(e); + } + + this.ArrayVisualizer.setCategory("Run All Sorts"); + this.ArrayVisualizer.setHeading("Finished!!"); } - */ } \ No newline at end of file diff --git a/src/threads/RunComparisonSort.java b/src/threads/RunComparisonSort.java index 708b602d..9b5f0a83 100644 --- a/src/threads/RunComparisonSort.java +++ b/src/threads/RunComparisonSort.java @@ -6,6 +6,7 @@ import main.ArrayManager; import main.ArrayVisualizer; +import templates.JErrorPane; import templates.Sort; import utils.Delays; import utils.Highlights; @@ -123,13 +124,12 @@ public void run() { else { ArrayManager.initializeArray(array); } - - ArrayVisualizer.endSort(); - ArrayManager.toggleMutableLength(true); } catch(Exception e) { - e.printStackTrace(); + JErrorPane.invokeErrorMessage(e); } + ArrayVisualizer.endSort(); + ArrayManager.toggleMutableLength(true); Sounds.toggleSound(false); } }); diff --git a/src/threads/RunConcurrentSorts.java b/src/threads/RunConcurrentSorts.java new file mode 100644 index 00000000..a70ac38d --- /dev/null +++ b/src/threads/RunConcurrentSorts.java @@ -0,0 +1,112 @@ +package threads; + +import main.ArrayVisualizer; +import sorts.IterativeBitonicSort; +import sorts.IterativeOddEvenMergeSort; +import sorts.IterativePairwiseSort; +import sorts.RecursiveBitonicSort; +import sorts.RecursiveOddEvenMergeSort; +import sorts.RecursivePairwiseSort; +import templates.JErrorPane; +import templates.MultipleSortThread; +import templates.Sort; + +/* + * +MIT License + +Copyright (c) 2019 w0rthy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + * + */ + +final public class RunConcurrentSorts extends MultipleSortThread { + private Sort RecursiveBitonicSort; + private Sort RecursiveOddEvenMergeSort; + private Sort RecursivePairwiseSort; + private Sort IterativeBitonicSort; + private Sort IterativeOddEvenMergeSort; + private Sort IterativePairwiseSort; + + public RunConcurrentSorts(ArrayVisualizer ArrayVisualizer) { + super(ArrayVisualizer); + this.sortCount = 6; + this.categoryCount = this.sortCount; + + RecursiveBitonicSort = new RecursiveBitonicSort(Delays, Highlights, Reads, Writes); + RecursiveOddEvenMergeSort = new RecursiveOddEvenMergeSort(Delays, Highlights, Reads, Writes); + RecursivePairwiseSort = new RecursivePairwiseSort(Delays, Highlights, Reads, Writes); + IterativeBitonicSort = new IterativeBitonicSort(Delays, Highlights, Reads, Writes); + IterativeOddEvenMergeSort = new IterativeOddEvenMergeSort(Delays, Highlights, Reads, Writes); + IterativePairwiseSort = new IterativePairwiseSort(Delays, Highlights, Reads, Writes); + } + + @Override + protected synchronized void executeSortList(int[] array) throws Exception { + RunConcurrentSorts.this.runIndividualSort(RecursiveBitonicSort, 0, array, 1024, 0.6667); + RunConcurrentSorts.this.runIndividualSort(RecursiveOddEvenMergeSort, 0, array, 1024, 1); + RunConcurrentSorts.this.runIndividualSort(RecursivePairwiseSort, 0, array, 1024, 1); + RunConcurrentSorts.this.runIndividualSort(IterativeBitonicSort, 0, array, 1024, 0.3333); + RunConcurrentSorts.this.runIndividualSort(IterativeOddEvenMergeSort, 0, array, 1024, 1); + RunConcurrentSorts.this.runIndividualSort(IterativePairwiseSort, 0, array, 1024, 0.8); + } + + @Override + protected synchronized void runThread(int[] array, int current, int total, boolean runAllActive) throws Exception { + if(ArrayVisualizer.getSortingThread() != null && ArrayVisualizer.getSortingThread().isAlive()) + return; + + Sounds.toggleSound(true); + ArrayVisualizer.setSortingThread(new Thread() { + @Override + public void run() { + try{ + if(runAllActive) { + RunConcurrentSorts.this.sortNumber = current; + RunConcurrentSorts.this.sortCount = total; + } + else { + RunConcurrentSorts.this.sortNumber = 1; + } + + ArrayManager.toggleMutableLength(false); + + ArrayVisualizer.setCategory("Concurrent Sorts"); + + RunConcurrentSorts.this.executeSortList(array); + + if(!runAllActive) { + ArrayVisualizer.setCategory("Run Concurrent Sorts"); + ArrayVisualizer.setHeading("Done"); + } + + ArrayManager.toggleMutableLength(true); + } + catch (Exception e) { + JErrorPane.invokeErrorMessage(e); + } + Sounds.toggleSound(false); + ArrayVisualizer.setSortingThread(null); + } + }); + + ArrayVisualizer.runSortingThread(); + } +} \ No newline at end of file diff --git a/src/threads/RunDistributionSort.java b/src/threads/RunDistributionSort.java index 97aa8fc9..93dd790c 100644 --- a/src/threads/RunDistributionSort.java +++ b/src/threads/RunDistributionSort.java @@ -1,20 +1,17 @@ package threads; -import java.awt.HeadlessException; import java.lang.reflect.Constructor; -import javax.swing.JDialog; import javax.swing.JOptionPane; -import javax.swing.UIManager; import main.ArrayManager; import main.ArrayVisualizer; -import sorts.FlashSort; +import templates.JEnhancedOptionPane; +import templates.JErrorPane; import templates.Sort; import utils.Delays; import utils.Highlights; import utils.Reads; -import utils.Shuffles; import utils.Sounds; import utils.Timer; import utils.Writes; @@ -45,31 +42,6 @@ of this software and associated documentation files (the "Software"), to deal * */ -// Many thanks to Freek de Bruijn on StackOverflow for providing a custom JOptionPane. -// https://stackoverflow.com/questions/14407804/how-to-change-the-default-text-of-buttons-in-joptionpane-showinputdialog?noredirect=1&lq=1 -final class JEnhancedOptionPane extends JOptionPane { - /** - * - */ - private static final long serialVersionUID = 1L; - - public static String showInputDialog(final Object message, final Object[] options) throws HeadlessException { - final JOptionPane pane = new JOptionPane(message, QUESTION_MESSAGE, - OK_CANCEL_OPTION, null, - options, null); - pane.setWantsInput(true); - pane.setComponentOrientation((getRootFrame()).getComponentOrientation()); - pane.setMessageType(QUESTION_MESSAGE); - pane.selectInitialValue(); - final String title = UIManager.getString("OptionPane.inputDialogTitle", null); - final JDialog dialog = pane.createDialog(null, title); - dialog.setVisible(true); - dialog.dispose(); - final Object value = pane.getInputValue(); - return (value == UNINITIALIZED_VALUE) ? null : (String) value; - } -} - final public class RunDistributionSort { private ArrayManager ArrayManager; private ArrayVisualizer ArrayVisualizer; @@ -183,20 +155,11 @@ public void run(){ } } else if(sort.getReportSortID().equals("Shatter Sort") || sort.getReportSortID().equals("Simple Shatter Sort")) { - // Ugh. Not happy with this patch at all. For some reason, Shatter Sort does not work - // for all distributions of data unless you only have two partitions/"shatters" **presumably**. - - // Specifically, an array that doesn't hold many unique values breaks Shatter Sort. - if(ArrayManager.getShuffle().equals(Shuffles.SIMILAR)) { - bucketCount = 2; + try { + bucketCount = Integer.parseInt(JEnhancedOptionPane.showInputDialog("Enter the size for each partition:", new Object[]{"Enter", "Use default"})); } - else { - try { - bucketCount = Integer.parseInt(JEnhancedOptionPane.showInputDialog("Enter the size for each partition:", new Object[]{"Enter", "Use default"})); - } - catch(Exception e) { - bucketCount = ArrayVisualizer.getCurrentLength() / 16; - } + catch(Exception e) { + bucketCount = ArrayVisualizer.getCurrentLength() / 16; } } else { @@ -263,11 +226,6 @@ else if(sort.getReportSortID().equals("Shatter Sort") || sort.getReportSortID(). goAhead = true; } - // Patch for Flashsort, fixes distribution for few unique numbers - if(sort.getReportSortID().equals("Flashsort")) { - ((FlashSort) sort).setCurrentShuffle(ArrayManager.getShuffle()); - } - if(sort.getReportSortID().equals("In-Place LSD Radix")) { Sounds.changeVolume(0.01); // Here to protect your ears :) } @@ -281,13 +239,12 @@ else if(sort.getReportSortID().equals("Shatter Sort") || sort.getReportSortID(). else { ArrayManager.initializeArray(array); } - - ArrayVisualizer.endSort(); - ArrayManager.toggleMutableLength(true); } catch(Exception e) { - e.printStackTrace(); + JErrorPane.invokeErrorMessage(e); } + ArrayVisualizer.endSort(); + ArrayManager.toggleMutableLength(true); Sounds.changeVolume(storeVol); Sounds.toggleSound(false); } diff --git a/src/threads/RunDistributionSorts.java b/src/threads/RunDistributionSorts.java new file mode 100644 index 00000000..c8279716 --- /dev/null +++ b/src/threads/RunDistributionSorts.java @@ -0,0 +1,141 @@ +package threads; + +import main.ArrayVisualizer; +import sorts.AmericanFlagSort; +import sorts.BinaryQuickSort; +import sorts.CountingSort; +import sorts.FlashSort; +import sorts.GravitySort; +import sorts.InPlaceLSDRadixSort; +import sorts.LSDRadixSort; +import sorts.MSDRadixSort; +import sorts.PigeonholeSort; +import sorts.RecursiveBinaryQuickSort; +import sorts.ShatterSort; +import sorts.SimpleShatterSort; +import sorts.TimeSort; +import templates.JErrorPane; +import templates.MultipleSortThread; +import templates.Sort; + +/* + * +MIT License + +Copyright (c) 2019 w0rthy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + * + */ + +final public class RunDistributionSorts extends MultipleSortThread { + private Sort CountingSort; + private Sort PigeonholeSort; + private Sort GravitySort; + private Sort AmericanFlagSort; + private Sort LSDRadixSort; + private Sort InPlaceLSDRadixSort; + private Sort MSDRadixSort; + private Sort FlashSort; + private Sort BinaryQuickSort; + private Sort RecursiveBinaryQuickSort; + private Sort ShatterSort; + private Sort SimpleShatterSort; + private Sort TimeSort; + + public RunDistributionSorts(ArrayVisualizer ArrayVisualizer) { + super(ArrayVisualizer); + this.sortCount = 13; + this.categoryCount = this.sortCount; + + CountingSort = new CountingSort(Delays, Highlights, Reads, Writes); + PigeonholeSort = new PigeonholeSort(Delays, Highlights, Reads, Writes); + GravitySort = new GravitySort(Delays, Highlights, Reads, Writes); + AmericanFlagSort = new AmericanFlagSort(Delays, Highlights, Reads, Writes); + LSDRadixSort = new LSDRadixSort(Delays, Highlights, Reads, Writes); + InPlaceLSDRadixSort = new InPlaceLSDRadixSort(Delays, Highlights, Reads, Writes); + MSDRadixSort = new MSDRadixSort(Delays, Highlights, Reads, Writes); + FlashSort = new FlashSort(Delays, Highlights, Reads, Writes); + BinaryQuickSort = new BinaryQuickSort(Delays, Highlights, Reads, Writes); + RecursiveBinaryQuickSort = new RecursiveBinaryQuickSort(Delays, Highlights, Reads, Writes); + ShatterSort = new ShatterSort(Delays, Highlights, Reads, Writes); + SimpleShatterSort = new SimpleShatterSort(Delays, Highlights, Reads, Writes); + TimeSort = new TimeSort(Delays, Highlights, Reads, Writes); + } + + @Override + protected synchronized void executeSortList(int[] array) throws Exception { + RunDistributionSorts.this.runIndividualSort(CountingSort, 0, array, 2048, 1.5); + RunDistributionSorts.this.runIndividualSort(PigeonholeSort, 0, array, 2048, 1.5); + RunDistributionSorts.this.runIndividualSort(GravitySort, 0, array, 1024, 0.5); + RunDistributionSorts.this.runIndividualSort(AmericanFlagSort, 128, array, 2048, 0.75); + RunDistributionSorts.this.runIndividualSort(LSDRadixSort, 4, array, 2048, 1.5); + Sounds.toggleSofterSounds(true); + RunDistributionSorts.this.runIndividualSort(InPlaceLSDRadixSort, 10, array, 2048, 1); + Sounds.toggleSofterSounds(false); + RunDistributionSorts.this.runIndividualSort(MSDRadixSort, 4, array, 2048, 1.25); + RunDistributionSorts.this.runIndividualSort(FlashSort, 0, array, 2048, 1); + RunDistributionSorts.this.runIndividualSort(BinaryQuickSort, 0, array, 2048, 1); + RunDistributionSorts.this.runIndividualSort(RecursiveBinaryQuickSort, 0, array, 2048, 1); + RunDistributionSorts.this.runIndividualSort(ShatterSort, 128, array, 2048, 1); + RunDistributionSorts.this.runIndividualSort(SimpleShatterSort, 128, array, 2048, 1); + RunDistributionSorts.this.runIndividualSort(TimeSort, 10, array, 2048, 1); + } + + @Override + protected synchronized void runThread(int[] array, int current, int total, boolean runAllActive) throws Exception { + if(ArrayVisualizer.getSortingThread() != null && ArrayVisualizer.getSortingThread().isAlive()) + return; + + Sounds.toggleSound(true); + ArrayVisualizer.setSortingThread(new Thread() { + @Override + public void run() { + try{ + if(runAllActive) { + RunDistributionSorts.this.sortNumber = current; + RunDistributionSorts.this.sortCount = total; + } + else { + RunDistributionSorts.this.sortNumber = 1; + } + + ArrayManager.toggleMutableLength(false); + + ArrayVisualizer.setCategory("Distribution Sorts"); + + RunDistributionSorts.this.executeSortList(array); + + if(!runAllActive) { + ArrayVisualizer.setCategory("Run Distribution Sorts"); + ArrayVisualizer.setHeading("Done"); + } + + ArrayManager.toggleMutableLength(true); + } + catch (Exception e) { + JErrorPane.invokeErrorMessage(e); + } + Sounds.toggleSound(false); + ArrayVisualizer.setSortingThread(null); + } + }); + ArrayVisualizer.runSortingThread(); + } +} \ No newline at end of file diff --git a/src/threads/RunExchangeSorts.java b/src/threads/RunExchangeSorts.java index a86101d2..5926f30c 100644 --- a/src/threads/RunExchangeSorts.java +++ b/src/threads/RunExchangeSorts.java @@ -12,10 +12,13 @@ import sorts.LRQuickSort; import sorts.OddEvenSort; import sorts.SmartBubbleSort; +import sorts.SmartCocktailSort; import sorts.SmartGnomeSort; import sorts.StableQuickSort; +import templates.JErrorPane; import templates.MultipleSortThread; import templates.Sort; +import utils.Shuffles; /* * @@ -44,11 +47,62 @@ of this software and associated documentation files (the "Software"), to deal */ final public class RunExchangeSorts extends MultipleSortThread { + private Sort BubbleSort; + private Sort SmartBubbleSort; + private Sort CocktailShakerSort; + private Sort SmartCocktailSort; + private Sort OddEvenSort; + private Sort GnomeSort; + private Sort SmartGnomeSort; + private Sort BinaryGnomeSort; + private Sort CombSort; + private Sort CircleSort; + private Sort LLQuickSort; + private Sort LRQuickSort; + private Sort DualPivotQuickSort; + private Sort StableQuickSort; + public RunExchangeSorts(ArrayVisualizer ArrayVisualizer) { super(ArrayVisualizer); + this.sortCount = 14; + this.categoryCount = this.sortCount; + + BubbleSort = new BubbleSort(Delays, Highlights, Reads, Writes); + SmartBubbleSort = new SmartBubbleSort(Delays, Highlights, Reads, Writes); + CocktailShakerSort = new CocktailShakerSort(Delays, Highlights, Reads, Writes); + SmartCocktailSort = new SmartCocktailSort(Delays, Highlights, Reads, Writes); + OddEvenSort = new OddEvenSort(Delays, Highlights, Reads, Writes); + GnomeSort = new GnomeSort(Delays, Highlights, Reads, Writes); + SmartGnomeSort = new SmartGnomeSort(Delays, Highlights, Reads, Writes); + BinaryGnomeSort = new BinaryGnomeSort(Delays, Highlights, Reads, Writes); + CombSort = new CombSort(Delays, Highlights, Reads, Writes); + CircleSort = new CircleSort(Delays, Highlights, Reads, Writes); + LLQuickSort = new LLQuickSort(Delays, Highlights, Reads, Writes); + LRQuickSort = new LRQuickSort(Delays, Highlights, Reads, Writes); + DualPivotQuickSort = new DualPivotQuickSort(Delays, Highlights, Reads, Writes); + StableQuickSort = new StableQuickSort(Delays, Highlights, Reads, Writes); } - public synchronized void ReportExchangeSorts(int[] array) throws Exception { + @Override + protected synchronized void executeSortList(int[] array) throws Exception { + RunExchangeSorts.this.runIndividualSort(BubbleSort, 0, array, 512, 1.5); + RunExchangeSorts.this.runIndividualSort(SmartBubbleSort, 0, array, 512, 1.5); + RunExchangeSorts.this.runIndividualSort(CocktailShakerSort, 0, array, 512, 1.25); + RunExchangeSorts.this.runIndividualSort(SmartCocktailSort, 0, array, 512, 1.25); + RunExchangeSorts.this.runIndividualSort(OddEvenSort, 0, array, 512, 1); + RunExchangeSorts.this.runIndividualSort(GnomeSort, 0, array, 128, 0.025); + RunExchangeSorts.this.runIndividualSort(SmartGnomeSort, 0, array, 128, 0.025); + RunExchangeSorts.this.runIndividualSort(BinaryGnomeSort, 0, array, 128, 0.025); + RunExchangeSorts.this.runIndividualSort(CombSort, 0, array, 1024, 1); + RunExchangeSorts.this.runIndividualSort(CircleSort, 0, array, 1024, 1); + RunExchangeSorts.this.runIndividualSort(LLQuickSort, 0, array, 2048, ArrayManager.getShuffle() == Shuffles.RANDOM ? 1.5 : 65); + RunExchangeSorts.this.runIndividualSort(LRQuickSort, 0, array, 2048, 1); + RunExchangeSorts.this.runIndividualSort(DualPivotQuickSort, 0, array, 2048, ArrayManager.getShuffle() == Shuffles.RANDOM ? 1 : 50); + RunExchangeSorts.this.runIndividualSort(StableQuickSort, 0, array, 2048, ArrayManager.getShuffle() == Shuffles.RANDOM ? 1 : 50); + } + + @Override + protected synchronized void runThread(int[] array, int current, int total, boolean runAllActive) throws Exception { if(ArrayVisualizer.getSortingThread() != null && ArrayVisualizer.getSortingThread().isAlive()) return; @@ -57,54 +111,34 @@ public synchronized void ReportExchangeSorts(int[] array) throws Exception { @Override public void run() { try{ - Sort BubbleSort = new BubbleSort(Delays, Highlights, Reads, Writes); - Sort SmartBubbleSort = new SmartBubbleSort(Delays, Highlights, Reads, Writes); - Sort CocktailShakerSort = new CocktailShakerSort(Delays, Highlights, Reads, Writes); - Sort OddEvenSort = new OddEvenSort(Delays, Highlights, Reads, Writes); - Sort GnomeSort = new GnomeSort(Delays, Highlights, Reads, Writes); - Sort SmartGnomeSort = new SmartGnomeSort(Delays, Highlights, Reads, Writes); - Sort BinaryGnomeSort = new BinaryGnomeSort(Delays, Highlights, Reads, Writes); - Sort CombSort = new CombSort(Delays, Highlights, Reads, Writes); - Sort CircleSort = new CircleSort(Delays, Highlights, Reads, Writes); - Sort LLQuickSort = new LLQuickSort(Delays, Highlights, Reads, Writes); - Sort LRQuickSort = new LRQuickSort(Delays, Highlights, Reads, Writes); - Sort DualPivotQuickSort = new DualPivotQuickSort(Delays, Highlights, Reads, Writes); - Sort StableQuickSort = new StableQuickSort(Delays, Highlights, Reads, Writes); - - RunExchangeSorts.this.sortNumber = 1; - RunExchangeSorts.this.sortCount = 13; - + if(runAllActive) { + RunExchangeSorts.this.sortNumber = current; + RunExchangeSorts.this.sortCount = total; + } + else { + RunExchangeSorts.this.sortNumber = 1; + } + ArrayManager.toggleMutableLength(false); ArrayVisualizer.setCategory("Exchange Sorts"); - RunExchangeSorts.this.RunIndividualSort(BubbleSort, 0, array, 25); - RunExchangeSorts.this.RunIndividualSort(SmartBubbleSort, 0, array, 22); - RunExchangeSorts.this.RunIndividualSort(CocktailShakerSort, 0, array, 22); - RunExchangeSorts.this.RunIndividualSort(OddEvenSort, 0, array, 25); - RunExchangeSorts.this.RunIndividualSort(GnomeSort, 0, array, 10); - RunExchangeSorts.this.RunIndividualSort(SmartGnomeSort, 0, array, 10); - RunExchangeSorts.this.RunIndividualSort(BinaryGnomeSort, 0, array, 10); - RunExchangeSorts.this.RunIndividualSort(CombSort, 0, array, 2); - RunExchangeSorts.this.RunIndividualSort(CircleSort, 0, array, 2.5); - RunExchangeSorts.this.RunIndividualSort(LLQuickSort, 0, array, 1.25); - RunExchangeSorts.this.RunIndividualSort(LRQuickSort, 0, array, 2); - RunExchangeSorts.this.RunIndividualSort(DualPivotQuickSort, 0, array, 1.25); - RunExchangeSorts.this.RunIndividualSort(StableQuickSort, 0, array, 1.5); + RunExchangeSorts.this.executeSortList(array); - ArrayVisualizer.setCategory("Run Exchange Sorts"); - ArrayVisualizer.setHeading("Done"); + if(!runAllActive) { + ArrayVisualizer.setCategory("Run Exchange Sorts"); + ArrayVisualizer.setHeading("Done"); + } ArrayManager.toggleMutableLength(true); } catch (Exception e) { - e.printStackTrace(); + JErrorPane.invokeErrorMessage(e); } Sounds.toggleSound(false); ArrayVisualizer.setSortingThread(null); } }); - ArrayVisualizer.runSortingThread(); } } \ No newline at end of file diff --git a/src/threads/RunHybridSorts.java b/src/threads/RunHybridSorts.java new file mode 100644 index 00000000..3ca2a196 --- /dev/null +++ b/src/threads/RunHybridSorts.java @@ -0,0 +1,144 @@ +package threads; + +import main.ArrayVisualizer; +import sorts.BinaryMergeSort; +import sorts.BottomUpMergeSort; +import sorts.BranchedPDQSort; +import sorts.BranchlessPDQSort; +import sorts.CocktailMergeSort; +import sorts.GrailSort; +import sorts.HybridCombSort; +import sorts.IntroCircleSort; +import sorts.IntroSort; +import sorts.OptimizedDualPivotQuickSort; +import sorts.SqrtSort; +import sorts.TimSort; +import sorts.WeaveMergeSort; +import sorts.WikiSort; +import templates.JErrorPane; +import templates.MultipleSortThread; +import templates.Sort; +import utils.Shuffles; + +/* + * +MIT License + +Copyright (c) 2019 w0rthy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + * + */ + +final public class RunHybridSorts extends MultipleSortThread { + private Sort HybridCombSort; + private Sort IntroCircleSort; + private Sort BinaryMergeSort; + private Sort WeaveMergeSort; + private Sort TimSort; + private Sort CocktailMergeSort; + private Sort WikiSort; + private Sort GrailSort; + private Sort SqrtSort; + private Sort IntroSort; + private Sort BottomUpMergeSort; + private Sort OptimizedDualPivotQuickSort; + private Sort BranchedPDQSort; + private Sort BranchlessPDQSort; + + public RunHybridSorts(ArrayVisualizer ArrayVisualizer) { + super(ArrayVisualizer); + this.sortCount = 14; + this.categoryCount = this.sortCount; + + HybridCombSort = new HybridCombSort(Delays, Highlights, Reads, Writes); + IntroCircleSort = new IntroCircleSort(Delays, Highlights, Reads, Writes); + BinaryMergeSort = new BinaryMergeSort(Delays, Highlights, Reads, Writes); + WeaveMergeSort = new WeaveMergeSort(Delays, Highlights, Reads, Writes); + TimSort = new TimSort(Delays, Highlights, Reads, Writes); + CocktailMergeSort = new CocktailMergeSort(Delays, Highlights, Reads, Writes); + WikiSort = new WikiSort(Delays, Highlights, Reads, Writes); + GrailSort = new GrailSort(Delays, Highlights, Reads, Writes); + SqrtSort = new SqrtSort(Delays, Highlights, Reads, Writes); + IntroSort = new IntroSort(Delays, Highlights, Reads, Writes); + BottomUpMergeSort = new BottomUpMergeSort(Delays, Highlights, Reads, Writes); + OptimizedDualPivotQuickSort = new OptimizedDualPivotQuickSort(Delays, Highlights, Reads, Writes); + BranchedPDQSort = new BranchedPDQSort(Delays, Highlights, Reads, Writes); + BranchlessPDQSort = new BranchlessPDQSort(Delays, Highlights, Reads, Writes); + } + + @Override + protected synchronized void executeSortList(int[] array) throws Exception { + RunHybridSorts.this.runIndividualSort(HybridCombSort, 0, array, 1024, 1); + RunHybridSorts.this.runIndividualSort(IntroCircleSort, 0, array, 1024, 1); + RunHybridSorts.this.runIndividualSort(BinaryMergeSort, 0, array, 2048, 1); + RunHybridSorts.this.runIndividualSort(WeaveMergeSort, 0, array, 2048, ArrayManager.getShuffle() == Shuffles.RANDOM ? 1.25 : 6); + RunHybridSorts.this.runIndividualSort(TimSort, 0, array, 2048, 1); + RunHybridSorts.this.runIndividualSort(CocktailMergeSort, 0, array, 2048, 1); + RunHybridSorts.this.runIndividualSort(WikiSort, 0, array, 2048, 1); + RunHybridSorts.this.runIndividualSort(GrailSort, 0, array, 2048, 1); + RunHybridSorts.this.runIndividualSort(SqrtSort, 0, array, 2048, 1); + RunHybridSorts.this.runIndividualSort(IntroSort, 0, array, 2048, 1); + RunHybridSorts.this.runIndividualSort(BottomUpMergeSort, 0, array, 2048, 1); + RunHybridSorts.this.runIndividualSort(OptimizedDualPivotQuickSort, 0, array, 2048, 0.75); + RunHybridSorts.this.runIndividualSort(BranchedPDQSort, 0, array, 2048, 0.75); + RunHybridSorts.this.runIndividualSort(BranchlessPDQSort, 0, array, 2048, 0.75); + } + + @Override + protected synchronized void runThread(int[] array, int current, int total, boolean runAllActive) throws Exception { + if(ArrayVisualizer.getSortingThread() != null && ArrayVisualizer.getSortingThread().isAlive()) + return; + + Sounds.toggleSound(true); + ArrayVisualizer.setSortingThread(new Thread() { + @Override + public void run() { + try{ + if(runAllActive) { + RunHybridSorts.this.sortNumber = current; + RunHybridSorts.this.sortCount = total; + } + else { + RunHybridSorts.this.sortNumber = 1; + } + + ArrayManager.toggleMutableLength(false); + + ArrayVisualizer.setCategory("Hybrid Sorts"); + + RunHybridSorts.this.executeSortList(array); + + if(!runAllActive) { + ArrayVisualizer.setCategory("Run Hybrid Sorts"); + ArrayVisualizer.setHeading("Done"); + } + + ArrayManager.toggleMutableLength(true); + } + catch (Exception e) { + JErrorPane.invokeErrorMessage(e); + } + Sounds.toggleSound(false); + ArrayVisualizer.setSortingThread(null); + } + }); + ArrayVisualizer.runSortingThread(); + } +} \ No newline at end of file diff --git a/src/threads/RunImpracticalSorts.java b/src/threads/RunImpracticalSorts.java new file mode 100644 index 00000000..69da1159 --- /dev/null +++ b/src/threads/RunImpracticalSorts.java @@ -0,0 +1,128 @@ +package threads; + +import main.ArrayVisualizer; +import sorts.BadSort; +import sorts.BogoSort; +import sorts.BubbleBogoSort; +import sorts.CocktailBogoSort; +import sorts.ExchangeBogoSort; +import sorts.LessBogoSort; +import sorts.SillySort; +import sorts.SlowSort; +import sorts.StoogeSort; +import templates.JErrorPane; +import templates.MultipleSortThread; +import templates.Sort; + +/* + * +MIT License + +Copyright (c) 2019 w0rthy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + * + */ + +final public class RunImpracticalSorts extends MultipleSortThread { + private Sort BadSort; + private Sort StoogeSort; + private Sort SillySort; + private Sort SlowSort; + private Sort ExchangeBogoSort; + private Sort BubbleBogoSort; + private Sort LessBogoSort; + private Sort CocktailBogoSort; + private Sort BogoSort; + + public RunImpracticalSorts(ArrayVisualizer ArrayVisualizer) { + super(ArrayVisualizer); + this.sortCount = 9; + this.categoryCount = this.sortCount; + + BadSort = new BadSort(Delays, Highlights, Reads, Writes); + StoogeSort = new StoogeSort(Delays, Highlights, Reads, Writes); + SillySort = new SillySort(Delays, Highlights, Reads, Writes); + SlowSort = new SlowSort(Delays, Highlights, Reads, Writes); + ExchangeBogoSort = new ExchangeBogoSort(Delays, Highlights, Reads, Writes); + BubbleBogoSort = new BubbleBogoSort(Delays, Highlights, Reads, Writes); + LessBogoSort = new LessBogoSort(Delays, Highlights, Reads, Writes); + CocktailBogoSort = new CocktailBogoSort(Delays, Highlights, Reads, Writes); + BogoSort = new BogoSort(Delays, Highlights, Reads, Writes); + } + + @Override + protected synchronized void executeSortList(int[] array) throws Exception { + RunImpracticalSorts.this.runIndividualSort(BadSort, 0, array, 64, 0.0075); + RunImpracticalSorts.this.runIndividualSort(StoogeSort, 0, array, 64, 0.005); + RunImpracticalSorts.this.runIndividualSort(SillySort, 0, array, 64, 10); + RunImpracticalSorts.this.runIndividualSort(SlowSort, 0, array, 64, 10); + Sounds.toggleSofterSounds(true); + RunImpracticalSorts.this.runIndividualSort(ExchangeBogoSort, 0, array, 32, 0.01); + RunImpracticalSorts.this.runIndividualSort(BubbleBogoSort, 0, array, 32, 0.01); + RunImpracticalSorts.this.runIndividualSort(LessBogoSort, 0, array, 16, 0.0025); + RunImpracticalSorts.this.runIndividualSort(CocktailBogoSort, 0, array, 16, 0.0025); + RunImpracticalSorts.this.runIndividualSort(BogoSort, 0, array, 8, 1); + Sounds.toggleSofterSounds(false); + } + + @Override + protected synchronized void runThread(int[] array, int current, int total, boolean runAllActive) throws Exception { + if(ArrayVisualizer.getSortingThread() != null && ArrayVisualizer.getSortingThread().isAlive()) + return; + + Sounds.toggleSound(true); + ArrayVisualizer.setSortingThread(new Thread() { + @Override + public void run() { + try{ + if(runAllActive) { + RunImpracticalSorts.this.sortNumber = current; + RunImpracticalSorts.this.sortCount = total; + } + else { + RunImpracticalSorts.this.sortNumber = 1; + } + + ArrayManager.toggleMutableLength(false); + + ArrayVisualizer.setCategory("Impractical Sorts"); + + RunImpracticalSorts.this.executeSortList(array); + + if(runAllActive) { + Thread.sleep(3000); + } + else { + ArrayVisualizer.setCategory("Run Impractical Sorts"); + ArrayVisualizer.setHeading("Done"); + } + + ArrayManager.toggleMutableLength(true); + } + catch (Exception e) { + JErrorPane.invokeErrorMessage(e); + } + Sounds.toggleSound(false); + ArrayVisualizer.setSortingThread(null); + } + }); + ArrayVisualizer.runSortingThread(); + } +} \ No newline at end of file diff --git a/src/threads/RunInsertionSorts.java b/src/threads/RunInsertionSorts.java index fddbd186..0a850f5e 100644 --- a/src/threads/RunInsertionSorts.java +++ b/src/threads/RunInsertionSorts.java @@ -5,7 +5,7 @@ import sorts.InsertionSort; import sorts.PatienceSort; import sorts.ShellSort; -import sorts.TreeSort; +import templates.JErrorPane; import templates.MultipleSortThread; import templates.Sort; @@ -36,11 +36,37 @@ of this software and associated documentation files (the "Software"), to deal */ final public class RunInsertionSorts extends MultipleSortThread { + private Sort InsertionSort; + private Sort BinaryInsertionSort; + private Sort ShellSort; + private Sort PatienceSort; + //private Sort TreeSort; + public RunInsertionSorts(ArrayVisualizer ArrayVisualizer) { super(ArrayVisualizer); + this.sortCount = 4; + //5; + //TODO: Add Treesort back in when fixed + this.categoryCount = this.sortCount; + + InsertionSort = new InsertionSort(Delays, Highlights, Reads, Writes); + BinaryInsertionSort = new BinaryInsertionSort(Delays, Highlights, Reads, Writes); + ShellSort = new ShellSort(Delays, Highlights, Reads, Writes); + PatienceSort = new PatienceSort(Delays, Highlights, Reads, Writes); + //Sort TreeSort = new TreeSort(Delays, Highlights, Reads, Writes); } - public synchronized void ReportInsertionSorts(int[] array) throws Exception { + @Override + protected synchronized void executeSortList(int[] array) throws Exception { + RunInsertionSorts.this.runIndividualSort(InsertionSort, 0, array, 128, 0.005); + RunInsertionSorts.this.runIndividualSort(BinaryInsertionSort, 0, array, 128, 0.025); + RunInsertionSorts.this.runIndividualSort(ShellSort, 0, array, 256, 0.1); + RunInsertionSorts.this.runIndividualSort(PatienceSort, 0, array, 2048, 1); + //RunInsertionSorts.this.RunIndividualSort(TreeSort, 0, array, 2048, 1); + } + + @Override + protected synchronized void runThread(int[] array, int current, int total, boolean runAllActive) throws Exception { if(ArrayVisualizer.getSortingThread() != null && ArrayVisualizer.getSortingThread().isAlive()) return; @@ -49,38 +75,34 @@ public synchronized void ReportInsertionSorts(int[] array) throws Exception { @Override public void run() { try{ - Sort InsertionSort = new InsertionSort(Delays, Highlights, Reads, Writes); - Sort BinaryInsertionSort = new BinaryInsertionSort(Delays, Highlights, Reads, Writes); - Sort ShellSort = new ShellSort(Delays, Highlights, Reads, Writes); - Sort PatienceSort = new PatienceSort(Delays, Highlights, Reads, Writes); - Sort TreeSort = new TreeSort(Delays, Highlights, Reads, Writes); - - RunInsertionSorts.this.sortNumber = 1; - RunInsertionSorts.this.sortCount = 5; - + if(runAllActive) { + RunInsertionSorts.this.sortNumber = current; + RunInsertionSorts.this.sortCount = total; + } + else { + RunInsertionSorts.this.sortNumber = 1; + } + ArrayManager.toggleMutableLength(false); ArrayVisualizer.setCategory("Insertion Sorts"); - RunInsertionSorts.this.RunIndividualSort(InsertionSort, 0, array, 2); - RunInsertionSorts.this.RunIndividualSort(BinaryInsertionSort, 0, array, 2); - RunInsertionSorts.this.RunIndividualSort(ShellSort, 0, array, 3); - RunInsertionSorts.this.RunIndividualSort(PatienceSort, 0, array, 2); - RunInsertionSorts.this.RunIndividualSort(TreeSort, 0, array, 2); + RunInsertionSorts.this.executeSortList(array); - ArrayVisualizer.setCategory("Run Insertion Sorts"); - ArrayVisualizer.setHeading("Done"); + if(!runAllActive) { + ArrayVisualizer.setCategory("Run Insertion Sorts"); + ArrayVisualizer.setHeading("Done"); + } ArrayManager.toggleMutableLength(true); } catch (Exception e) { - e.printStackTrace(); + JErrorPane.invokeErrorMessage(e); } Sounds.toggleSound(false); ArrayVisualizer.setSortingThread(null); } }); - ArrayVisualizer.runSortingThread(); } } \ No newline at end of file diff --git a/src/threads/RunMergeSorts.java b/src/threads/RunMergeSorts.java index d2725a8b..e52a26c9 100644 --- a/src/threads/RunMergeSorts.java +++ b/src/threads/RunMergeSorts.java @@ -5,6 +5,7 @@ import sorts.LazyStableSort; import sorts.MergeSort; import sorts.RotateMergeSort; +import templates.JErrorPane; import templates.MultipleSortThread; import templates.Sort; @@ -35,11 +36,32 @@ of this software and associated documentation files (the "Software"), to deal */ final public class RunMergeSorts extends MultipleSortThread { + private Sort MergeSort; + private Sort InPlaceMergeSort; + private Sort LazyStableSort; + private Sort RotateMergeSort; + public RunMergeSorts(ArrayVisualizer ArrayVisualizer) { super(ArrayVisualizer); + this.sortCount = 4; + this.categoryCount = this.sortCount; + + MergeSort = new MergeSort(Delays, Highlights, Reads, Writes); + InPlaceMergeSort = new InPlaceMergeSort(Delays, Highlights, Reads, Writes); + LazyStableSort = new LazyStableSort(Delays, Highlights, Reads, Writes); + RotateMergeSort = new RotateMergeSort(Delays, Highlights, Reads, Writes); } - public synchronized void ReportMergeSorts(int[] array) throws Exception { + @Override + protected synchronized void executeSortList(int[] array) throws Exception { + RunMergeSorts.this.runIndividualSort(MergeSort, 0, array, 2048, 1.5); + RunMergeSorts.this.runIndividualSort(InPlaceMergeSort, 0, array, 2048, 1.75); + RunMergeSorts.this.runIndividualSort(LazyStableSort, 0, array, 256, 0.2); + RunMergeSorts.this.runIndividualSort(RotateMergeSort, 0, array, 512, 0.2); + } + + @Override + protected synchronized void runThread(int[] array, int current, int total, boolean runAllActive) throws Exception { if(ArrayVisualizer.getSortingThread() != null && ArrayVisualizer.getSortingThread().isAlive()) return; @@ -48,36 +70,34 @@ public synchronized void ReportMergeSorts(int[] array) throws Exception { @Override public void run() { try{ - Sort MergeSort = new MergeSort(Delays, Highlights, Reads, Writes); - Sort InPlaceMergeSort = new InPlaceMergeSort(Delays, Highlights, Reads, Writes); - Sort LazyStableSort = new LazyStableSort(Delays, Highlights, Reads, Writes); - Sort RotateMergeSort = new RotateMergeSort(Delays, Highlights, Reads, Writes); + if(runAllActive) { + RunMergeSorts.this.sortNumber = current; + RunMergeSorts.this.sortCount = total; + } + else { + RunMergeSorts.this.sortNumber = 1; + } - RunMergeSorts.this.sortNumber = 1; - RunMergeSorts.this.sortCount = 4; - ArrayManager.toggleMutableLength(false); ArrayVisualizer.setCategory("Merge Sorts"); - RunMergeSorts.this.RunIndividualSort(MergeSort, 0, array, 1.75); - RunMergeSorts.this.RunIndividualSort(InPlaceMergeSort, 0, array, 2); - RunMergeSorts.this.RunIndividualSort(LazyStableSort, 0, array, 20); - RunMergeSorts.this.RunIndividualSort(RotateMergeSort, 0, array, 1.5); + RunMergeSorts.this.executeSortList(array); - ArrayVisualizer.setCategory("Merge Sorts"); - ArrayVisualizer.setHeading("Done"); + if(!runAllActive) { + ArrayVisualizer.setCategory("Run Merge Sorts"); + ArrayVisualizer.setHeading("Done"); + } ArrayManager.toggleMutableLength(true); } catch (Exception e) { - e.printStackTrace(); + JErrorPane.invokeErrorMessage(e); } Sounds.toggleSound(false); ArrayVisualizer.setSortingThread(null); } }); - ArrayVisualizer.runSortingThread(); } } \ No newline at end of file diff --git a/src/threads/RunMiscellaneousSorts.java b/src/threads/RunMiscellaneousSorts.java new file mode 100644 index 00000000..3f782a90 --- /dev/null +++ b/src/threads/RunMiscellaneousSorts.java @@ -0,0 +1,91 @@ +package threads; + +import main.ArrayVisualizer; +import sorts.PancakeSort; +import templates.JErrorPane; +import templates.MultipleSortThread; +import templates.Sort; + +/* + * +MIT License + +Copyright (c) 2019 w0rthy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + * + */ + +final public class RunMiscellaneousSorts extends MultipleSortThread { + private Sort PancakeSort; + + public RunMiscellaneousSorts(ArrayVisualizer ArrayVisualizer) { + super(ArrayVisualizer); + this.sortCount = 1; + this.categoryCount = this.sortCount; + + PancakeSort = new PancakeSort(Delays, Highlights, Reads, Writes); + } + + @Override + protected synchronized void executeSortList(int[] array) throws Exception { + RunMiscellaneousSorts.this.runIndividualSort(PancakeSort, 0, array, 128, 0.015); + } + + @Override + protected synchronized void runThread(int[] array, int current, int total, boolean runAllActive) throws Exception { + if(ArrayVisualizer.getSortingThread() != null && ArrayVisualizer.getSortingThread().isAlive()) + return; + + Sounds.toggleSound(true); + ArrayVisualizer.setSortingThread(new Thread() { + @Override + public void run() { + try{ + if(runAllActive) { + RunMiscellaneousSorts.this.sortNumber = current; + RunMiscellaneousSorts.this.sortCount = total; + } + else { + RunMiscellaneousSorts.this.sortNumber = 1; + } + + ArrayManager.toggleMutableLength(false); + + ArrayVisualizer.setCategory("Miscellaneous Sorts"); + + RunMiscellaneousSorts.this.executeSortList(array); + + if(!runAllActive) { + ArrayVisualizer.setCategory("Run Miscellaneous Sorts"); + ArrayVisualizer.setHeading("Done"); + } + + ArrayManager.toggleMutableLength(true); + } + catch (Exception e) { + JErrorPane.invokeErrorMessage(e); + } + Sounds.toggleSound(false); + ArrayVisualizer.setSortingThread(null); + } + }); + ArrayVisualizer.runSortingThread(); + } +} \ No newline at end of file diff --git a/src/threads/RunSelectionSorts.java b/src/threads/RunSelectionSorts.java index 51567c23..16b76546 100644 --- a/src/threads/RunSelectionSorts.java +++ b/src/threads/RunSelectionSorts.java @@ -3,6 +3,7 @@ import main.ArrayVisualizer; import sorts.CycleSort; import sorts.DoubleSelectionSort; +import sorts.FlippedMinHeapSort; import sorts.MaxHeapSort; import sorts.MinHeapSort; import sorts.PoplarHeapSort; @@ -11,6 +12,7 @@ import sorts.TernaryHeapSort; import sorts.TournamentSort; import sorts.WeakHeapSort; +import templates.JErrorPane; import templates.MultipleSortThread; import templates.Sort; @@ -41,11 +43,53 @@ of this software and associated documentation files (the "Software"), to deal */ final public class RunSelectionSorts extends MultipleSortThread { + private Sort SelectionSort; + private Sort DoubleSelectionSort; + private Sort CycleSort; + private Sort MaxHeapSort; + private Sort MinHeapSort; + private Sort FlippedMinHeapSort; + private Sort WeakHeapSort; + private Sort TernaryHeapSort; + private Sort SmoothSort; + private Sort PoplarHeapSort; + private Sort TournamentSort; + public RunSelectionSorts(ArrayVisualizer ArrayVisualizer) { super(ArrayVisualizer); + this.sortCount = 11; + this.categoryCount = this.sortCount; + + SelectionSort = new SelectionSort(Delays, Highlights, Reads, Writes); + DoubleSelectionSort = new DoubleSelectionSort(Delays, Highlights, Reads, Writes); + CycleSort = new CycleSort(Delays, Highlights, Reads, Writes); + MaxHeapSort = new MaxHeapSort(Delays, Highlights, Reads, Writes); + MinHeapSort = new MinHeapSort(Delays, Highlights, Reads, Writes); + FlippedMinHeapSort = new FlippedMinHeapSort(Delays, Highlights, Reads, Writes); + WeakHeapSort = new WeakHeapSort(Delays, Highlights, Reads, Writes); + TernaryHeapSort = new TernaryHeapSort(Delays, Highlights, Reads, Writes); + SmoothSort = new SmoothSort(Delays, Highlights, Reads, Writes); + PoplarHeapSort = new PoplarHeapSort(Delays, Highlights, Reads, Writes); + TournamentSort = new TournamentSort(Delays, Highlights, Reads, Writes); } - public synchronized void ReportSelectionSorts(int[] array) throws Exception { + @Override + protected synchronized void executeSortList(int[] array) throws Exception { + RunSelectionSorts.this.runIndividualSort(SelectionSort, 0, array, 128, 0.01); + RunSelectionSorts.this.runIndividualSort(DoubleSelectionSort, 0, array, 128, 0.01); + RunSelectionSorts.this.runIndividualSort(CycleSort, 0, array, 128, 0.01); + RunSelectionSorts.this.runIndividualSort(MaxHeapSort, 0, array, 2048, 1.5); + RunSelectionSorts.this.runIndividualSort(MinHeapSort, 0, array, 2048, 1.5); + RunSelectionSorts.this.runIndividualSort(FlippedMinHeapSort, 0, array, 2048, 1.5); + RunSelectionSorts.this.runIndividualSort(WeakHeapSort, 0, array, 2048, 1); + RunSelectionSorts.this.runIndividualSort(TernaryHeapSort, 0, array, 2048, 1); + RunSelectionSorts.this.runIndividualSort(SmoothSort, 0, array, 2048, 1.5); + RunSelectionSorts.this.runIndividualSort(PoplarHeapSort, 0, array, 2048, 1); + RunSelectionSorts.this.runIndividualSort(TournamentSort, 0, array, 2048, 1.5); + } + + @Override + protected synchronized void runThread(int[] array, int current, int total, boolean runAllActive) throws Exception { if(ArrayVisualizer.getSortingThread() != null && ArrayVisualizer.getSortingThread().isAlive()) return; @@ -54,48 +98,34 @@ public synchronized void ReportSelectionSorts(int[] array) throws Exception { @Override public void run() { try{ - Sort SelectionSort = new SelectionSort(Delays, Highlights, Reads, Writes); - Sort DoubleSelectionSort = new DoubleSelectionSort(Delays, Highlights, Reads, Writes); - Sort CycleSort = new CycleSort(Delays, Highlights, Reads, Writes); - Sort MaxHeapSort = new MaxHeapSort(Delays, Highlights, Reads, Writes); - Sort MinHeapSort = new MinHeapSort(Delays, Highlights, Reads, Writes); - Sort WeakHeapSort = new WeakHeapSort(Delays, Highlights, Reads, Writes); - Sort TernaryHeapSort = new TernaryHeapSort(Delays, Highlights, Reads, Writes); - Sort SmoothSort = new SmoothSort(Delays, Highlights, Reads, Writes); - Sort PoplarHeapSort = new PoplarHeapSort(Delays, Highlights, Reads, Writes); - Sort TournamentSort = new TournamentSort(Delays, Highlights, Reads, Writes); - - RunSelectionSorts.this.sortNumber = 1; - RunSelectionSorts.this.sortCount = 10; - + if(runAllActive) { + RunSelectionSorts.this.sortNumber = current; + RunSelectionSorts.this.sortCount = total; + } + else { + RunSelectionSorts.this.sortNumber = 1; + } + ArrayManager.toggleMutableLength(false); ArrayVisualizer.setCategory("Selection Sorts"); - RunSelectionSorts.this.RunIndividualSort(SelectionSort, 0, array, 5); - RunSelectionSorts.this.RunIndividualSort(DoubleSelectionSort, 0, array, 5); - RunSelectionSorts.this.RunIndividualSort(CycleSort, 0, array, 3); - RunSelectionSorts.this.RunIndividualSort(MaxHeapSort, 0, array, 1.25); - RunSelectionSorts.this.RunIndividualSort(MinHeapSort, 0, array, 1.25); - RunSelectionSorts.this.RunIndividualSort(WeakHeapSort, 0, array, 1.25); - RunSelectionSorts.this.RunIndividualSort(TernaryHeapSort, 0, array, 1.25); - RunSelectionSorts.this.RunIndividualSort(SmoothSort, 0, array, 2); - RunSelectionSorts.this.RunIndividualSort(PoplarHeapSort, 0, array, 1); - RunSelectionSorts.this.RunIndividualSort(TournamentSort, 0, array, 1.5); + RunSelectionSorts.this.executeSortList(array); - ArrayVisualizer.setCategory("Run Selection Sorts"); - ArrayVisualizer.setHeading("Done"); + if(!runAllActive) { + ArrayVisualizer.setCategory("Run Selection Sorts"); + ArrayVisualizer.setHeading("Done"); + } ArrayManager.toggleMutableLength(true); } catch (Exception e) { - e.printStackTrace(); + JErrorPane.invokeErrorMessage(e); } Sounds.toggleSound(false); ArrayVisualizer.setSortingThread(null); } }); - ArrayVisualizer.runSortingThread(); } } \ No newline at end of file diff --git a/src/utils/Delays.java b/src/utils/Delays.java index 3c5e7be2..1d224c37 100644 --- a/src/utils/Delays.java +++ b/src/utils/Delays.java @@ -1,9 +1,14 @@ package utils; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.NumberFormat; +import java.util.Locale; import java.util.logging.Level; import java.util.logging.Logger; import main.ArrayVisualizer; +import templates.JErrorPane; /* * @@ -37,19 +42,60 @@ final public class Delays { private double addamt; private double delay; + private double nanos; - public Delays() { + private volatile double currentDelay; + + private DecimalFormat formatter; + private DecimalFormatSymbols symbols; + + private Sounds Sounds; + + public Delays(ArrayVisualizer ArrayVisualizer) { this.SLEEPRATIO = 1.0; this.SKIPPED = false; - this.addamt = 0.0; + this.addamt = 0; + + this.formatter = (DecimalFormat) NumberFormat.getInstance(Locale.US); + this.symbols = this.formatter.getDecimalFormatSymbols(); + + this.symbols.setGroupingSeparator(','); + this.formatter.setDecimalFormatSymbols(this.symbols); + + this.Sounds = ArrayVisualizer.getSounds(); } + public String displayCurrentDelay() { + String currDelay = ""; + + if(this.currentDelay == 0 || this.SKIPPED) { + currDelay = "0"; + } + else if(this.currentDelay < 0.001) { + currDelay = "< 0.001"; + } + else { + currDelay = formatter.format(this.currentDelay); + } + + return currDelay; + } public double getCurrentDelay() { - return this.delay; + return this.currentDelay; } public void setCurrentDelay(double value) { this.delay = value; } + public void updateCurrentDelay(double oldRatio, double newRatio) { + this.delay = (this.delay * oldRatio) / newRatio; + this.currentDelay = this.delay; + this.Sounds.changeNoteDelayAndFilter((int) this.currentDelay); + this.addamt = 0; + + if(this.currentDelay < 0) { + this.delay = this.currentDelay = 0; + } + } public double getSleepRatio() { return this.SLEEPRATIO; @@ -63,6 +109,7 @@ public boolean skipped() { } public void changeSkipped(boolean Bool) { this.SKIPPED = Bool; + if(this.SKIPPED) this.Sounds.changeNoteDelayAndFilter(1); } public void sleep(double millis){ @@ -70,22 +117,26 @@ public void sleep(double millis){ return; } - this.delay = (millis * (1 / this.SLEEPRATIO)); - this.addamt += this.delay; + this.delay += (millis * (1 / this.SLEEPRATIO)); + this.currentDelay = (millis * (1 / this.SLEEPRATIO)); - long amt = (long) this.delay; - if(this.addamt >= 1){ - amt += (int) this.addamt; - this.addamt -= (int) this.addamt; - } + this.Sounds.changeNoteDelayAndFilter((int) this.currentDelay); try { // With this for loop, you can change the speed of sorts without waiting for the current delay to finish. - for(int i = 0; i < amt / this.SLEEPRATIO; i++) { - Thread.sleep(1); + if(!this.SKIPPED) { + while(this.delay >= 1) { + Thread.sleep(1); + this.delay--; + } + } + else { + this.delay = 0; } } catch(Exception ex) { - Logger.getLogger(ArrayVisualizer.class.getName()).log(Level.SEVERE, null, ex); + JErrorPane.invokeErrorMessage(ex); } + + this.currentDelay = 0; } } \ No newline at end of file diff --git a/src/utils/Highlights.java b/src/utils/Highlights.java index bd49cf86..0b16c65c 100644 --- a/src/utils/Highlights.java +++ b/src/utils/Highlights.java @@ -2,6 +2,8 @@ import java.util.Arrays; +import main.ArrayVisualizer; + /* * MIT License @@ -53,7 +55,11 @@ final public class Highlights { private volatile boolean fancyFinish; private volatile int trackFinish; - public Highlights(int maximumLength) { + private ArrayVisualizer ArrayVisualizer; + + public Highlights(ArrayVisualizer ArrayVisualizer, int maximumLength) { + this.ArrayVisualizer = ArrayVisualizer; + this.Highlights = new int[maximumLength]; this.FANCYFINISH = true; this.maxIndexMarked = 0; @@ -86,6 +92,11 @@ public void resetFancyFinish() { this.trackFinish = -1; // Magic number that clears the green sweep animation } + //TODO: Move Analysis to Highlights + public void toggleAnalysis(boolean Bool) { + this.ArrayVisualizer.toggleAnalysis(Bool); + } + public int getMaxIndex() { return this.maxIndexMarked; } diff --git a/src/utils/Reads.java b/src/utils/Reads.java index 2998f270..a2fa1c13 100644 --- a/src/utils/Reads.java +++ b/src/utils/Reads.java @@ -69,7 +69,7 @@ public void addComparison() { this.comparisons++; } - public String getComparisons() { + public String displayComparisons() { if(this.comparisons < 0) { this.comparisons = Long.MIN_VALUE; return "Over " + this.formatter.format(Long.MAX_VALUE); @@ -80,18 +80,26 @@ public String getComparisons() { } } + public long getComparisons() { + return this.comparisons; + } + + public void setComparisons(long value) { + this.comparisons = value; + } + public int compare(int left, int right) { this.comparisons++; int cmpVal = 0; - if(Timer.timerEnabled()) Timer.startLap(); + Timer.startLap(); if(left > right) cmpVal = 1; else if(left < right) cmpVal = -1; else cmpVal = 0; - if(Timer.timerEnabled()) Timer.stopLap(); + Timer.stopLap(); return cmpVal; } @@ -102,11 +110,11 @@ public int analyzeMax(int[] array, int length, double sleep, boolean mark) { int max = 0; for(int i = 0; i < length; i++) { - if(Timer.timerEnabled()) Timer.startLap(); + Timer.startLap(); if(array[i] > max) max = array[i]; - if(Timer.timerEnabled()) Timer.stopLap(); + Timer.stopLap(); if(mark) { Highlights.markArray(1, i); @@ -125,12 +133,13 @@ public int analyzeMaxLog(int[] array, int length, int base, double sleep, boolea int max = 0; for(int i = 0; i < length; i++) { - if(Timer.timerEnabled()) Timer.startLap(); - int log = (int) (Math.log(array[i]) / Math.log(base)); + + Timer.startLap(); + if(log > max) max = log; - if(Timer.timerEnabled()) Timer.stopLap(); + Timer.stopLap(); if(mark) { Highlights.markArray(1, i); @@ -150,20 +159,20 @@ public int analyzeBit(int[] array, int length) { int max = 0; for(int i = 0; i < length; i++) { - if(Timer.timerEnabled()) Timer.startLap(); + Timer.startLap(); max = Math.max(max, array[i]); - if(Timer.timerEnabled()) Timer.stopLap(); + Timer.stopLap(); Highlights.markArray(1, i); Delays.sleep(0.75); } - if(Timer.timerEnabled()) Timer.startLap(); + Timer.startLap(); int analysis = 31 - Integer.numberOfLeadingZeros(max); - if(Timer.timerEnabled()) Timer.stopLap(); + Timer.stopLap(); ArrayVisualizer.toggleAnalysis(false); return analysis; diff --git a/src/utils/Renderer.java b/src/utils/Renderer.java index b0d33926..a46fa377 100644 --- a/src/utils/Renderer.java +++ b/src/utils/Renderer.java @@ -1,15 +1,8 @@ package utils; import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Graphics2D; import main.ArrayVisualizer; -import visuals.Bars; -import visuals.Circular; -import visuals.Hoops; -import visuals.Mesh; -import visuals.Pixels; import visuals.VisualStyles; /* @@ -38,6 +31,8 @@ of this software and associated documentation files (the "Software"), to deal * */ +// TODO: Many of these methods should exist solely in visual classes + final class WindowState { private boolean windowUpdated; private boolean windowResized; @@ -57,12 +52,6 @@ public boolean resized() { } final public class Renderer { - private Bars Bars; - private Circular Circular; - private Hoops Hoops; - private Mesh Mesh; - private Pixels Pixels; - private volatile double xscl; //TODO: Change to xScale/yScale private volatile double yscl; @@ -71,8 +60,6 @@ final public class Renderer { private int linkedpixdrawx; //TODO: Change names private int linkedpixdrawy; - private int frames; - private int doth; //TODO: Change names private int dotw; private int dots; //TODO: Change name to dotDims/dotDimensions @@ -118,27 +105,24 @@ public void setLineY(int y) { this.linkedpixdrawy = y; } - public void updateGraphics(ArrayVisualizer ArrayVisualizer) { + public static void createRenders(ArrayVisualizer ArrayVisualizer) { ArrayVisualizer.createVolatileImage(); ArrayVisualizer.setMainRender(); ArrayVisualizer.setExtraRender(); } - public void initializeVisuals(ArrayVisualizer ArrayVisualizer, VisualStyles VisualStyles) { - this.Bars = new Bars(); - this.Circular = new Circular(); - this.Hoops = new Hoops(); - this.Mesh = new Mesh(); - this.Pixels = new Pixels(); - - this.frames = 0; - this.updateGraphics(ArrayVisualizer); + public static void initializeVisuals(ArrayVisualizer ArrayVisualizer) { + Renderer.createRenders(ArrayVisualizer); ArrayVisualizer.updateFontSize(); ArrayVisualizer.repositionFrames(); } + public static void updateGraphics(ArrayVisualizer ArrayVisualizer) { + Renderer.createRenders(ArrayVisualizer); + ArrayVisualizer.updateVisuals(); + } - private WindowState checkWindowResizeAndReposition(ArrayVisualizer ArrayVisualizer) { + private static WindowState checkWindowResizeAndReposition(ArrayVisualizer ArrayVisualizer) { boolean windowUpdate = false; boolean windowResize = false; @@ -174,7 +158,7 @@ public void updateVisuals(ArrayVisualizer ArrayVisualizer) { if(WindowState.resized()) { ArrayVisualizer.updateDimensions(); - this.updateGraphics(ArrayVisualizer); + updateGraphics(ArrayVisualizer); } ArrayVisualizer.updateFontSize(); @@ -193,8 +177,6 @@ public void updateVisuals(ArrayVisualizer ArrayVisualizer) { this.linkedpixdrawx = 0; this.linkedpixdrawy = 0; - this.frames++; - this.dotw = (int) (2 * (ArrayVisualizer.currentWidth() / 640.0)); this.doth = (int) (2 * (ArrayVisualizer.currentHeight() / 480.0)); this.dots = (this.dotw + this.doth) / 2; //TODO: Does multiply/divide by 2 like this cancel out?? @@ -202,177 +184,7 @@ public void updateVisuals(ArrayVisualizer ArrayVisualizer) { ArrayVisualizer.resetMainStroke(); } - public Color getIntColor(int i, int length) { - return Color.getHSBColor(((float) i / length), 1.0F, 0.8F); - } - - public void markBar(Graphics2D bar, boolean color, boolean rainbow, boolean analysis) { - if(color || rainbow) { - if(analysis) bar.setColor(Color.WHITE); - else bar.setColor(Color.BLACK); - } - else if(analysis) bar.setColor(Color.BLUE); - else bar.setColor(Color.RED); - } - private void markBarFancy(Graphics2D bar, boolean color, boolean rainbow) { - if(!color && !rainbow) bar.setColor(Color.RED); - else bar.setColor(Color.BLACK); - } - - public void lineMark(Graphics2D line, double width, boolean color, boolean analysis) { - line.setStroke(new BasicStroke((float) (9f * (width / 1280f)))); - if(color) line.setColor(Color.BLACK); - else if(analysis) line.setColor(Color.BLUE); - else line.setColor(Color.RED); - } - //TODO: Change name to markLineFancy - public void lineFancy(Graphics2D line, double width) { - line.setColor(Color.GREEN); - line.setStroke(new BasicStroke((float) (9f * (width / 1280f)))); - } - //TODO: Change name to clearLine - public void lineClear(Graphics2D line, boolean color, int[] array, int i, int length, double width) { - if(color) line.setColor(getIntColor(array[i], length)); - else line.setColor(Color.WHITE); - line.setStroke(new BasicStroke((float) (3f * (width / 1280f)))); - } - - public void setRectColor(Graphics2D rect, boolean color, boolean analysis) { - if(color) rect.setColor(Color.WHITE); - else if(analysis) rect.setColor(Color.BLUE); - else rect.setColor(Color.RED); - } - - @SuppressWarnings("fallthrough") - //The longer the array length, the more bars marked. Makes the visual easier to see when bars are thinner. - public void colorMarkedBars(int logOfLen, int index, Highlights Highlights, Graphics2D mainRender, boolean colorEnabled, boolean rainbowEnabled, boolean analysis) { - switch(logOfLen) { - case 12: if(Highlights.containsPosition(index - 3)) markBar(mainRender, colorEnabled, rainbowEnabled, analysis); - case 11: if(Highlights.containsPosition(index - 2)) markBar(mainRender, colorEnabled, rainbowEnabled, analysis); - case 10: if(Highlights.containsPosition(index - 1)) markBar(mainRender, colorEnabled, rainbowEnabled, analysis); - default: if(Highlights.containsPosition(index)) markBar(mainRender, colorEnabled, rainbowEnabled, analysis); - } - } - - @SuppressWarnings("fallthrough") - public void markHoops(int logOfLen, int index, Highlights Highlights, Graphics2D mainRender) { - switch(logOfLen) { - case 12: if(Highlights.containsPosition(index - 11)) mainRender.setColor(Color.BLACK); - case 11: if(Highlights.containsPosition(index - 10)) mainRender.setColor(Color.BLACK); - case 10: if(Highlights.containsPosition(index - 9)) mainRender.setColor(Color.BLACK); - case 9: if(Highlights.containsPosition(index - 8)) mainRender.setColor(Color.BLACK); - case 8: if(Highlights.containsPosition(index - 7)) mainRender.setColor(Color.BLACK); - case 7: if(Highlights.containsPosition(index - 6)) mainRender.setColor(Color.BLACK); - case 6: if(Highlights.containsPosition(index - 5)) mainRender.setColor(Color.BLACK); - case 5: if(Highlights.containsPosition(index - 4)) mainRender.setColor(Color.BLACK); - case 4: if(Highlights.containsPosition(index - 3)) mainRender.setColor(Color.BLACK); - case 3: if(Highlights.containsPosition(index - 2)) mainRender.setColor(Color.BLACK); - case 2: if(Highlights.containsPosition(index - 1)) mainRender.setColor(Color.BLACK); - default: if(Highlights.containsPosition(index)) mainRender.setColor(Color.BLACK); - } - } - - @SuppressWarnings("fallthrough") - public void drawFancyFinish(int logOfLen, int index, int position, Graphics2D mainRender, boolean colorEnabled, boolean rainbowEnabled) { - switch(logOfLen) { - case 12: if(index == position - 11) markBarFancy(mainRender, colorEnabled, rainbowEnabled); - case 11: if(index == position - 10) markBarFancy(mainRender, colorEnabled, rainbowEnabled); - case 10: if(index == position - 9) markBarFancy(mainRender, colorEnabled, rainbowEnabled); - case 9: if(index == position - 8) markBarFancy(mainRender, colorEnabled, rainbowEnabled); - case 8: if(index == position - 7) markBarFancy(mainRender, colorEnabled, rainbowEnabled); - case 7: if(index == position - 6) markBarFancy(mainRender, colorEnabled, rainbowEnabled); - case 6: if(index == position - 5) markBarFancy(mainRender, colorEnabled, rainbowEnabled); - case 5: if(index == position - 4) markBarFancy(mainRender, colorEnabled, rainbowEnabled); - case 4: if(index == position - 3) markBarFancy(mainRender, colorEnabled, rainbowEnabled); - case 3: if(index == position - 2) markBarFancy(mainRender, colorEnabled, rainbowEnabled); - case 2: if(index == position - 1) markBarFancy(mainRender, colorEnabled, rainbowEnabled); - default: if(index == position) markBarFancy(mainRender, colorEnabled, rainbowEnabled); - } - } - - @SuppressWarnings("fallthrough") - public void drawFancyFinishLine(int logOfLen, int index, int position, Graphics2D mainRender, double width, boolean colorEnabled) { - switch(logOfLen) { - case 12: if(index == position - 11) lineMark(mainRender, width, colorEnabled, false); - case 11: if(index == position - 10) lineMark(mainRender, width, colorEnabled, false); - case 10: if(index == position - 9) lineMark(mainRender, width, colorEnabled, false); - case 9: if(index == position - 8) lineMark(mainRender, width, colorEnabled, false); - case 8: if(index == position - 7) lineMark(mainRender, width, colorEnabled, false); - case 7: if(index == position - 6) lineMark(mainRender, width, colorEnabled, false); - case 6: if(index == position - 5) lineMark(mainRender, width, colorEnabled, false); - case 5: if(index == position - 4) lineMark(mainRender, width, colorEnabled, false); - case 4: if(index == position - 3) lineMark(mainRender, width, colorEnabled, false); - case 3: if(index == position - 2) lineMark(mainRender, width, colorEnabled, false); - case 2: if(index == position - 1) lineMark(mainRender, width, colorEnabled, false); - default: if(index == position) lineMark(mainRender, width, colorEnabled, false); - } - } - - @SuppressWarnings("fallthrough") - public void drawFancyFinishHoops(int logOfLen, int index, int position, Graphics2D mainRender) { - switch(logOfLen) { - case 12: if(index == position - 11) mainRender.setColor(Color.BLACK); - case 11: if(index == position - 10) mainRender.setColor(Color.BLACK); - case 10: if(index == position - 9) mainRender.setColor(Color.BLACK); - case 9: if(index == position - 8) mainRender.setColor(Color.BLACK); - case 8: if(index == position - 7) mainRender.setColor(Color.BLACK); - case 7: if(index == position - 6) mainRender.setColor(Color.BLACK); - case 6: if(index == position - 5) mainRender.setColor(Color.BLACK); - case 5: if(index == position - 4) mainRender.setColor(Color.BLACK); - case 4: if(index == position - 3) mainRender.setColor(Color.BLACK); - case 3: if(index == position - 2) mainRender.setColor(Color.BLACK); - case 2: if(index == position - 1) mainRender.setColor(Color.BLACK); - default: if(index == position) mainRender.setColor(Color.BLACK); - } - } - - public int getTriangleHeight(int length, double height) { - switch(length) { - case 2: height *= 20; break; - case 4: height *= 13; break; - case 8: height *= 8; break; - case 16: - case 32: height *= 4.4; break; - case 64: height *= 2.3; break; - case 128: height *= 2.35; break; - case 256: height *= 1.22; break; - default: height *= 1; - } - - return (int) height; - } - - public int getTrianglesPerRow(int length, int trianglesPerColumn) { - int trianglesPerRow; - - switch(length) { - case 32: - case 64: trianglesPerRow = 4; break; - case 128: - case 256: trianglesPerRow = 8; break; - default: trianglesPerRow = Math.max(length / trianglesPerColumn, 2); - } - - return trianglesPerRow; - } - - public void drawCircle(int[] array, ArrayVisualizer ArrayVisualizer, Graphics2D mainRender, Graphics2D extraRender, Highlights Highlights) { - Circular.drawVisual(array, ArrayVisualizer, this, mainRender, extraRender, Highlights); - } - public void drawHoops(int[] array, ArrayVisualizer ArrayVisualizer, Graphics2D mainRender, Graphics2D extraRender, Highlights Highlights) { - Hoops.drawVisual(array, ArrayVisualizer, this, mainRender, extraRender, Highlights); - } - public void drawMesh(int[] array, ArrayVisualizer ArrayVisualizer, Graphics2D mainRender, Graphics2D extraRender, Highlights Highlights) { - Mesh.drawVisual(array, ArrayVisualizer, this, mainRender, extraRender, Highlights); - } - public void drawBars(int[] array, ArrayVisualizer ArrayVisualizer, Graphics2D mainRender, Graphics2D extraRender, Highlights Highlights) { - Bars.drawVisual(array, ArrayVisualizer, this, mainRender, extraRender, Highlights); - } - public void drawPixels(int[] array, ArrayVisualizer ArrayVisualizer, Graphics2D mainRender, Graphics2D extraRender, Highlights Highlights) { - Pixels.drawVisual(array, ArrayVisualizer, this, mainRender, extraRender, Highlights); - } - - public void drawVisual(VisualStyles VisualStyles, int[] array, ArrayVisualizer ArrayVisualizer, Graphics2D mainRender, Graphics2D extraRender, Highlights Highlights) { - VisualStyles.drawVisual(array, ArrayVisualizer, this, mainRender, extraRender, Highlights); + public void drawVisual(VisualStyles VisualStyles, int[] array, ArrayVisualizer ArrayVisualizer, Highlights Highlights) { + VisualStyles.drawVisual(array, ArrayVisualizer, this, Highlights); } } \ No newline at end of file diff --git a/src/utils/Shuffles.java b/src/utils/Shuffles.java index c81f9d08..1e3e6e9e 100644 --- a/src/utils/Shuffles.java +++ b/src/utils/Shuffles.java @@ -30,12 +30,18 @@ of this software and associated documentation files (the "Software"), to deal public enum Shuffles { RANDOM { + // If you want to learn why the random shuffle was changed, + // I highly encourage you read this. It's quite fascinating: + // http://datagenetics.com/blog/november42014/index.html + @Override public void shuffleArray(int[] array, ArrayVisualizer ArrayVisualizer, Delays Delays, Highlights Highlights, Writes Writes) { int currentLen = ArrayVisualizer.getCurrentLength(); + //TODO: Consider separate method for(int i = 0; i < currentLen; i++){ - Writes.swap(array, i, (int)(Math.random()*currentLen), 0, true, false); + int randomIndex = (int) (Math.random() * (currentLen - i)) + i; + Writes.swap(array, i, randomIndex, 0, true, false); if(ArrayVisualizer.shuffleEnabled()) Delays.sleep(1); } @@ -70,7 +76,8 @@ public void shuffleArray(int[] array, ArrayVisualizer ArrayVisualizer, Delays De if(ArrayVisualizer.shuffleEnabled()) Delays.sleep(1); } for(int i = 0; i < currentLen; i++){ - Writes.swap(array, i, (int)(Math.random()*currentLen), 0, true, false); + int randomIndex = (int) (Math.random() * (currentLen - i)) + i; + Writes.swap(array, i, randomIndex, 0, true, false); if(ArrayVisualizer.shuffleEnabled()) Delays.sleep(1); } @@ -83,9 +90,22 @@ public void shuffleArray(int[] array, ArrayVisualizer ArrayVisualizer, Delays De for(int i = 0; i < Math.max(currentLen / 20, 1); i++){ Writes.swap(array, (int)(Math.random()*currentLen), (int)(Math.random()*currentLen), 0, true, false); - if(ArrayVisualizer.shuffleEnabled()) Delays.sleep(2); } + + /* + int step = (int) Math.sqrt(currentLen); + + //TODO: *Strongly* consider randomSwap method + for(int i = 0; i < currentLen; i += step){ + int randomIndex = (int) (Math.random() * step); + randomIndex = Math.max(randomIndex, 1); + randomIndex = Math.min(randomIndex, currentLen - i - 1); + Writes.swap(array, i, i + randomIndex, 0, true, false); + + if(ArrayVisualizer.shuffleEnabled()) Delays.sleep(2); + } + */ } }, ALREADY { diff --git a/src/utils/Sounds.java b/src/utils/Sounds.java index fcc76164..3f5c27a0 100644 --- a/src/utils/Sounds.java +++ b/src/utils/Sounds.java @@ -1,9 +1,7 @@ package utils; -import java.io.File; -import java.io.IOException; +import java.io.InputStream; -import javax.sound.midi.InvalidMidiDataException; import javax.sound.midi.MidiChannel; import javax.sound.midi.MidiSystem; import javax.sound.midi.MidiUnavailableException; @@ -11,6 +9,9 @@ import javax.swing.JOptionPane; import main.ArrayVisualizer; +import soundfont.SFXFetcher; +import soundfont.SFXFetcher; +import templates.JErrorPane; /* * @@ -50,12 +51,15 @@ final public class Sounds { private Synthesizer synth; private MidiChannel[] channels; + private volatile int noteDelay; + private volatile boolean SOUND; private boolean MIDI; private int NUMCHANNELS; //Number of Audio Channels private double PITCHMIN; //Minimum Pitch private double PITCHMAX; //Maximum Pitch private double SOUNDMUL; + private boolean SOFTERSOUNDS; final private int REVERB = 91; @@ -71,24 +75,35 @@ public Sounds(int[] array, ArrayVisualizer arrayVisualizer) { this.PITCHMAX = 105d; this.SOUNDMUL = 1d; + this.noteDelay = 1; + try { MidiSystem.getSequencer(false); this.synth = MidiSystem.getSynthesizer(); this.synth.open(); } catch (MidiUnavailableException e) { - JOptionPane.showMessageDialog(null, "The MIDI device is unavailable, possibly because it is already being used by another application. Sound is disabled."); - e.printStackTrace(); + JOptionPane.showMessageDialog(null, e.getMessage() + ": The MIDI device is unavailable, possibly because it is already being used by another application. Sound is disabled."); } + SFXFetcher sfxFetcher = new SFXFetcher(); + InputStream stream = sfxFetcher.getSFXFile(); try { - this.synth.loadAllInstruments(MidiSystem.getSoundbank(new File("soundfont/sfx.dls"))); - } catch (InvalidMidiDataException | IOException e1) { - e1.printStackTrace(); + this.synth.loadAllInstruments(MidiSystem.getSoundbank(stream)); + } catch (Exception e) { + JErrorPane.invokeErrorMessage(e); + } + finally { + try { + stream.close(); + } catch (Exception e) { + JErrorPane.invokeErrorMessage(e); + } } this.channels = new MidiChannel[this.NUMCHANNELS]; for(int i = 0; i < this.NUMCHANNELS; i++) { this.channels[i] = this.synth.getChannels()[i]; + //this.channels[i].programChange(this.synth.getLoadedInstruments()[197].getPatch().getProgram()); this.channels[i].programChange(this.synth.getLoadedInstruments()[16].getPatch().getProgram()); // MIDI Instrument 16 is a Rock Organ. this.channels[i].setChannelPressure(1); } @@ -103,7 +118,7 @@ public void run() { for(MidiChannel channel : channels) { channel.allNotesOff(); } - if(SOUND == false || MIDI == false) { + if(SOUND == false || MIDI == false || JErrorPane.errorMessageActive) { continue; } @@ -129,19 +144,21 @@ public void run() { channels[voice].noteOn(pitchmajor, vel); channels[voice].setPitchBend(pitchminor); channels[voice].controlChange(REVERB, 10); - + if((++voice % Math.max(noteCount, 1)) == 0) break; } } catch (Exception e) { - e.printStackTrace(); + JErrorPane.invokeErrorMessage(e); } } try { - sleep(1); + for(int i = 0; i < Sounds.this.noteDelay; i++) { + sleep(1); + } } catch(Exception e) { - e.printStackTrace(); + JErrorPane.invokeErrorMessage(e); } } } @@ -156,6 +173,14 @@ public synchronized void toggleSound(boolean val) { this.MIDI = val; } + //Double check logic + public void toggleSofterSounds(boolean val) { + this.SOFTERSOUNDS = val; + + if(this.SOFTERSOUNDS) this.SOUNDMUL = 0.01; + else this.SOUNDMUL = 1; + } + public double getVolume() { return this.SOUNDMUL; } @@ -163,6 +188,22 @@ public void changeVolume(double val) { this.SOUNDMUL = val; } + public void changeNoteDelayAndFilter(int noteFactor) { + if(noteFactor != this.noteDelay) { + if(noteFactor > 1) { + this.noteDelay = noteFactor; + this.SOUNDMUL = 1d / noteFactor; + } + //Double check logic + else { + this.noteDelay = 1; + + if(this.SOFTERSOUNDS) this.SOUNDMUL = 0.01; + else this.SOUNDMUL = 1; + } + } + } + public void startAudioThread() { AudioThread.start(); } diff --git a/src/utils/Timer.java b/src/utils/Timer.java index 05e795f5..d3882007 100644 --- a/src/utils/Timer.java +++ b/src/utils/Timer.java @@ -82,10 +82,10 @@ else if(this.realTimer == 0) { if(this.timerEnabled) return "0.000ms"; else return "---ms"; } - else if(this.realTimer < 0.001) return "<0.001ms"; - else if(this.realTimer >= 60000.000) return this.formatter.format((int) (this.realTimer / 60000)) + "m" + (int) ((this.realTimer % 60000) / 1000) + "s"; - else if(this.realTimer >= 1000.000) return this.formatter.format(this.realTimer / 1000) + "s"; - else return this.formatter.format(this.realTimer) + "ms"; + else if(this.realTimer < 0.001) return "< 0.001ms"; + else if(this.realTimer >= 60000.000) return "~" + this.formatter.format((int) (this.realTimer / 60000)) + "m" + (int) ((this.realTimer % 60000) / 1000) + "s"; + else if(this.realTimer >= 1000.000) return "~" + this.formatter.format(this.realTimer / 1000) + "s"; + else return "~" + this.formatter.format(this.realTimer) + "ms"; } public void toggleRealTimer(boolean Bool) { @@ -107,12 +107,12 @@ public boolean timerEnabled() { } public void startLap() { - this.timeStart = System.nanoTime(); + if(this.timerEnabled) this.timeStart = System.nanoTime(); } public void stopLap() { this.timeStop = System.nanoTime(); - this.realTimer += (timeStop - timeStart) / 1e+6; + if(this.timerEnabled) this.realTimer += (timeStop - timeStart) * 1e-6d; } void manualAddTime(long milliseconds) { diff --git a/src/utils/Writes.java b/src/utils/Writes.java index 5032cefe..09bf7712 100644 --- a/src/utils/Writes.java +++ b/src/utils/Writes.java @@ -104,8 +104,8 @@ public String getTempWrites() { return "Over " + this.formatter.format(Long.MAX_VALUE); } else { - if(this.tempWrites == 1) return this.tempWrites + " Write to Auxillary Array(s)"; - else return this.formatter.format(this.tempWrites) + " Writes to Auxillary Array(s)"; + if(this.tempWrites == 1) return this.tempWrites + " Write to Auxiliary Array(s)"; + else return this.formatter.format(this.tempWrites) + " Writes to Auxiliary Array(s)"; } } @@ -142,13 +142,13 @@ private void markSwap(int a, int b) { public void swap(int[] array, int a, int b, double pause, boolean mark, boolean auxwrite) { if(mark) this.markSwap(a, b); - if(Timer.timerEnabled()) Timer.startLap(); + Timer.startLap(); int temp = array[a]; array[a] = array[b]; array[b] = temp; - if(Timer.timerEnabled()) Timer.stopLap(); + Timer.stopLap(); this.updateSwap(auxwrite); Delays.sleep(pause); @@ -183,11 +183,11 @@ public void write(int[] array, int at, int equals, double pause, boolean mark, b if(auxwrite) tempWrites++; else writes++; - if(Timer.timerEnabled()) Timer.startLap(); + Timer.startLap(); array[at] = equals; - if(Timer.timerEnabled()) Timer.stopLap(); + Timer.stopLap(); Delays.sleep(pause); } @@ -198,11 +198,11 @@ public void multiDimWrite(int[][] array, int x, int y, int equals, double pause, if(auxwrite) tempWrites++; else writes++; - if(Timer.timerEnabled()) Timer.startLap(); + Timer.startLap(); array[x][y] = equals; - if(Timer.timerEnabled()) Timer.stopLap(); + Timer.stopLap(); Delays.sleep(pause); } @@ -213,11 +213,11 @@ public void mockWrite(int length, int pos, int val, double pause) { this.tempWrites++; - if(Timer.timerEnabled()) Timer.startLap(); + Timer.startLap(); mockArray[pos] = val; - if(Timer.timerEnabled()) Timer.stopLap(); + Timer.stopLap(); Delays.sleep(pause); } @@ -234,7 +234,7 @@ public void transcribe(int[] array, ArrayList[] registers, int start, b } } - public void transcribeMSD(int[] array, ArrayList[] registers, int start, int min, boolean mark, boolean auxwrite) { + public void transcribeMSD(int[] array, ArrayList[] registers, int start, int min, double sleep, boolean mark, boolean auxwrite) { int total = start; int temp = 0; @@ -245,12 +245,12 @@ public void transcribeMSD(int[] array, ArrayList[] registers, int start for(int index = registers.length - 1; index >= 0; index--) { for(int i = registers[index].size() - 1; i >= 0; i--) { this.write(array, total + min - temp++ - 1, registers[index].get(i), 0, mark, auxwrite); - if(mark) Delays.sleep(1 + (2 / registers[index].size())); + if(mark) Delays.sleep(sleep); } } } - public void fancyTranscribe(int[] array, int length, ArrayList[] registers) { + public void fancyTranscribe(int[] array, int length, ArrayList[] registers, double sleep) { int[] tempArray = new int[length]; boolean[] tempWrite = new boolean[length]; int radix = registers.length; @@ -260,7 +260,7 @@ public void fancyTranscribe(int[] array, int length, ArrayList[] regist for(int i = 0; i < length; i++) { int register = i % radix; - int pos = (int) ((register * (length / radix)) + (i / radix)); + int pos = (register * (length / radix)) + (i / radix); if(!tempWrite[pos]) { this.write(array, pos, tempArray[pos], 0, false, false); @@ -268,7 +268,7 @@ public void fancyTranscribe(int[] array, int length, ArrayList[] regist } Highlights.markArray(register, pos); - if(register == 0) Delays.sleep(radix); + if(register == 0) Delays.sleep(sleep); } for(int i = 0; i < length; i++) { if(!tempWrite[i]){ @@ -282,23 +282,24 @@ public void fancyTranscribe(int[] array, int length, ArrayList[] regist //Methods mocking System.arraycopy (reversearraycopy is for TimSort's MergeHi and BinaryInsert, and WikiSort's Rotate) public void arraycopy(int[] src, int srcPos, int[] dest, int destPos, int length, double sleep, boolean mark, boolean temp) { for(int i = 0; i < length; i++) { - this.write(dest, destPos + i, src[srcPos + i], sleep, false, temp); - if(mark) { if(temp) Highlights.markArray(1, srcPos + i); else Highlights.markArray(1, destPos + i); } + + //TODO: Handle order of Delays in write method better + this.write(dest, destPos + i, src[srcPos + i], sleep, false, temp); } } public void reversearraycopy(int[] src, int srcPos, int[] dest, int destPos, int length, double sleep, boolean mark, boolean temp) { for(int i = length - 1; i >= 0; i--) { - this.write(dest, destPos + i, src[srcPos + i], sleep, false, temp); - if(mark) { if(temp) Highlights.markArray(1, srcPos + i); else Highlights.markArray(1, destPos + i); } + + this.write(dest, destPos + i, src[srcPos + i], sleep, false, temp); } } diff --git a/src/visuals/Bars.java b/src/visuals/Bars.java index bae63e73..eb4a9ee2 100644 --- a/src/visuals/Bars.java +++ b/src/visuals/Bars.java @@ -1,9 +1,9 @@ package visuals; import java.awt.Color; -import java.awt.Graphics2D; import main.ArrayVisualizer; +import templates.Visual; import utils.Highlights; import utils.Renderer; @@ -33,47 +33,83 @@ of this software and associated documentation files (the "Software"), to deal * */ -final public class Bars { - public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, Graphics2D mainRender, Graphics2D extraRender, Highlights Highlights) { +final public class Bars extends Visual { + public Bars(ArrayVisualizer ArrayVisualizer) { + super(ArrayVisualizer); + } + + @Override + public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, Highlights Highlights) { for(int i = 0; i < ArrayVisualizer.getCurrentLength(); i++){ if(Highlights.fancyFinishActive()) { if(i < Highlights.getFancyFinishPosition()) { - mainRender.setColor(Color.GREEN); + this.mainRender.setColor(Color.GREEN); } else if(ArrayVisualizer.rainbowEnabled() || ArrayVisualizer.colorEnabled()) { - mainRender.setColor(Renderer.getIntColor(array[i], ArrayVisualizer.getCurrentLength())); + this.mainRender.setColor(getIntColor(array[i], ArrayVisualizer.getCurrentLength())); } - else mainRender.setColor(Color.WHITE); + else this.mainRender.setColor(Color.WHITE); - Renderer.drawFancyFinish(ArrayVisualizer.getLogBaseTwoOfLength(), i, Highlights.getFancyFinishPosition(), mainRender, ArrayVisualizer.colorEnabled(), ArrayVisualizer.rainbowEnabled()); + drawFancyFinish(ArrayVisualizer.getLogBaseTwoOfLength(), i, Highlights.getFancyFinishPosition(), this.mainRender, ArrayVisualizer.colorEnabled(), ArrayVisualizer.rainbowEnabled()); } else { if(ArrayVisualizer.rainbowEnabled() || ArrayVisualizer.colorEnabled()) { - mainRender.setColor(Renderer.getIntColor(array[i], ArrayVisualizer.getCurrentLength())); + this.mainRender.setColor(getIntColor(array[i], ArrayVisualizer.getCurrentLength())); } - else mainRender.setColor(Color.WHITE); + else this.mainRender.setColor(Color.WHITE); if(ArrayVisualizer.getCurrentLength() != 2) { - Renderer.colorMarkedBars(ArrayVisualizer.getLogBaseTwoOfLength(), i, Highlights, mainRender, ArrayVisualizer.colorEnabled(), ArrayVisualizer.rainbowEnabled(), ArrayVisualizer.analysisEnabled()); + colorMarkedBars(ArrayVisualizer.getLogBaseTwoOfLength(), i, Highlights, this.mainRender, ArrayVisualizer.colorEnabled(), ArrayVisualizer.rainbowEnabled(), ArrayVisualizer.analysisEnabled()); } } - + /* + int markHeight = 0; + Color currentColor = mainRender.getColor(); + if(currentColor == Color.BLACK || currentColor == Color.RED || currentColor == Color.BLUE) { + markHeight = 5; + } + */ + int y = 0; int width = (int) (Renderer.getXScale() * (i + 1)) - Renderer.getOffset(); if(ArrayVisualizer.rainbowEnabled()) { if(width > 0) { - mainRender.fillRect(Renderer.getOffset() + 20, 0, width, ArrayVisualizer.windowHeight()); + this.mainRender.fillRect(Renderer.getOffset() + 20, 0, width, ArrayVisualizer.windowHeight()); } Renderer.setOffset(Renderer.getOffset() + width); } + else if(ArrayVisualizer.waveEnabled()) { + if(width > 0) { + y = (int) ((ArrayVisualizer.windowHeight() / 4) * Math.sin((2 * Math.PI * ((double) array[i] / ArrayVisualizer.getCurrentLength()))) + ArrayVisualizer.windowHalfHeight()); + this.mainRender.fillRect(Renderer.getOffset() + 20, y, width, 20); + } + Renderer.setOffset(Renderer.getOffset() + width); + } else { if(width > 0) { - y = (int) (((ArrayVisualizer.windowHeight() - 20)) - array[i] * Renderer.getYScale()); - mainRender.fillRect(Renderer.getOffset() + 20, y, width, (int) Math.max(array[i] * Renderer.getYScale(), 1)); + /* + int gap = 0; + if(width > 5) { + gap = 5; + } + */ + + y = (int) (((ArrayVisualizer.windowHeight() - 20)) - (array[i] + 1) * Renderer.getYScale()); + mainRender.fillRect(Renderer.getOffset() + 20, y, width, (int) ((array[i] + 1) * Renderer.getYScale())); + + //mainRender.fillRect(Renderer.getOffset() + 20, y /*- markHeight*/, width /*- gap*/, (int) ((array[i] + 1) * Renderer.getYScale()) /*+ markHeight*/); + + /* + double thickness = 1; + Stroke oldStroke = mainRender.getStroke(); + mainRender.setStroke(new BasicStroke((float) thickness)); + mainRender.setColor(Color.BLACK); + mainRender.drawLine(Renderer.getOffset() + 20, y, Renderer.getOffset() + 20, (int) Math.max(array[i] * Renderer.getYScale()-1, 1) + y); + mainRender.setStroke(oldStroke); + */ } - Renderer.setOffset(Renderer.getOffset() + width); } } diff --git a/src/visuals/Circular.java b/src/visuals/Circular.java index 49eb5050..753a4d96 100644 --- a/src/visuals/Circular.java +++ b/src/visuals/Circular.java @@ -2,10 +2,10 @@ import java.awt.BasicStroke; import java.awt.Color; -import java.awt.Graphics2D; import java.awt.Polygon; import main.ArrayVisualizer; +import templates.Visual; import utils.Highlights; import utils.Renderer; @@ -35,11 +35,13 @@ of this software and associated documentation files (the "Software"), to deal * */ -final public class Circular { - final private double CIRC_HEIGHT_RATIO = (9/6.0843731432) * (16/9d); - final private double CIRC_WIDTH_RATIO = (16/6.0843731432) * (16/9d); +final public class Circular extends Visual { + final private static double CIRC_HEIGHT_RATIO = (9/6.0843731432) * (16/9d); + final private static double CIRC_WIDTH_RATIO = (16/6.0843731432) * (16/9d); - private boolean drawRect; + public Circular(ArrayVisualizer ArrayVisualizer) { + super(ArrayVisualizer); + } // The reason we use cosine with height (expressed in terms of y) and sine with width (expressed in terms of x) is because our circles are rotated 90 degrees. // After that rotation, sine is on the x-axis and cosine is on the y-axis. @@ -55,27 +57,29 @@ private static double getCosOfDegrees(double d, int halfCirc) { return Math.cos((d * Math.PI) / halfCirc); } - public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, Graphics2D mainRender, Graphics2D extraRender, Highlights Highlights) { + @Override + public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, Highlights Highlights) { for(int i = 0; i < ArrayVisualizer.getCurrentLength(); i++){ if(i < Highlights.getFancyFinishPosition()) { - mainRender.setColor(Color.getHSBColor((1f/3f), 1f, 0.8f)); + this.mainRender.setColor(Color.getHSBColor((1f/3f), 1f, 0.8f)); } else if(!ArrayVisualizer.colorEnabled() && (ArrayVisualizer.spiralEnabled() || ArrayVisualizer.distanceEnabled() || ArrayVisualizer.pixelsEnabled())) { - mainRender.setColor(Color.WHITE); + this.mainRender.setColor(Color.WHITE); } - else mainRender.setColor(Renderer.getIntColor(array[i], ArrayVisualizer.getCurrentLength())); + else this.mainRender.setColor(getIntColor(array[i], ArrayVisualizer.getCurrentLength())); if(Highlights.fancyFinishActive()) { - Renderer.drawFancyFinish(ArrayVisualizer.getLogBaseTwoOfLength(), i, Highlights.getFancyFinishPosition(), mainRender, ArrayVisualizer.rainbowEnabled(), ArrayVisualizer.colorEnabled()); + drawFancyFinish(ArrayVisualizer.getLogBaseTwoOfLength(), i, Highlights.getFancyFinishPosition(), this.mainRender, ArrayVisualizer.rainbowEnabled(), ArrayVisualizer.colorEnabled()); } else { + /* if(ArrayVisualizer.pointerActive()) { if(Highlights.containsPosition(i)) { if(ArrayVisualizer.analysisEnabled()) { - extraRender.setColor(Color.GRAY); + this.extraRender.setColor(Color.GRAY); } else { - extraRender.setColor(Color.WHITE); + this.extraRender.setColor(Color.WHITE); } //Create new Polygon for the pointer @@ -114,14 +118,14 @@ else if(!ArrayVisualizer.colorEnabled() && (ArrayVisualizer.spiralEnabled() || A pointer.addPoint(pointerXValues[j], pointerYValues[j]); } - extraRender.fillPolygon(pointer); + this.extraRender.fillPolygon(pointer); } } - else if(ArrayVisualizer.getCurrentLength() != 2){ - Renderer.colorMarkedBars(ArrayVisualizer.getLogBaseTwoOfLength(), i, Highlights, mainRender, ArrayVisualizer.rainbowEnabled(), ArrayVisualizer.colorEnabled(), ArrayVisualizer.analysisEnabled()); + else */ if(ArrayVisualizer.getCurrentLength() != 2){ + colorMarkedBars(ArrayVisualizer.getLogBaseTwoOfLength(), i, Highlights, this.mainRender, ArrayVisualizer.rainbowEnabled(), ArrayVisualizer.colorEnabled(), ArrayVisualizer.analysisEnabled()); } } - + if(ArrayVisualizer.distanceEnabled()) { //TODO: Rewrite this abomination double len = ((ArrayVisualizer.getCurrentLength() / 2d) - Math.min(Math.min(Math.abs(i - array[i]), Math.abs(i - array[i] + ArrayVisualizer.getCurrentLength())), Math.abs(i - array[i] - ArrayVisualizer.getCurrentLength()))) / (ArrayVisualizer.getCurrentLength() / 2d); @@ -134,43 +138,43 @@ else if(ArrayVisualizer.getCurrentLength() != 2){ if(i > 0) { if(Highlights.fancyFinishActive()) { if(i < Highlights.getFancyFinishPosition()) { - Renderer.lineFancy(mainRender, ArrayVisualizer.currentWidth()); + lineFancy(this.mainRender, ArrayVisualizer.currentWidth()); } else { - Renderer.lineClear(mainRender, ArrayVisualizer.colorEnabled(), array, i, ArrayVisualizer.getCurrentLength(), ArrayVisualizer.currentWidth()); + lineClear(this.mainRender, ArrayVisualizer.colorEnabled(), array, i, ArrayVisualizer.getCurrentLength(), ArrayVisualizer.currentWidth()); } - Renderer.drawFancyFinishLine(ArrayVisualizer.getLogBaseTwoOfLength(), i, Highlights.getFancyFinishPosition(), mainRender, ArrayVisualizer.currentWidth(), ArrayVisualizer.colorEnabled()); + drawFancyFinishLine(ArrayVisualizer.getLogBaseTwoOfLength(), i, Highlights.getFancyFinishPosition(), this.mainRender, ArrayVisualizer.currentWidth(), ArrayVisualizer.colorEnabled()); } else { if(Highlights.containsPosition(i)) { - Renderer.lineMark(mainRender, ArrayVisualizer.currentWidth(), ArrayVisualizer.colorEnabled(), ArrayVisualizer.analysisEnabled()); + lineMark(this.mainRender, ArrayVisualizer.currentWidth(), ArrayVisualizer.colorEnabled(), ArrayVisualizer.analysisEnabled()); } - else Renderer.lineClear(mainRender, ArrayVisualizer.colorEnabled(), array, i, ArrayVisualizer.getCurrentLength(), ArrayVisualizer.currentWidth()); + else lineClear(this.mainRender, ArrayVisualizer.colorEnabled(), array, i, ArrayVisualizer.getCurrentLength(), ArrayVisualizer.currentWidth()); } - mainRender.drawLine(linkedpixX, linkedpixY, Renderer.getLineX(), Renderer.getLineY()); + this.mainRender.drawLine(linkedpixX, linkedpixY, Renderer.getLineX(), Renderer.getLineY()); } Renderer.setLineX(linkedpixX); Renderer.setLineY(linkedpixY); } else { + boolean drawRect = false; if(Highlights.containsPosition(i)) { - Renderer.setRectColor(extraRender, ArrayVisualizer.colorEnabled(), ArrayVisualizer.analysisEnabled()); + setRectColor(this.extraRender, ArrayVisualizer.colorEnabled(), ArrayVisualizer.analysisEnabled()); drawRect = true; } - else drawRect = false; if(drawRect) { - extraRender.setStroke(ArrayVisualizer.getThickStroke()); + this.extraRender.setStroke(ArrayVisualizer.getThickStroke()); if(Highlights.fancyFinishActive()) { - extraRender.fillRect((linkedpixX - Renderer.getDotWidth() / 2) - 10, (linkedpixY - Renderer.getDotHeight() / 2) - 10, Renderer.getDotWidth() + 20, Renderer.getDotHeight() + 20); + this.extraRender.fillRect((linkedpixX - Renderer.getDotWidth() / 2) - 10, (linkedpixY - Renderer.getDotHeight() / 2) - 10, Renderer.getDotWidth() + 20, Renderer.getDotHeight() + 20); } else { - extraRender.drawRect((linkedpixX - Renderer.getDotWidth() / 2) - 10, (linkedpixY - Renderer.getDotHeight() / 2) - 10, Renderer.getDotWidth() + 20, Renderer.getDotHeight() + 20); + this.extraRender.drawRect((linkedpixX - Renderer.getDotWidth() / 2) - 10, (linkedpixY - Renderer.getDotHeight() / 2) - 10, Renderer.getDotWidth() + 20, Renderer.getDotHeight() + 20); } - extraRender.setStroke(new BasicStroke(3f * (ArrayVisualizer.currentWidth() / 1280f))); + this.extraRender.setStroke(new BasicStroke(3f * (ArrayVisualizer.currentWidth() / 1280f))); } - mainRender.fillRect(linkedpixX - Renderer.getDotWidth() / 2, linkedpixY - Renderer.getDotHeight() / 2, Renderer.getDotWidth(), Renderer.getDotHeight()); + this.mainRender.fillRect(linkedpixX - Renderer.getDotWidth() / 2, linkedpixY - Renderer.getDotHeight() / 2, Renderer.getDotWidth(), Renderer.getDotHeight()); } } else { @@ -185,7 +189,7 @@ else if(ArrayVisualizer.getCurrentLength() != 2){ p.addPoint(ArrayVisualizer.windowHalfWidth() + (int) (Circular.getSinOfDegrees(i + 1, ArrayVisualizer.halfCircle()) * (((ArrayVisualizer.currentWidth() - 64) / CIRC_WIDTH_RATIO) * len)), ArrayVisualizer.windowHalfHeight() - (int) (Circular.getCosOfDegrees(i + 1, ArrayVisualizer.halfCircle()) * (((ArrayVisualizer.currentHeight() - 96) / CIRC_HEIGHT_RATIO) * len))); - mainRender.fillPolygon(p); + this.mainRender.fillPolygon(p); } } else if(ArrayVisualizer.spiralEnabled()) { @@ -194,19 +198,19 @@ else if(ArrayVisualizer.spiralEnabled()) { if(i > 0) { if(Highlights.fancyFinishActive()) { if(i < Highlights.getFancyFinishPosition()) { - Renderer.lineFancy(mainRender, ArrayVisualizer.currentWidth()); + lineFancy(this.mainRender, ArrayVisualizer.currentWidth()); } - else Renderer.lineClear(mainRender, ArrayVisualizer.colorEnabled(), array, i, ArrayVisualizer.getCurrentLength(), ArrayVisualizer.currentWidth()); + else lineClear(this.mainRender, ArrayVisualizer.colorEnabled(), array, i, ArrayVisualizer.getCurrentLength(), ArrayVisualizer.currentWidth()); - Renderer.drawFancyFinishLine(ArrayVisualizer.getLogBaseTwoOfLength(), i, Highlights.getFancyFinishPosition(), mainRender, ArrayVisualizer.currentWidth(), ArrayVisualizer.colorEnabled()); + drawFancyFinishLine(ArrayVisualizer.getLogBaseTwoOfLength(), i, Highlights.getFancyFinishPosition(), this.mainRender, ArrayVisualizer.currentWidth(), ArrayVisualizer.colorEnabled()); } else { if(Highlights.containsPosition(i)) { - Renderer.lineMark(mainRender, ArrayVisualizer.currentWidth(), ArrayVisualizer.colorEnabled(), ArrayVisualizer.analysisEnabled()); + lineMark(this.mainRender, ArrayVisualizer.currentWidth(), ArrayVisualizer.colorEnabled(), ArrayVisualizer.analysisEnabled()); } - else Renderer.lineClear(mainRender, ArrayVisualizer.colorEnabled(), array, i, ArrayVisualizer.getCurrentLength(), ArrayVisualizer.currentWidth()); + else lineClear(this.mainRender, ArrayVisualizer.colorEnabled(), array, i, ArrayVisualizer.getCurrentLength(), ArrayVisualizer.currentWidth()); } - mainRender.drawLine(ArrayVisualizer.windowHalfWidth() + (int) (Circular.getSinOfDegrees(i, ArrayVisualizer.halfCircle()) * ((((ArrayVisualizer.windowWidth() - 64) / 3.0) * array[i]) / ArrayVisualizer.getCurrentLength())), + this.mainRender.drawLine(ArrayVisualizer.windowHalfWidth() + (int) (Circular.getSinOfDegrees(i, ArrayVisualizer.halfCircle()) * ((((ArrayVisualizer.windowWidth() - 64) / 3.0) * array[i]) / ArrayVisualizer.getCurrentLength())), ArrayVisualizer.windowHalfHeight() - (int) (Circular.getCosOfDegrees(i, ArrayVisualizer.halfCircle()) * ((((ArrayVisualizer.windowHeight() - 96) / 2.0) * array[i]) / ArrayVisualizer.getCurrentLength())), Renderer.getLineX(), Renderer.getLineY()); @@ -215,32 +219,32 @@ else if(ArrayVisualizer.spiralEnabled()) { Renderer.setLineY(ArrayVisualizer.windowHalfHeight() - (int) (Circular.getCosOfDegrees(i, ArrayVisualizer.halfCircle()) * ((((ArrayVisualizer.windowHeight() - 96) / 2.0) * array[i]) / ArrayVisualizer.getCurrentLength()))); } else { + boolean drawRect = false; if(Highlights.containsPosition(i)) { - Renderer.setRectColor(extraRender, ArrayVisualizer.colorEnabled(), ArrayVisualizer.analysisEnabled()); + setRectColor(this.extraRender, ArrayVisualizer.colorEnabled(), ArrayVisualizer.analysisEnabled()); drawRect = true; } - else drawRect = false; int rectx = ArrayVisualizer.windowHalfWidth() + (int) (Circular.getSinOfDegrees(i, ArrayVisualizer.halfCircle()) * (((((ArrayVisualizer.windowWidth() - 64) / 3.0) * array[i]) / ArrayVisualizer.getCurrentLength()))); int recty = ArrayVisualizer.windowHalfHeight() - (int) (Circular.getCosOfDegrees(i, ArrayVisualizer.halfCircle()) * (((((ArrayVisualizer.windowHeight() - 96) / 2.0) * array[i]) / ArrayVisualizer.getCurrentLength()))); - mainRender.fillRect(rectx, recty, Renderer.getDotWidth(), Renderer.getDotHeight()); + this.mainRender.fillRect(rectx, recty, Renderer.getDotWidth(), Renderer.getDotHeight()); if(drawRect) { - extraRender.setStroke(ArrayVisualizer.getThickStroke()); + this.extraRender.setStroke(ArrayVisualizer.getThickStroke()); if(Highlights.fancyFinishActive()) { - extraRender.fillRect(rectx - 10, recty - 10, Renderer.getDotWidth() + 20, Renderer.getDotHeight() + 20); + this.extraRender.fillRect(rectx - 10, recty - 10, Renderer.getDotWidth() + 20, Renderer.getDotHeight() + 20); } else { - extraRender.drawRect(rectx - 10, recty - 10, Renderer.getDotWidth() + 20, Renderer.getDotHeight() + 20); + this.extraRender.drawRect(rectx - 10, recty - 10, Renderer.getDotWidth() + 20, Renderer.getDotHeight() + 20); } - extraRender.setStroke(new BasicStroke(3f * (ArrayVisualizer.currentWidth() / 1280f))); + this.extraRender.setStroke(new BasicStroke(3f * (ArrayVisualizer.currentWidth() / 1280f))); } } } else { if(Highlights.containsPosition(i)) { - Renderer.markBar(mainRender, ArrayVisualizer.colorEnabled(), ArrayVisualizer.rainbowEnabled(), ArrayVisualizer.analysisEnabled()); + markBar(this.mainRender, ArrayVisualizer.colorEnabled(), ArrayVisualizer.rainbowEnabled(), ArrayVisualizer.analysisEnabled()); } Polygon p = new Polygon(); @@ -254,7 +258,7 @@ else if(ArrayVisualizer.spiralEnabled()) { p.addPoint(ArrayVisualizer.windowHalfWidth() + (int) (Circular.getSinOfDegrees(i + 1, ArrayVisualizer.halfCircle()) * ((((ArrayVisualizer.windowWidth() - 64) / 3.0) * array[Math.min(i + 1, ArrayVisualizer.getCurrentLength() - 1)]) / ArrayVisualizer.getCurrentLength())), ArrayVisualizer.windowHalfHeight() - (int) (Circular.getCosOfDegrees(i + 1, ArrayVisualizer.halfCircle()) * ((((ArrayVisualizer.windowHeight() - 96) / 2.0) * array[Math.min(i + 1, ArrayVisualizer.getCurrentLength() - 1)]) / ArrayVisualizer.getCurrentLength()))); - mainRender.fillPolygon(p); + this.mainRender.fillPolygon(p); } } else { @@ -269,7 +273,7 @@ else if(ArrayVisualizer.spiralEnabled()) { p.addPoint(ArrayVisualizer.windowHalfWidth() + (int) (Circular.getSinOfDegrees(i + 1, ArrayVisualizer.halfCircle()) * ((ArrayVisualizer.windowWidth() - 64) / CIRC_WIDTH_RATIO)), ArrayVisualizer.windowHalfHeight() - (int) (Circular.getCosOfDegrees(i + 1, ArrayVisualizer.halfCircle()) * ((ArrayVisualizer.windowHeight() - 96) / CIRC_HEIGHT_RATIO))); - mainRender.fillPolygon(p); + this.mainRender.fillPolygon(p); } } } diff --git a/src/visuals/Hoops.java b/src/visuals/Hoops.java index c4e8f7f7..9041e6e2 100644 --- a/src/visuals/Hoops.java +++ b/src/visuals/Hoops.java @@ -5,6 +5,7 @@ import java.awt.Graphics2D; import main.ArrayVisualizer; +import templates.Visual; import utils.Highlights; import utils.Renderer; @@ -34,11 +35,56 @@ of this software and associated documentation files (the "Software"), to deal * */ -final public class Hoops { +final public class Hoops extends Visual { + public Hoops(ArrayVisualizer ArrayVisualizer) { + super(ArrayVisualizer); + } + + @SuppressWarnings("fallthrough") + public static void markHoops(int logOfLen, int index, Highlights Highlights, Graphics2D mainRender) { + switch(logOfLen) { + case 14: if(Highlights.containsPosition(index - 13)) mainRender.setColor(Color.BLACK); + case 13: if(Highlights.containsPosition(index - 12)) mainRender.setColor(Color.BLACK); + case 12: if(Highlights.containsPosition(index - 11)) mainRender.setColor(Color.BLACK); + case 11: if(Highlights.containsPosition(index - 10)) mainRender.setColor(Color.BLACK); + case 10: if(Highlights.containsPosition(index - 9)) mainRender.setColor(Color.BLACK); + case 9: if(Highlights.containsPosition(index - 8)) mainRender.setColor(Color.BLACK); + case 8: if(Highlights.containsPosition(index - 7)) mainRender.setColor(Color.BLACK); + case 7: if(Highlights.containsPosition(index - 6)) mainRender.setColor(Color.BLACK); + case 6: if(Highlights.containsPosition(index - 5)) mainRender.setColor(Color.BLACK); + case 5: if(Highlights.containsPosition(index - 4)) mainRender.setColor(Color.BLACK); + case 4: if(Highlights.containsPosition(index - 3)) mainRender.setColor(Color.BLACK); + case 3: if(Highlights.containsPosition(index - 2)) mainRender.setColor(Color.BLACK); + case 2: if(Highlights.containsPosition(index - 1)) mainRender.setColor(Color.BLACK); + default: if(Highlights.containsPosition(index)) mainRender.setColor(Color.BLACK); + } + } + + @SuppressWarnings("fallthrough") + public static void drawFancyFinishHoops(int logOfLen, int index, int position, Graphics2D mainRender) { + switch(logOfLen) { + case 14: if(index == position - 13) mainRender.setColor(Color.BLACK); + case 13: if(index == position - 12) mainRender.setColor(Color.BLACK); + case 12: if(index == position - 11) mainRender.setColor(Color.BLACK); + case 11: if(index == position - 10) mainRender.setColor(Color.BLACK); + case 10: if(index == position - 9) mainRender.setColor(Color.BLACK); + case 9: if(index == position - 8) mainRender.setColor(Color.BLACK); + case 8: if(index == position - 7) mainRender.setColor(Color.BLACK); + case 7: if(index == position - 6) mainRender.setColor(Color.BLACK); + case 6: if(index == position - 5) mainRender.setColor(Color.BLACK); + case 5: if(index == position - 4) mainRender.setColor(Color.BLACK); + case 4: if(index == position - 3) mainRender.setColor(Color.BLACK); + case 3: if(index == position - 2) mainRender.setColor(Color.BLACK); + case 2: if(index == position - 1) mainRender.setColor(Color.BLACK); + default: if(index == position) mainRender.setColor(Color.BLACK); + } + } + //TODO: Fix scaling to ensure Hoops close at the center //TODO: Too many rings highlighted at once!! - public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, Graphics2D mainRender, Graphics2D extraRender, Highlights Highlights) { - mainRender.setStroke(new BasicStroke(1.0f)); //thin strokes significantly increased performance + @Override + public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, Highlights Highlights) { + this.mainRender.setStroke(new BasicStroke(1.0f)); //thin strokes significantly increased performance //This StackOverflow thread may be related: https://stackoverflow.com/questions/47102734/performances-issue-when-drawing-dashed-line-in-java @@ -48,23 +94,23 @@ public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Re for(int i = 0; i < ArrayVisualizer.getCurrentLength(); i++) { if(Highlights.fancyFinishActive()) { if(i < Highlights.getFancyFinishPosition()) { - mainRender.setColor(Color.GREEN); + this.mainRender.setColor(Color.GREEN); } - else mainRender.setColor(Renderer.getIntColor(array[i], ArrayVisualizer.getCurrentLength())); + else this.mainRender.setColor(getIntColor(array[i], ArrayVisualizer.getCurrentLength())); - Renderer.drawFancyFinishHoops(ArrayVisualizer.getLogBaseTwoOfLength(), i, Highlights.getFancyFinishPosition(), mainRender); + drawFancyFinishHoops(ArrayVisualizer.getLogBaseTwoOfLength(), i, Highlights.getFancyFinishPosition(), this.mainRender); } else { - mainRender.setColor(Renderer.getIntColor(array[i], ArrayVisualizer.getCurrentLength())); + this.mainRender.setColor(getIntColor(array[i], ArrayVisualizer.getCurrentLength())); } if(ArrayVisualizer.getCurrentLength() != 2) { - Renderer.markHoops(ArrayVisualizer.getLogBaseTwoOfLength(), i, Highlights, mainRender); + markHoops(ArrayVisualizer.getLogBaseTwoOfLength(), i, Highlights, this.mainRender); } int radius = (int) (diameter / 2.0); - mainRender.drawOval(ArrayVisualizer.windowHalfWidth() - radius, + this.mainRender.drawOval(ArrayVisualizer.windowHalfWidth() - radius, ArrayVisualizer.windowHalfHeight() - radius + 12, (int) diameter, (int) diameter); diff --git a/src/visuals/Mesh.java b/src/visuals/Mesh.java index 69ef1100..03bbf650 100644 --- a/src/visuals/Mesh.java +++ b/src/visuals/Mesh.java @@ -1,9 +1,9 @@ package visuals; import java.awt.Color; -import java.awt.Graphics2D; import main.ArrayVisualizer; +import templates.Visual; import utils.Highlights; import utils.Renderer; @@ -33,12 +33,48 @@ of this software and associated documentation files (the "Software"), to deal * */ -final public class Mesh { - public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, Graphics2D mainRender, Graphics2D extraRender, Highlights Highlights) { - int trih = Renderer.getTriangleHeight(ArrayVisualizer.getCurrentLength(), ArrayVisualizer.windowHeight() / 20); //Height of triangles to use, Width will be scaled accordingly +final public class Mesh extends Visual { + public Mesh(ArrayVisualizer ArrayVisualizer) { + super(ArrayVisualizer); + } + + //TODO: Change these to be more consistent between array lengths. These heights and counts are a bit random. + public static int getTriangleHeight(int length, double height) { + switch(length) { + case 2: height *= 20; break; + case 4: height *= 13; break; + case 8: height *= 8; break; + case 16: + case 32: height *= 4.4; break; + case 64: height *= 2.3; break; + case 128: height *= 2.35; break; + case 256: height *= 1.22; break; + default: height *= 1; + } + + return (int) height; + } + + public static int getTrianglesPerRow(int length, int trianglesPerColumn) { + int trianglesPerRow; + + switch(length) { + case 32: + case 64: trianglesPerRow = 4; break; + case 128: + case 256: trianglesPerRow = 8; break; + default: trianglesPerRow = Math.max(length / trianglesPerColumn, 2); + } + + return trianglesPerRow; + } + + @Override + public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, Highlights Highlights) { + int trih = getTriangleHeight(ArrayVisualizer.getCurrentLength(), ArrayVisualizer.windowHeight() / 20); //Height of triangles to use, Width will be scaled accordingly int tripercol = (ArrayVisualizer.windowHeight() / trih) * 2; //Triangles per column - int triperrow = Renderer.getTrianglesPerRow(ArrayVisualizer.getCurrentLength(), tripercol); //Triangles per row + int triperrow = getTrianglesPerRow(ArrayVisualizer.getCurrentLength(), tripercol); //Triangles per row double triw = (double) ArrayVisualizer.windowWidth() / triperrow; //Width of triangles to use @@ -50,15 +86,15 @@ public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Re for(int i = 0; i < ArrayVisualizer.getCurrentLength(); i++){ if(Highlights.containsPosition(i) && ArrayVisualizer.getCurrentLength() != 2) { - if(ArrayVisualizer.analysisEnabled()) mainRender.setColor(Color.WHITE); - else mainRender.setColor(Color.BLACK); + if(ArrayVisualizer.analysisEnabled()) this.mainRender.setColor(Color.WHITE); + else this.mainRender.setColor(Color.BLACK); } else { //TODO: Clean up this visual trick if(Highlights.fancyFinishActive() && (i < Highlights.getFancyFinishPosition() && i > Highlights.getFancyFinishPosition() - ArrayVisualizer.getLogBaseTwoOfLength())) { - mainRender.setColor(Color.GREEN); + this.mainRender.setColor(Color.GREEN); } - else mainRender.setColor(Renderer.getIntColor(array[i], ArrayVisualizer.getCurrentLength())); + else this.mainRender.setColor(getIntColor(array[i], ArrayVisualizer.getCurrentLength())); } //If i/triperrow is even, then triangle points right, else left boolean direction = false; @@ -89,7 +125,7 @@ public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Re } //Draw it - mainRender.fillPolygon(triptsx, triptsy, triptsx.length); + this.mainRender.fillPolygon(triptsx, triptsy, triptsx.length); //If at the end of a row, reset curx //(i != 0 || i != currentLen - 1) diff --git a/src/visuals/Pixels.java b/src/visuals/Pixels.java index 92d306ed..a1fad716 100644 --- a/src/visuals/Pixels.java +++ b/src/visuals/Pixels.java @@ -2,9 +2,9 @@ import java.awt.BasicStroke; import java.awt.Color; -import java.awt.Graphics2D; import main.ArrayVisualizer; +import templates.Visual; import utils.Highlights; import utils.Renderer; @@ -34,34 +34,52 @@ of this software and associated documentation files (the "Software"), to deal * */ -final public class Pixels { - private boolean drawRect; - - public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, Graphics2D mainRender, Graphics2D extraRender, Highlights Highlights) { - //TODO: Fix zeroth line approaching infinity +final public class Pixels extends Visual { + public Pixels(ArrayVisualizer ArrayVisualizer) { + super(ArrayVisualizer); + } + + @Override + public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, Highlights Highlights) { if(ArrayVisualizer.linesEnabled()) { + //TODO: Wave visual needs to be *heavily* refactored + if(ArrayVisualizer.waveEnabled()) { + Renderer.setLineY((int) ((ArrayVisualizer.windowHeight() / 4) * Math.sin((2 * Math.PI * ((double) array[1] / ArrayVisualizer.getCurrentLength()))) + ArrayVisualizer.windowHalfHeight())); + } + else { + Renderer.setLineY((int) ((ArrayVisualizer.windowHeight() - 20) - array[0] * Renderer.getYScale())); + } for(int i = 0; i < ArrayVisualizer.getCurrentLength(); i++) { - int y = 0; + int y; + if(ArrayVisualizer.waveEnabled()) { + y = (int) ((ArrayVisualizer.windowHeight() / 4) * Math.sin((2 * Math.PI * ((double) array[i] / ArrayVisualizer.getCurrentLength()))) + ArrayVisualizer.windowHalfHeight()); + } + else { + y = (int) ((ArrayVisualizer.windowHeight() - 20) - (Math.max(array[i], 1) * Renderer.getYScale())); + + // Quick patch to fix the first line being horizontal for some reason + if(i == 0) y += ((ArrayVisualizer.windowHeight() - 20) - array[1] * Renderer.getYScale()) + - ((ArrayVisualizer.windowHeight() - 20) - array[2] * Renderer.getYScale()); + } + int width = (int) (Renderer.getXScale() * (i + 1)) - Renderer.getOffset(); if(width > 0) { - y = (int) ((ArrayVisualizer.windowHeight() - 20) - (Math.max(array[i], 1) * Renderer.getYScale())); - if(i > 0) { if(Highlights.fancyFinishActive()) { if(i < Highlights.getFancyFinishPosition()) { - Renderer.lineFancy(mainRender, ArrayVisualizer.currentWidth()); + lineFancy(this.mainRender, ArrayVisualizer.currentWidth()); } - else Renderer.lineClear(mainRender, ArrayVisualizer.colorEnabled(), array, i, ArrayVisualizer.getCurrentLength(), ArrayVisualizer.currentWidth()); + else lineClear(this.mainRender, ArrayVisualizer.colorEnabled(), array, i, ArrayVisualizer.getCurrentLength(), ArrayVisualizer.currentWidth()); - Renderer.drawFancyFinishLine(ArrayVisualizer.getLogBaseTwoOfLength(), i, Highlights.getFancyFinishPosition(), mainRender, ArrayVisualizer.currentWidth(), ArrayVisualizer.colorEnabled()); + drawFancyFinishLine(ArrayVisualizer.getLogBaseTwoOfLength(), i, Highlights.getFancyFinishPosition(), this.mainRender, ArrayVisualizer.currentWidth(), ArrayVisualizer.colorEnabled()); } else if(Highlights.containsPosition(i) && ArrayVisualizer.getCurrentLength() != 2) { - Renderer.lineMark(mainRender, ArrayVisualizer.currentWidth(), ArrayVisualizer.colorEnabled(), ArrayVisualizer.analysisEnabled()); + lineMark(this.mainRender, ArrayVisualizer.currentWidth(), ArrayVisualizer.colorEnabled(), ArrayVisualizer.analysisEnabled()); } - else Renderer.lineClear(mainRender, ArrayVisualizer.colorEnabled(), array, i, ArrayVisualizer.getCurrentLength(), ArrayVisualizer.currentWidth()); - - mainRender.drawLine(Renderer.getOffset() + 20, y, Renderer.getLineX() + 20, Renderer.getLineY()); + else lineClear(this.mainRender, ArrayVisualizer.colorEnabled(), array, i, ArrayVisualizer.getCurrentLength(), ArrayVisualizer.currentWidth()); + + this.mainRender.drawLine(Renderer.getOffset() + 20, y, Renderer.getLineX() + 20, Renderer.getLineY()); } Renderer.setLineX(Renderer.getOffset()); Renderer.setLineY(y); @@ -72,43 +90,48 @@ else if(Highlights.containsPosition(i) && ArrayVisualizer.getCurrentLength() != else { for(int i = 0; i < ArrayVisualizer.getCurrentLength(); i++) { if(i < Highlights.getFancyFinishPosition()) { - mainRender.setColor(Color.GREEN); + this.mainRender.setColor(Color.GREEN); } else if(i == Highlights.getFancyFinishPosition() && Highlights.fancyFinishActive()) { if(ArrayVisualizer.colorEnabled()) { - mainRender.setColor(Color.WHITE); + this.mainRender.setColor(Color.WHITE); } - else mainRender.setColor(Color.RED); + else this.mainRender.setColor(Color.RED); } else if(ArrayVisualizer.colorEnabled()) { - mainRender.setColor(Renderer.getIntColor(array[i], ArrayVisualizer.getCurrentLength())); + this.mainRender.setColor(getIntColor(array[i], ArrayVisualizer.getCurrentLength())); } - else mainRender.setColor(Color.WHITE); + else this.mainRender.setColor(Color.WHITE); int y = 0; int width = (int) (Renderer.getXScale() * (i + 1)) - Renderer.getOffset(); + boolean drawRect = false; if(Highlights.containsPosition(i) && ArrayVisualizer.getCurrentLength() != 2) { - Renderer.setRectColor(extraRender, ArrayVisualizer.colorEnabled(), ArrayVisualizer.analysisEnabled()); + setRectColor(this.extraRender, ArrayVisualizer.colorEnabled(), ArrayVisualizer.analysisEnabled()); drawRect = true; } - else drawRect = false; if(width > 0) { - y = (int) ((ArrayVisualizer.windowHeight() - 20) - (array[i] * Renderer.getYScale())); - mainRender.fillRect(Renderer.getOffset() + 20, y, Renderer.getDotDimensions(), Renderer.getDotDimensions()); + if(ArrayVisualizer.waveEnabled()) { + y = (int) ((ArrayVisualizer.windowHeight() / 4) * Math.sin((2 * Math.PI * ((double) array[i] / ArrayVisualizer.getCurrentLength()))) + ArrayVisualizer.windowHalfHeight()); + } + else { + y = (int) ((ArrayVisualizer.windowHeight() - 20) - (array[i] * Renderer.getYScale())); + } + this.mainRender.fillRect(Renderer.getOffset() + 20, y, Renderer.getDotDimensions(), Renderer.getDotDimensions()); if(drawRect) { - extraRender.setStroke(ArrayVisualizer.getThickStroke()); + this.extraRender.setStroke(ArrayVisualizer.getThickStroke()); if(Highlights.fancyFinishActive()) { - extraRender.fillRect(Renderer.getOffset() + 10, y - 10, Renderer.getDotDimensions() + 20, Renderer.getDotDimensions() + 20); + this.extraRender.fillRect(Renderer.getOffset() + 10, y - 10, Renderer.getDotDimensions() + 20, Renderer.getDotDimensions() + 20); } else { - extraRender.drawRect(Renderer.getOffset() + 10, y - 10, Renderer.getDotDimensions() + 20, Renderer.getDotDimensions() + 20); + this.extraRender.drawRect(Renderer.getOffset() + 10, y - 10, Renderer.getDotDimensions() + 20, Renderer.getDotDimensions() + 20); } - extraRender.setStroke(new BasicStroke(3f * (ArrayVisualizer.currentWidth() / 1280f))); //TODO: This BasicStroke should have a getDefaultStroke() method + this.extraRender.setStroke(new BasicStroke(3f * (ArrayVisualizer.currentWidth() / 1280f))); //TODO: This BasicStroke should have a getDefaultStroke() method } } Renderer.setOffset(Renderer.getOffset() + width); diff --git a/src/visuals/VisualStyles.java b/src/visuals/VisualStyles.java index 46b7c600..d7b8f683 100644 --- a/src/visuals/VisualStyles.java +++ b/src/visuals/VisualStyles.java @@ -1,7 +1,5 @@ package visuals; -import java.awt.Graphics2D; - import main.ArrayVisualizer; import utils.Highlights; import utils.Renderer; @@ -33,45 +31,40 @@ of this software and associated documentation files (the "Software"), to deal */ public enum VisualStyles { - CIRCULAR { + BARS { @Override - public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, - Graphics2D mainRender, Graphics2D extraRender, Highlights Highlights) { - Renderer.drawCircle(array, ArrayVisualizer, mainRender, extraRender, Highlights); + public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, Highlights Highlights) { + ArrayVisualizer.getVisuals()[0].drawVisual(array, ArrayVisualizer, Renderer, Highlights); } }, - HOOPS { + CIRCULAR { @Override - public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, - Graphics2D mainRender, Graphics2D extraRender, Highlights Highlights) { - Renderer.drawHoops(array, ArrayVisualizer, mainRender, extraRender, Highlights); + public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, Highlights Highlights) { + ArrayVisualizer.getVisuals()[1].drawVisual(array, ArrayVisualizer, Renderer, Highlights); } }, - MESH { + HOOPS { @Override - public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, - Graphics2D mainRender, Graphics2D extraRender, Highlights Highlights) { - Renderer.drawMesh(array, ArrayVisualizer, mainRender, extraRender, Highlights); + public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, Highlights Highlights) { + ArrayVisualizer.getVisuals()[2].drawVisual(array, ArrayVisualizer, Renderer, Highlights); } }, - BARS { + MESH { @Override - public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, - Graphics2D mainRender, Graphics2D extraRender, Highlights Highlights) { - Renderer.drawBars(array, ArrayVisualizer, mainRender, extraRender, Highlights); + public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, Highlights Highlights) { + ArrayVisualizer.getVisuals()[3].drawVisual(array, ArrayVisualizer, Renderer, Highlights); } }, PIXELS { @Override - public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, - Graphics2D mainRender, Graphics2D extraRender, Highlights Highlights) { - Renderer.drawPixels(array, ArrayVisualizer, mainRender, extraRender, Highlights); + public void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, Highlights Highlights) { + ArrayVisualizer.getVisuals()[4].drawVisual(array, ArrayVisualizer, Renderer, Highlights); } }; - public VisualStyles getVisual() { + public VisualStyles getCurrentVisual() { return this; } - public abstract void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, Graphics2D mainRender, Graphics2D extraRender, Highlights Highlights); + public abstract void drawVisual(int[] array, ArrayVisualizer ArrayVisualizer, Renderer Renderer, Highlights Highlights); } \ No newline at end of file