├── README.md └── Sorting Visualizer ├── .classpath ├── .project ├── .settings └── org.eclipse.jdt.core.prefs ├── bin └── .gitignore ├── res ├── burger-icon-disabled.png ├── burger-icon-enabled.png ├── plain-black.png ├── shuffle-icon-disabled.png ├── shuffle-icon-enabled.png ├── sort-icon-disabled.png ├── sort-icon-enabled.png └── stop-icon-enabled.png └── src ├── customJComponent ├── CustomJButton.java ├── CustomJLabel.java ├── CustomJPanel.java ├── CustomJSlider.java └── CustomSwingWorker.java ├── main └── MainApp.java ├── screen ├── MainScreen.java ├── Menu.java ├── SidePanel.java └── SortingPanel.java └── sortingAlgorithm ├── BogoSort.java ├── BubbleSort.java ├── InsertionSort.java ├── MergeSort.java ├── QuickSort.java ├── SelectionSort.java ├── SortAlgorithm.java └── SortingAlgorithm.java /README.md: -------------------------------------------------------------------------------- 1 | # Java-Sorting-Visualizer 2 | Java Sorting Visualizer using *Swing Components | Swing Worker | Graphics 2D 3 | 4 | ## Sorting Algorithms : 5 | * Insertion Sort 6 | * Selection Sort 7 | * Bubble Sort 8 | * Merge Sort 9 | * Quick Sort 10 | * Bogo Sort 11 | 12 | ## Main Libraries Used : 13 | * Swing Worker 14 | * Swing Components 15 | * Graphics 2D 16 | 17 | ## Skills Learned : 18 | * Multi-Threading using Swing Worker 19 | * Customising Swing Components 20 | * Graphics 2D 21 | * Apply Sorting Algorithms 22 | 23 | ## Program Structure : 24 | ### main 25 | * contains *MainApp* which sets up the JFrame. 26 | ### screen 27 | * constains 4 *CustomJPanels* 28 | * *Menu* has the control buttons such as Pause, Sort, and Shuffle. 29 | * *SidePanel* has the different sorting algorithms and its task is to set the `current_algorithm`. 30 | * *SortingPanel* is the *CustomJPanel* that handles the sorting and painting it on the Component. 31 | * *MainScreen* is the `contentPane` of *MainApp* and it holds the 3 *CustomJPanel*. 32 | ### sortingAlgorithm 33 | * contains all the sorting algorithm used 34 | * *SortAlgorithm* is the Parent Class of the sorting algorithms. It has all the methods that the sorting algorithm needs. 35 | * *SortingAlgorithm* is an `enum` that controls the request from other panels. It also handles methods that are being called in the `current_algorithm`. 36 | ### customJComponent 37 | * JComponents that have various constructors to meet the needs of the program. 38 | 39 | There are three main indeces here : `current_index`, `traversing_index`, and `selected_index`. Their task is to visually guide the user on the current state of the sorting process. Their uses varies from each Sorting Algorithms. 40 | The information displayed such as Time Complexities and Space Complexity are being set up in the *SortingAlgorithm* enum. 41 | Lastly, the only dynamic value on the HUD is the `array_access` which is being updated during the sorting process. 42 | 43 | Here's my email : codeitphiliks@gmail.com if you have found a bug or if you have any queries regarding this project. 44 | -------------------------------------------------------------------------------- /Sorting Visualizer/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Sorting Visualizer/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Sorting Visualizer 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /Sorting Visualizer/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 5 | org.eclipse.jdt.core.compiler.compliance=11 6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 10 | org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled 11 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 12 | org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning 13 | org.eclipse.jdt.core.compiler.release=enabled 14 | org.eclipse.jdt.core.compiler.source=11 15 | -------------------------------------------------------------------------------- /Sorting Visualizer/bin/.gitignore: -------------------------------------------------------------------------------- 1 | /burger-icon-disabled.png 2 | /burger-icon-enabled.png 3 | /customJComponent/ 4 | /main/ 5 | /plain-black.png 6 | /screen/ 7 | /shuffle-icon-disabled.png 8 | /shuffle-icon-enabled.png 9 | /sort-icon-disabled.png 10 | /sort-icon-enabled.png 11 | /sortingAlgorithm/ 12 | /stop-icon-enabled.png 13 | -------------------------------------------------------------------------------- /Sorting Visualizer/res/burger-icon-disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philiks/Java-Sorting-Visualizer/122b5f8c66970c9f9af196b6d438eea215c52f2b/Sorting Visualizer/res/burger-icon-disabled.png -------------------------------------------------------------------------------- /Sorting Visualizer/res/burger-icon-enabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philiks/Java-Sorting-Visualizer/122b5f8c66970c9f9af196b6d438eea215c52f2b/Sorting Visualizer/res/burger-icon-enabled.png -------------------------------------------------------------------------------- /Sorting Visualizer/res/plain-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philiks/Java-Sorting-Visualizer/122b5f8c66970c9f9af196b6d438eea215c52f2b/Sorting Visualizer/res/plain-black.png -------------------------------------------------------------------------------- /Sorting Visualizer/res/shuffle-icon-disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philiks/Java-Sorting-Visualizer/122b5f8c66970c9f9af196b6d438eea215c52f2b/Sorting Visualizer/res/shuffle-icon-disabled.png -------------------------------------------------------------------------------- /Sorting Visualizer/res/shuffle-icon-enabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philiks/Java-Sorting-Visualizer/122b5f8c66970c9f9af196b6d438eea215c52f2b/Sorting Visualizer/res/shuffle-icon-enabled.png -------------------------------------------------------------------------------- /Sorting Visualizer/res/sort-icon-disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philiks/Java-Sorting-Visualizer/122b5f8c66970c9f9af196b6d438eea215c52f2b/Sorting Visualizer/res/sort-icon-disabled.png -------------------------------------------------------------------------------- /Sorting Visualizer/res/sort-icon-enabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philiks/Java-Sorting-Visualizer/122b5f8c66970c9f9af196b6d438eea215c52f2b/Sorting Visualizer/res/sort-icon-enabled.png -------------------------------------------------------------------------------- /Sorting Visualizer/res/stop-icon-enabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philiks/Java-Sorting-Visualizer/122b5f8c66970c9f9af196b6d438eea215c52f2b/Sorting Visualizer/res/stop-icon-enabled.png -------------------------------------------------------------------------------- /Sorting Visualizer/src/customJComponent/CustomJButton.java: -------------------------------------------------------------------------------- 1 | package customJComponent; 2 | 3 | import java.awt.Color; 4 | import java.awt.Dimension; 5 | import java.awt.Rectangle; 6 | 7 | import javax.swing.AbstractAction; 8 | import javax.swing.BorderFactory; 9 | import javax.swing.ImageIcon; 10 | import javax.swing.JButton; 11 | 12 | /** 13 | * CustomJButton 14 | * @author philiks 15 | * Just like an ordinary JButton, CustomJButton component 16 | * provides an action when trigerred. This allows 17 | * interaction between various components or do abstract 18 | * action. 19 | * 20 | * CustomJButton was created to serve as a modified version 21 | * of JButton, its purpose is to provide funtionalities 22 | * (same of JButton) with some modifications to suit the needs 23 | * of the project, Sorting Visualizer. Such modifications are: 24 | * constructors, Look and Feel, and more default values to its 25 | * properties. 26 | * 27 | * Warning: 28 | * The rectangular bounds is a required argument in 29 | * CustomJButton because the Container @see CustomJPanel 30 | * that it will be placed has a null layout. Therefore, 31 | * specifying its rectangular bounds defines the location 32 | * and dimension of the CustomJButton. 33 | */ 34 | public class CustomJButton extends JButton{ 35 | private static final long serialVersionUID = 1L; 36 | 37 | /*** 38 | * CUSTOM_JBUTTON_WIDTH and CUSTOM_JBUTTON_HEIGHT sets the 39 | * PreferredSize of the CustomJButton. CUSTOM_JBUTTON_WIDTH 40 | * and CUSTOM_JBUTTON_HEIGHT overrules the dimension that is 41 | * set by Swing using @see setSize() by overriding 42 | * @see getPreferredSize(). Therefore CustomJButton 43 | * always use the dimension in rectangular bounds. 44 | * CustomJButton's dimension can be changed by 45 | * calling the @see setBounds() method. 46 | */ 47 | protected int CUSTOM_JBUTTON_WIDTH; 48 | protected int CUSTOM_JBUTTON_HEIGHT; 49 | 50 | /*** 51 | * Creates a CustomJButton instance with the specified 52 | * rectangular bounds, abstact action, icon (enabled and 53 | * disabled), and text. 54 | * The CustomJButton is centered horizontally and vertically 55 | * in its display area. 56 | * The image displays first following by a trailing text. 57 | * 58 | * @param rect The rectangular bounds that defines the 59 | * CustomJButton's location and dimension. 60 | * @param action The action that will take place when 61 | * the CustomJButton is triggered. 62 | * @param enabled_icon The image to be displayed by the CustomJButton when enabled. 63 | * @param disabled_icon The image to be displayed by the CustomJButton when disabled. 64 | * @param text The text to be displayed by the CustomJButton. 65 | */ 66 | public CustomJButton(Rectangle rect, AbstractAction action, 67 | ImageIcon enabled_icon, ImageIcon disabled_icon, 68 | String text, String tooltip) { 69 | CUSTOM_JBUTTON_WIDTH = rect.width; 70 | CUSTOM_JBUTTON_HEIGHT = rect.height; 71 | 72 | setBounds(rect); 73 | setAction(action); 74 | setIcon(enabled_icon); 75 | setDisabledIcon(disabled_icon); 76 | setText(text); 77 | setToolTipText(tooltip); 78 | 79 | setOpaque(true); 80 | setForeground(Color.WHITE); 81 | setContentAreaFilled(false); 82 | setHorizontalAlignment(JButton.CENTER); 83 | setVerticalAlignment(JButton.CENTER); 84 | setBorder(BorderFactory.createLineBorder(Color.WHITE)); 85 | } 86 | 87 | /*** 88 | * Creates a CustomJButton instance with the specified 89 | * rectangular bounds, abstact action and icon (enabled and 90 | * disabled). 91 | * The CustomJButton is centered horizontally and vertically 92 | * in its display area. 93 | * 94 | * @param rect The rectangular bounds that defines the 95 | * CustomJButton's location and dimension. 96 | * @param action The action that will take place when 97 | * the CustomJButton is triggered. 98 | * @param enabled_icon The image to be displayed by the CustomJButton when enabled. 99 | * @param disabled_icon The image to be displayed by the CustomJButton when disabled. 100 | * @param tooltip The tooltip to be displayed by the CustomJButton 101 | */ 102 | public CustomJButton(Rectangle rect, AbstractAction action, 103 | ImageIcon enabled_icon, ImageIcon disabled_icon, String tooltip) { 104 | this(rect, action, enabled_icon, disabled_icon, "", tooltip); 105 | } 106 | 107 | /*** 108 | * Creates a CustomJButton instance with the specified 109 | * rectangular bounds, abstact action and icon. 110 | * The CustomJButton is centered horizontally and vertically 111 | * in its display area. 112 | * 113 | * @param rect The rectangular bounds that defines the 114 | * CustomJButton's location and dimension. 115 | * @param action The action that will take place when 116 | * the CustomJButton is triggered. 117 | * @param enabled_icon The image to be displayed by the CustomJButton when enabled. 118 | * @param tooltip The tooltip to be displayed by the CustomJButton 119 | */ 120 | public CustomJButton(Rectangle rect, AbstractAction action, ImageIcon enabled_icon, String tooltip) { 121 | this(rect, action, enabled_icon, null, "", tooltip); 122 | } 123 | 124 | /*** 125 | * Creates a CustomJButton instance with the specified 126 | * rectangular bounds, abstact action, and text. 127 | * The CustomJButton is centered horizontally and vertically 128 | * in its display area. 129 | * 130 | * @param rect The rectangular bounds that defines the 131 | * CustomJButton's location and dimension. 132 | * @param action The action that will take place when 133 | * the CustomJButton is triggered. 134 | * @param text The text to be displayed by the CustomJButton. 135 | */ 136 | public CustomJButton(Rectangle rect, AbstractAction action, String text) { 137 | this(rect, action, null, null, text, ""); 138 | } 139 | 140 | @Override 141 | public Dimension getPreferredSize() { 142 | return new Dimension(CUSTOM_JBUTTON_WIDTH, CUSTOM_JBUTTON_HEIGHT); 143 | } 144 | } -------------------------------------------------------------------------------- /Sorting Visualizer/src/customJComponent/CustomJLabel.java: -------------------------------------------------------------------------------- 1 | package customJComponent; 2 | 3 | import java.awt.Color; 4 | import java.awt.Dimension; 5 | import java.awt.Font; 6 | import java.awt.Rectangle; 7 | 8 | import javax.swing.ImageIcon; 9 | import javax.swing.JLabel; 10 | 11 | /** 12 | * CustomJLabel 13 | * @author philiks 14 | * Just like an ordinary JLabel, CustomJLabel component 15 | * provides an area for short text strings, an image, 16 | * or both. 17 | * 18 | * CustomJLabel was created to serve as a modified version 19 | * of JLabel, its purpose is to provide funtionalities 20 | * (same of JLabel) with some modifications to suit the needs 21 | * of the project, Sorting Visualizer. Such modifications are: 22 | * constructors, Look and Feel, and more default values to its 23 | * properties. 24 | * 25 | * Warning: 26 | * The rectangular bounds is a required argument in 27 | * CustomJLabel because the Container @see CustomJPanel 28 | * that it will be placed has a null layout. Therefore, 29 | * specifying its rectangular bounds defines the location 30 | * and dimension of the CustomJLabel. 31 | */ 32 | public class CustomJLabel extends JLabel{ 33 | private static final long serialVersionUID = 1L; 34 | 35 | /*** 36 | * CUSTOM_JLABEL_WIDTH and CUSTOM_JLABEL_HEIGHT sets the 37 | * PreferredSize of the CustomJLabel. CUSTOM_JLABEL_WIDTH 38 | * and CUSTOM_JLABEL_HEIGHT overrules the dimension that is 39 | * set by Swing using @see setSize() by overriding 40 | * @see getPreferredSize(). Therefore CustomJLabel 41 | * always use the dimension in rectangular bounds. 42 | * CustomJLabel's dimension can be changed by 43 | * calling the @see setBounds() method. 44 | */ 45 | protected int CUSTOM_JLABEL_WIDTH; 46 | protected int CUSTOM_JLABEL_HEIGHT; 47 | 48 | /*** 49 | * Creates a CustomJLabel instance with the specified 50 | * rectangular bounds, image, text. 51 | * The CustomJLabel is centered horizontally and vertically 52 | * in its display area. 53 | * The image displays first following by a trailing text. 54 | * 55 | * @param rect The rectangular bounds that defines the 56 | * CustomJLabel's location and dimension. 57 | * @param icon The image to be displayed by the CustomJLabel. 58 | * @param text The text to be displayed by the CustomJLabel. 59 | */ 60 | public CustomJLabel(Rectangle rect, ImageIcon icon, String text) { 61 | this.CUSTOM_JLABEL_WIDTH = rect.width; 62 | this.CUSTOM_JLABEL_HEIGHT = rect.height; 63 | 64 | setBounds(rect); 65 | setIcon(icon); 66 | setText(text); 67 | 68 | setOpaque(false); 69 | setForeground(Color.WHITE); 70 | setHorizontalAlignment(JLabel.CENTER); 71 | setVerticalAlignment(JLabel.CENTER); 72 | } 73 | 74 | /*** 75 | * Creates a CustomJLabel instance with the specified 76 | * rectangular bounds and image. 77 | * The CustomJLabel is centered horizontally and vertically 78 | * in its display area. 79 | * 80 | * @param rect The rectangular bounds that defines the 81 | * CustomJLabel's location and dimension. 82 | * @param icon The image to be displayed by the CustomJLabel. 83 | */ 84 | public CustomJLabel(Rectangle rect, ImageIcon icon) { 85 | this(rect, icon, ""); 86 | } 87 | 88 | /*** 89 | * Creates a CustomJLabel instance with the specified 90 | * rectangular bounds, text, and its font. 91 | * The CustomJLabel is centered horizontally and vertically 92 | * in its display area. 93 | * 94 | * @param rect The rectangular bounds that defines the 95 | * CustomJLabel's location and dimension. 96 | * @param text The text to be displayed by the CustomJLabel. 97 | * @param font The font that formats the text to be displayed 98 | * by the CustomJLabel. 99 | */ 100 | public CustomJLabel(Rectangle rect, String text, Font font) { 101 | this(rect, null, text); 102 | setFont(font); 103 | } 104 | 105 | /*** 106 | * Creates a CustomJLabel instance with the specified 107 | * rectangular bounds and text. 108 | * The CustomJLabel is centered horizontally and vertically 109 | * in its display area. 110 | * 111 | * @param rect The rectangular bounds that defines the 112 | * CustomJLabel's location and dimension. 113 | * @param text The text to be displayed by the CustomJLabel. 114 | */ 115 | public CustomJLabel(Rectangle rect, String text) { 116 | this(rect, null, text); 117 | } 118 | 119 | /*** 120 | * Creates a CustomJLabel instance with the specified 121 | * rectangular bounds, with no image, empty string for content. 122 | * 123 | * @param rect The rectangular bounds that defines the 124 | * CustomJLabel's location and dimension. 125 | */ 126 | public CustomJLabel(Rectangle rect) { 127 | this(rect, null, ""); 128 | } 129 | 130 | @Override 131 | public Dimension getPreferredSize() { 132 | return new Dimension(this.CUSTOM_JLABEL_WIDTH, this.CUSTOM_JLABEL_HEIGHT); 133 | } 134 | } -------------------------------------------------------------------------------- /Sorting Visualizer/src/customJComponent/CustomJPanel.java: -------------------------------------------------------------------------------- 1 | package customJComponent; 2 | 3 | import java.awt.Color; 4 | import java.awt.Dimension; 5 | import java.awt.Rectangle; 6 | 7 | import javax.swing.JPanel; 8 | 9 | /** 10 | * CustomJPanel 11 | * @author philiks 12 | * Just like an ordinary JPanel, CustomJPanel component 13 | * provides an area as a container of various components 14 | * (supports both native Swing and Custom components). 15 | * 16 | * CustomJPanel was created to serve as a modified version 17 | * of JPanel, its purpose is to provide funtionalities 18 | * (same of JPanel) with some modifications to suit the needs 19 | * of the project, Sorting Visualizer. Such modifications are: 20 | * constructors, Look and Feel, and more default values to its 21 | * properties. 22 | * 23 | * The rectangular bounds specifies the location 24 | * and dimension of the CustomJPanel. 25 | */ 26 | public class CustomJPanel extends JPanel{ 27 | private static final long serialVersionUID = 1L; 28 | 29 | /*** 30 | * CUSTOM_JPANEL_WIDTH and CUSTOM_JPANEL_HEIGHT sets the 31 | * PreferredSize of the CustomJPanel. CUSTOM_JPANEL_WIDTH 32 | * and CUSTOM_JPANEL_HEIGHT overrules the dimension that is 33 | * set by Swing using @see setSize() by overriding 34 | * @see getPreferredSize(). Therefore CustomJPanel 35 | * always use the dimension in rectangular bounds. 36 | * CustomJPanel's dimension can be changed by 37 | * calling the @see setBounds() method. 38 | */ 39 | protected int CUSTOM_JPANEL_WIDTH; 40 | protected int CUSTOM_JPANEL_HEIGHT; 41 | 42 | /*** 43 | * Creates a CustomJPanel instance with the specified 44 | * rectangular bounds. 45 | * The CustomJPanel has a null layout. 46 | * 47 | * @param rect The rectangular bounds that defines the 48 | * CustomJPanel's location and dimension. 49 | * @param action The action that will take place when 50 | * the CustomJPanel is triggered. 51 | * @param icon The image to be displayed by the CustomJPanel. 52 | * @param text The text to be displayed by the CustomJPanel. 53 | */ 54 | public CustomJPanel(Rectangle rect) { 55 | CUSTOM_JPANEL_WIDTH = rect.width; 56 | CUSTOM_JPANEL_HEIGHT = rect.height; 57 | 58 | setBounds(rect); 59 | setLayout(null); 60 | setBackground(Color.BLACK); 61 | } 62 | 63 | /*** 64 | * Creates a CustomJPanel instance with the specified dimension. 65 | * The CustomJPanel's location will be at (0,0) (x,y) coordinate. 66 | * 67 | * @param dim The Dimension of the CustomJPanel. 68 | */ 69 | public CustomJPanel(Dimension dim) { 70 | this(new Rectangle(0, 0, dim.width, dim.height)); 71 | } 72 | 73 | @Override 74 | public Dimension getPreferredSize() { 75 | return new Dimension(CUSTOM_JPANEL_WIDTH, CUSTOM_JPANEL_HEIGHT); 76 | } 77 | } -------------------------------------------------------------------------------- /Sorting Visualizer/src/customJComponent/CustomJSlider.java: -------------------------------------------------------------------------------- 1 | package customJComponent; 2 | import java.awt.Color; 3 | import java.awt.Dimension; 4 | import java.awt.Graphics; 5 | import java.awt.Rectangle; 6 | import java.awt.event.ActionEvent; 7 | import java.awt.event.ActionListener; 8 | import java.awt.event.MouseAdapter; 9 | import java.awt.event.MouseEvent; 10 | 11 | import javax.swing.BoundedRangeModel; 12 | import javax.swing.JSlider; 13 | import javax.swing.Timer; 14 | 15 | /** 16 | * CustomJSlider 17 | * @author philiks 18 | * Just like an ordinary JSlider, CustomJSlider component 19 | * provides a way of adjust certain values via changing 20 | * the state of its thumb. 21 | * 22 | * CustomJSlider was created to serve as a modified version 23 | * of JSlider, its purpose is to provide funtionalities 24 | * (same of JSlider) with some modifications to suit the needs 25 | * of the project, Sorting Visualizer. Such modifications are: 26 | * constructors, Look and Feel, and its ability to cover/uncover. 27 | */ 28 | public class CustomJSlider extends JSlider { 29 | private static final long serialVersionUID = 1L; 30 | 31 | /*** 32 | * CUSTOM_JSLIDER_WIDTH and CUSTOM_JSLIDER_HEIGHT sets the 33 | * PreferredSize of the CustomJSlider. CUSTOM_JSLIDER_WIDTH 34 | * and CUSTOM_JSLIDER_HEIGHT overrules the dimension that is 35 | * set by Swing using @see setSize() by overriding 36 | * @see getPreferredSize(). Therefore CustomJSlider 37 | * always use the dimension in rectangular bounds. 38 | * CustomJSlider's dimension can be changed by 39 | * calling the @see setBounds() method. 40 | */ 41 | protected int CUSTOM_JSLIDER_WIDTH; 42 | protected int CUSTOM_JSLIDER_HEIGHT; 43 | 44 | private Timer sliderCoverAnimation; 45 | private volatile boolean isCovered = true; 46 | private volatile int startOfCoveredRegion; 47 | 48 | public CustomJSlider(Rectangle rect, BoundedRangeModel brm, 49 | int minor_tick, int major_tick) { 50 | CUSTOM_JSLIDER_WIDTH = rect.width; 51 | CUSTOM_JSLIDER_HEIGHT = rect.height; 52 | 53 | setOrientation(HORIZONTAL); 54 | setBounds(rect); 55 | setModel(brm); 56 | setMinorTickSpacing(minor_tick); 57 | setMajorTickSpacing(major_tick); 58 | 59 | setOpaque(false); 60 | setFocusable(false); 61 | setSnapToTicks(true); 62 | 63 | initAnimationTimer(); 64 | 65 | addMouseListener(new MouseAdapter() { 66 | @Override 67 | public void mouseEntered(MouseEvent e) { 68 | if(!isCovered) return; 69 | isCovered = false; 70 | setEnabled(false); 71 | sliderCoverAnimation.start(); 72 | } 73 | 74 | @Override 75 | public void mouseExited(MouseEvent e) { 76 | Rectangle bounds = new Rectangle(0, 0, CUSTOM_JSLIDER_WIDTH, CUSTOM_JSLIDER_HEIGHT); 77 | if(bounds.contains(e.getPoint())) return; 78 | 79 | isCovered = true; 80 | setEnabled(false); 81 | sliderCoverAnimation.start(); 82 | } 83 | }); 84 | } 85 | 86 | @Override 87 | public void paintComponent(Graphics g) { 88 | super.paintComponent(g); 89 | g.setColor(Color.BLACK); 90 | g.fillRect(startOfCoveredRegion, 0, 91 | this.getWidth() - startOfCoveredRegion, this.getHeight()); 92 | } 93 | 94 | public void initAnimationTimer() { 95 | sliderCoverAnimation = new Timer(0, new ActionListener() { 96 | @Override 97 | public void actionPerformed(ActionEvent e) { 98 | if(startOfCoveredRegion <= getWidth() && !isCovered()) 99 | startOfCoveredRegion++; 100 | else if(startOfCoveredRegion >= 0 && isCovered()) 101 | startOfCoveredRegion--; 102 | else { 103 | sliderCoverAnimation.stop(); 104 | setEnabled(true); 105 | } 106 | 107 | repaint(); 108 | } 109 | }); 110 | } 111 | 112 | @Override 113 | public Dimension getPreferredSize() { 114 | return new Dimension(CUSTOM_JSLIDER_WIDTH, CUSTOM_JSLIDER_HEIGHT); 115 | } 116 | 117 | public final int getStartOfCoveredRegion() { 118 | return startOfCoveredRegion; 119 | } 120 | 121 | public final boolean isCovered() { 122 | return isCovered; 123 | } 124 | 125 | public final boolean isAnimationRunning() { 126 | return sliderCoverAnimation.isRunning(); 127 | } 128 | } -------------------------------------------------------------------------------- /Sorting Visualizer/src/customJComponent/CustomSwingWorker.java: -------------------------------------------------------------------------------- 1 | package customJComponent; 2 | 3 | import javax.swing.SwingWorker; 4 | 5 | /** 6 | * CustomSwingWorker 7 | * @author philiks 8 | * Just like an ordinary SwingWorker, CustomSwingWorker 9 | * provides a thread to execute certain tasks. 10 | * 11 | * CustomSwingWorker was created to serve as a modified version 12 | * of SwingWorker, its purpose is to provide funtionalities 13 | * (same of SwingWorker) with one specific modifications to 14 | * suit the needs of the project, Sorting Visualizer. This 15 | * modification is its ability to be paused, resume and 16 | * terminate (termination of SwingWorker already exists but 17 | * overridden for this purpose). 18 | */ 19 | public abstract class CustomSwingWorker extends SwingWorker { 20 | private volatile boolean isPaused; 21 | 22 | public final void pause() { 23 | if(!isPaused() && !isDone()) { 24 | isPaused = true; 25 | firePropertyChange("paused", false, true); 26 | } 27 | } 28 | 29 | public final void resume() { 30 | if(isPaused() && !isDone()) { 31 | isPaused = false; 32 | firePropertyChange("paused", true, false); 33 | } 34 | } 35 | 36 | public final boolean isPaused() { 37 | return isPaused; 38 | } 39 | } -------------------------------------------------------------------------------- /Sorting Visualizer/src/main/MainApp.java: -------------------------------------------------------------------------------- 1 | package main; 2 | 3 | import java.awt.Dimension; 4 | 5 | import javax.swing.JFrame; 6 | import javax.swing.SwingUtilities; 7 | import javax.swing.UIManager; 8 | import javax.swing.UnsupportedLookAndFeelException; 9 | 10 | import screen.MainScreen; 11 | 12 | public class MainApp { 13 | public static final int SCREEN_WIDTH = 1080; 14 | public static final int SCREEN_HEIGHT = SCREEN_WIDTH * 9 / 16; 15 | 16 | private JFrame frame = null; 17 | 18 | private void start() { 19 | try { 20 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 21 | } catch (ClassNotFoundException | InstantiationException | IllegalAccessException 22 | | UnsupportedLookAndFeelException e) { 23 | e.printStackTrace(); 24 | } 25 | 26 | MainScreen screen = new MainScreen(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT)); 27 | 28 | frame = new JFrame("Sorting Visualizer"); 29 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 30 | frame.setResizable(false); 31 | frame.setContentPane(screen); 32 | frame.validate(); 33 | frame.pack(); 34 | frame.setVisible(true); 35 | frame.setLocationRelativeTo(null); 36 | screen.requestFocusInWindow(); 37 | } 38 | 39 | public static void main(String args[]) { 40 | SwingUtilities.invokeLater(new Runnable() { 41 | @Override 42 | public void run() { 43 | new MainApp().start(); 44 | } 45 | }); 46 | } 47 | } -------------------------------------------------------------------------------- /Sorting Visualizer/src/screen/MainScreen.java: -------------------------------------------------------------------------------- 1 | package screen; 2 | 3 | import java.awt.Dimension; 4 | import java.awt.Rectangle; 5 | 6 | import customJComponent.CustomJPanel; 7 | import sortingAlgorithm.SortingAlgorithm; 8 | 9 | public class MainScreen extends CustomJPanel { 10 | private static final long serialVersionUID = 1L; 11 | 12 | private SortingAlgorithm selected_algorithm = SortingAlgorithm.NO_ALGORITHM; 13 | private Menu menuScreen; 14 | private SortingPanel sortingScreen; 15 | private SidePanel sidePanel; 16 | 17 | public static enum PROCESS { 18 | SORT, PAUSE, RESUME, SHUFFLE, RESET, SIDEPANEL_ANIMATION; 19 | } 20 | 21 | public MainScreen(Dimension dim) { 22 | super(dim); 23 | createAndDisplayGUI(); 24 | } 25 | 26 | private void createAndDisplayGUI() { 27 | menuScreen = new Menu(this, new Rectangle(0, 0, 28 | this.getBounds().width, 29 | this.getBounds().height / 10)); 30 | 31 | sortingScreen = new SortingPanel(this, new Rectangle(0, 32 | menuScreen.getY() + menuScreen.getHeight(), 33 | this.getBounds().width, 34 | this.getBounds().height - menuScreen.getHeight())); 35 | 36 | sidePanel = new SidePanel(this, new Rectangle(-1 * this.getBounds().width / 4, 37 | sortingScreen.getY(), 38 | this.getBounds().width / 4, 39 | sortingScreen.getHeight())); 40 | 41 | add(menuScreen); 42 | add(sidePanel); 43 | add(sortingScreen); 44 | } 45 | 46 | public void startProcess(PROCESS process) { 47 | switch(process) { 48 | case SORT: 49 | sortingScreen.sort(); 50 | break; 51 | case PAUSE: 52 | sortingScreen.pause(); 53 | break; 54 | case RESUME: 55 | sortingScreen.resume(); 56 | break; 57 | case SHUFFLE: 58 | sortingScreen.randomizeBarHeight(); 59 | sortingScreen.setAlgorithm(selected_algorithm); 60 | break; 61 | case RESET: 62 | sortingScreen.resetScreen(); 63 | break; 64 | case SIDEPANEL_ANIMATION: 65 | sidePanel.startSidePanelAnimation(); 66 | break; 67 | default: 68 | System.out.println("Process Start Request Error : " + 69 | process + " Undefined Process"); 70 | break; 71 | } 72 | } 73 | 74 | public void doneProcess(PROCESS process) { 75 | switch(process) { 76 | case SORT: 77 | menuScreen.doneSorting(); 78 | break; 79 | case SHUFFLE: 80 | menuScreen.doneShuffling(); 81 | break; 82 | default: 83 | System.out.println("Process Done Flag Error : " + 84 | process + " Undefined Process"); 85 | break; 86 | } 87 | } 88 | 89 | public void changeValue(String name, int value) { 90 | switch(name) { 91 | case "SIZE": 92 | sortingScreen.setBarSize(value); 93 | break; 94 | case "SPEED": 95 | sortingScreen.setSpeed((long)value); 96 | break; 97 | default: 98 | System.out.println("Change Value Error : " + 99 | name + " Undefined variable"); 100 | break; 101 | } 102 | } 103 | 104 | public void setAlgorithm(SortingAlgorithm algorithm) { 105 | this.selected_algorithm = algorithm; 106 | sortingScreen.setAlgorithm(algorithm); 107 | menuScreen.donePicking(); 108 | } 109 | 110 | public boolean isSidePanelShown() { 111 | return sidePanel.isShown(); 112 | } 113 | 114 | public boolean hasChosenAnAlgorithm() { 115 | return selected_algorithm != SortingAlgorithm.NO_ALGORITHM; 116 | } 117 | } -------------------------------------------------------------------------------- /Sorting Visualizer/src/screen/Menu.java: -------------------------------------------------------------------------------- 1 | package screen; 2 | 3 | import java.awt.Font; 4 | import java.awt.Image; 5 | import java.awt.Rectangle; 6 | import java.awt.event.ActionEvent; 7 | import java.awt.event.ActionListener; 8 | import java.awt.event.MouseEvent; 9 | import java.awt.event.MouseListener; 10 | import java.io.IOException; 11 | 12 | import javax.imageio.ImageIO; 13 | import javax.swing.AbstractAction; 14 | import javax.swing.DefaultBoundedRangeModel; 15 | import javax.swing.ImageIcon; 16 | import javax.swing.Timer; 17 | import javax.swing.UIManager; 18 | import javax.swing.event.ChangeEvent; 19 | import javax.swing.event.ChangeListener; 20 | 21 | import customJComponent.CustomJButton; 22 | import customJComponent.CustomJLabel; 23 | import customJComponent.CustomJPanel; 24 | import customJComponent.CustomJSlider; 25 | 26 | public class Menu extends CustomJPanel { 27 | private static final long serialVersionUID = 1L; 28 | private MainScreen mainScreen; 29 | private CustomJButton burger, sort, stop, shuffle; 30 | private CustomJLabel title, sliderName, sliderValue; 31 | private CustomJSlider sizeSlider, speedSlider; 32 | 33 | private Timer sliderAnimationTimer; 34 | 35 | private final String size_slider_name = "SIZE", speed_slider_name = "SPEED"; 36 | private String current_slider; 37 | 38 | public static final int MIN_SIZE_SLIDER_VAL = 10, 39 | MAX_SIZE_SLIDER_VAL = 500, 40 | INIT_SIZE_SLIDER_VAL = 250, 41 | SIZE_SLIDER_MINOR_TICK = 10, 42 | SIZE_SLIDER_MAJOR_TICK = 100; 43 | 44 | public static final int MIN_SPEED_SLIDER_VAL = 10, 45 | MAX_SPEED_SLIDER_VAL = 1000, 46 | INIT_SPEED_SLIDER_VAL = 500, 47 | SPEED_SLIDER_MINOR_TICK = 10, 48 | SPEED_SLIDER_MAJOR_TICK = 250; 49 | 50 | private enum COMPONENT { 51 | //enable | disable 52 | BURGER, SORT, SHUFFLE, SLIDER, 53 | //visible | invisible 54 | SORT_VISIBILITY, STOP_VISIBILITY, SIZE_SLIDER_VISIBILITY; 55 | } 56 | 57 | /* 58 | * Identifies whether sort or resume when sort 59 | * button is triggered. 60 | * First click triggers the sort but the following 61 | * clicks triggers the resume (that means the sorting 62 | * was just interrupted by a pause. 63 | * This goes back to false when the sortingPanel is 64 | * reset. 65 | */ 66 | private boolean wasPaused = false; 67 | 68 | public Menu(MainScreen mainScreen, Rectangle rect) { 69 | super(rect); 70 | this.mainScreen = mainScreen; 71 | 72 | initComponent(); 73 | } 74 | 75 | private void initComponent() { 76 | // 1/6 padding in all sides giving 2/3 of dimension for its content 77 | final int PADDING = CUSTOM_JPANEL_HEIGHT * 1 / 6; 78 | final int FIXED_HEIGHT = CUSTOM_JPANEL_HEIGHT - (2 * PADDING), 79 | FIXED_WIDTH = FIXED_HEIGHT, 80 | FIXED_Y = CUSTOM_JPANEL_HEIGHT / 2 - FIXED_HEIGHT / 2; 81 | final Font SLIDER_FONT = new Font(Font.SANS_SERIF, Font.BOLD, 13); 82 | 83 | // width is important for identifying the dimension (square) of icons 84 | ImageIcon icons[] = setUpIcon(FIXED_HEIGHT); 85 | final int BURGER_ENABLED_INDEX = 0, BURGER_DISABLED_INDEX = 1, 86 | SORT_ENABLED_INDEX = 2, SORT_DISABLED_INDEX = 3, 87 | SHUFFLE_ENABLED_INDEX = 4, SHUFFLE_DISABLED_INDEX = 5, 88 | STOP_ENABLED_INDEX = 6; 89 | 90 | final String burger_tooltip = "ALGORITHM MENU", no_algorithm_tooltip = "PICK AN ALGORITHM FIRST :)", 91 | shuffle_tooltip = "SHUFFLE", stop_tooltip = "STOP"; 92 | 93 | // ==== BUTTON ==== 94 | AbstractAction burger_action = new AbstractAction("burger") { 95 | private static final long serialVersionUID = 1L; 96 | 97 | @Override 98 | public void actionPerformed(ActionEvent e) { 99 | mainScreen.startProcess(MainScreen.PROCESS.SIDEPANEL_ANIMATION); 100 | if(wasPaused) 101 | resetSorting(); 102 | mainScreen.repaint(); 103 | } 104 | }; 105 | 106 | burger = new CustomJButton(new Rectangle(PADDING, 107 | FIXED_Y, 108 | FIXED_WIDTH, FIXED_HEIGHT), 109 | burger_action, 110 | icons[BURGER_ENABLED_INDEX], 111 | icons[BURGER_DISABLED_INDEX], 112 | burger_tooltip); 113 | 114 | AbstractAction sort_action = new AbstractAction("sort") { 115 | private static final long serialVersionUID = 1L; 116 | 117 | @Override 118 | public void actionPerformed(ActionEvent e) { 119 | if(!mainScreen.hasChosenAnAlgorithm()) { 120 | sort.setToolTipText("Please choose an algorithm first :)"); 121 | sort.createToolTip().setVisible(true); 122 | return; 123 | } else { 124 | sort.setToolTipText(""); 125 | } 126 | 127 | if(wasPaused) { 128 | mainScreen.startProcess(MainScreen.PROCESS.RESUME); 129 | }else { 130 | resetSorting(); 131 | mainScreen.startProcess(MainScreen.PROCESS.SORT); 132 | } 133 | 134 | if(mainScreen.isSidePanelShown()) mainScreen.startProcess(MainScreen.PROCESS.SIDEPANEL_ANIMATION); 135 | 136 | changeComponentState(COMPONENT.BURGER, COMPONENT.SHUFFLE, COMPONENT.SLIDER, 137 | COMPONENT.SORT_VISIBILITY, COMPONENT.STOP_VISIBILITY); 138 | } 139 | }; 140 | 141 | sort = new CustomJButton(new Rectangle(burger.getX() + burger.getWidth() + PADDING, 142 | FIXED_Y, 143 | FIXED_WIDTH, 144 | FIXED_HEIGHT), 145 | sort_action, 146 | icons[SORT_ENABLED_INDEX], 147 | icons[SORT_DISABLED_INDEX], 148 | no_algorithm_tooltip); 149 | 150 | AbstractAction stop_action = new AbstractAction("stop") { 151 | private static final long serialVersionUID = 1L; 152 | 153 | @Override 154 | public void actionPerformed(ActionEvent e) { 155 | wasPaused = true; //remains true until sortingPanel was reset 156 | 157 | changeComponentState(COMPONENT.BURGER, COMPONENT.SHUFFLE, COMPONENT.SLIDER, 158 | COMPONENT.SORT_VISIBILITY, COMPONENT.STOP_VISIBILITY); 159 | 160 | mainScreen.startProcess(MainScreen.PROCESS.PAUSE); 161 | } 162 | }; 163 | 164 | stop = new CustomJButton(new Rectangle(burger.getX() + burger.getWidth() + PADDING, 165 | FIXED_Y, 166 | FIXED_WIDTH, 167 | FIXED_HEIGHT), 168 | stop_action, 169 | icons[STOP_ENABLED_INDEX], 170 | stop_tooltip); 171 | 172 | AbstractAction shuffle_action = new AbstractAction("shuffle") { 173 | private static final long serialVersionUID = 1L; 174 | 175 | @Override 176 | public void actionPerformed(ActionEvent e) { 177 | if(mainScreen.isSidePanelShown()) mainScreen.startProcess(MainScreen.PROCESS.SIDEPANEL_ANIMATION); 178 | 179 | changeComponentState(COMPONENT.BURGER, COMPONENT.SORT, COMPONENT.SHUFFLE, 180 | COMPONENT.SIZE_SLIDER_VISIBILITY); 181 | mainScreen.startProcess(MainScreen.PROCESS.SHUFFLE); 182 | } 183 | }; 184 | 185 | shuffle = new CustomJButton(new Rectangle(sort.getX() + sort.getWidth() + PADDING, 186 | FIXED_Y, 187 | FIXED_WIDTH, 188 | FIXED_HEIGHT), 189 | shuffle_action, 190 | icons[SHUFFLE_ENABLED_INDEX], 191 | icons[SHUFFLE_DISABLED_INDEX], 192 | shuffle_tooltip); 193 | 194 | // ==== SLIDER ==== 195 | current_slider = size_slider_name; 196 | sliderName = new CustomJLabel(new Rectangle(shuffle.getX() + shuffle.getWidth() + PADDING, 197 | FIXED_Y, 198 | FIXED_WIDTH * 5 / 4, // increased width to see "SPEED" 199 | FIXED_HEIGHT), current_slider, SLIDER_FONT); 200 | 201 | UIManager.put("Slider.paintValue", false); 202 | 203 | sizeSlider = new CustomJSlider( 204 | new Rectangle(sliderName.getX() + sliderName.getWidth() + PADDING, 205 | FIXED_Y, 206 | FIXED_WIDTH * 2, 207 | FIXED_HEIGHT), 208 | new DefaultBoundedRangeModel(INIT_SIZE_SLIDER_VAL, 0, 209 | MIN_SIZE_SLIDER_VAL, MAX_SIZE_SLIDER_VAL), 210 | SIZE_SLIDER_MINOR_TICK, SIZE_SLIDER_MAJOR_TICK); 211 | sizeSlider.addChangeListener(new ChangeListener() { 212 | @Override 213 | public void stateChanged(ChangeEvent e) { 214 | if(mainScreen.isSidePanelShown()) mainScreen.startProcess(MainScreen.PROCESS.SIDEPANEL_ANIMATION); 215 | 216 | resetSorting(); 217 | int size_value = ((CustomJSlider)e.getSource()).getValue(); 218 | mainScreen.changeValue(size_slider_name, size_value); 219 | sliderValue.setText(String.valueOf(size_value)); 220 | } 221 | }); 222 | sizeSlider.addMouseListener(new MouseListener() { 223 | @Override 224 | public void mouseEntered(MouseEvent e) { 225 | sliderAnimationTimer.start(); 226 | } 227 | 228 | @Override 229 | public void mouseExited(MouseEvent e) { 230 | sliderAnimationTimer.start(); 231 | } 232 | 233 | @Override 234 | public void mouseClicked(MouseEvent e) {} 235 | @Override 236 | public void mousePressed(MouseEvent e) {} 237 | @Override 238 | public void mouseReleased(MouseEvent e) {} 239 | }); 240 | 241 | speedSlider = new CustomJSlider(sizeSlider.getBounds(), 242 | new DefaultBoundedRangeModel(INIT_SPEED_SLIDER_VAL, 0, 243 | MIN_SPEED_SLIDER_VAL, MAX_SPEED_SLIDER_VAL), 244 | SPEED_SLIDER_MINOR_TICK, SPEED_SLIDER_MAJOR_TICK); 245 | speedSlider.addChangeListener(new ChangeListener() { 246 | @Override 247 | public void stateChanged(ChangeEvent e) { 248 | int speed_value = ((CustomJSlider)e.getSource()).getValue(); 249 | mainScreen.changeValue(speed_slider_name, speed_value); 250 | sliderValue.setText(String.valueOf(speed_value) + "ms"); 251 | } 252 | }); 253 | speedSlider.addMouseListener(new MouseListener() { 254 | @Override 255 | public void mouseEntered(MouseEvent e) { 256 | sliderAnimationTimer.start(); 257 | } 258 | 259 | @Override 260 | public void mouseExited(MouseEvent e) { 261 | sliderAnimationTimer.start(); 262 | } 263 | 264 | @Override 265 | public void mouseClicked(MouseEvent e) {} 266 | @Override 267 | public void mousePressed(MouseEvent e) {} 268 | @Override 269 | public void mouseReleased(MouseEvent e) {} 270 | }); 271 | 272 | sliderValue = new CustomJLabel(new Rectangle(sizeSlider.getX(), 273 | FIXED_Y, 274 | FIXED_WIDTH * 3 / 2, // increased width to see "x.xx ms" 275 | FIXED_HEIGHT), 276 | String.valueOf(sizeSlider.getValue()), SLIDER_FONT); 277 | 278 | // ==== TITLE ==== 279 | // x depends on the current width of CustomJSlider 280 | String titleAndDev = "Sorting Visualizer" 281 | + " a program of Felix L. Janopol Jr."; 282 | title = new CustomJLabel(new Rectangle(sizeSlider.getX() + sizeSlider.getStartOfCoveredRegion(), 283 | FIXED_Y, 284 | CUSTOM_JPANEL_WIDTH - (sizeSlider.getX() + sizeSlider.getWidth() + PADDING), 285 | FIXED_HEIGHT), titleAndDev); 286 | 287 | // initial state of components 288 | sort.setEnabled(false); // there's no algorithm yet 289 | stop.setVisible(false); // sort is currently shown 290 | speedSlider.setVisible(false); // size slider is currently shown 291 | 292 | initAnimationTimer(); 293 | 294 | add(burger); 295 | add(sort); 296 | add(shuffle); 297 | add(stop); 298 | add(sliderName); 299 | add(sliderValue); 300 | add(sizeSlider); add(speedSlider); 301 | add(title); 302 | } 303 | 304 | private void initAnimationTimer() { 305 | sliderAnimationTimer = new Timer(0, new ActionListener() { 306 | @Override 307 | public void actionPerformed(ActionEvent e) { 308 | int startOfCoveredRegion = sizeSlider.isVisible() ? 309 | sizeSlider.getStartOfCoveredRegion() 310 | : speedSlider.getStartOfCoveredRegion(); 311 | 312 | // sizeSlider and speedSlider have the same X coordinate relative to Menu panel. 313 | // Must add the X coordinate since the startOfCoveredRegion is relative to the 314 | // slider's X coordinate and not on the panel. 315 | startOfCoveredRegion += sizeSlider.getX(); 316 | 317 | boolean animationRunning = sizeSlider.isVisible() ? 318 | sizeSlider.isAnimationRunning() 319 | : speedSlider.isAnimationRunning(); 320 | 321 | if(animationRunning) { 322 | sliderValue.setLocation(startOfCoveredRegion, sliderValue.getY()); 323 | title.setLocation(sliderValue.getX() + sliderValue.getWidth(), title.getY()); 324 | }else 325 | sliderAnimationTimer.stop(); 326 | } 327 | }); 328 | } 329 | 330 | /*** 331 | * @param dim dimension of the icons when scaled. 332 | */ 333 | private ImageIcon[] setUpIcon(int dim) { 334 | String paths[] = { "/burger-icon-enabled.png", "/burger-icon-disabled.png", 335 | "/sort-icon-enabled.png", "/sort-icon-disabled.png", 336 | "/shuffle-icon-enabled.png","/shuffle-icon-disabled.png", 337 | "/stop-icon-enabled.png" 338 | }; 339 | 340 | ImageIcon icons[] = new ImageIcon[paths.length]; 341 | 342 | // only occupy the 2 / 3 of the button 343 | final int ICON_WIDTH = dim * 2 / 3, 344 | ICON_HEIGHT = ICON_WIDTH; 345 | 346 | for(int i = 0; i < icons.length; i++) { 347 | try { 348 | Image image = ImageIO.read(getClass() 349 | .getResource(paths[i])) 350 | .getScaledInstance(ICON_WIDTH, ICON_HEIGHT, Image.SCALE_SMOOTH); 351 | icons[i] = new ImageIcon(image); 352 | } catch (IOException e) { 353 | System.out.println("Failed to get Image File"); 354 | e.printStackTrace(); 355 | } 356 | } 357 | 358 | return icons; 359 | } 360 | 361 | private void changeComponentState(COMPONENT...components) { 362 | for(COMPONENT component : components) { 363 | switch(component) { 364 | case BURGER: 365 | burger.setEnabled(!burger.isEnabled()); 366 | break; 367 | case SORT: 368 | // sort will remain disabled until there's an algorithm chosen 369 | // therefore, any attempt to change it (i.e. via shuffle), 370 | // sort will remain disabled 371 | if(!mainScreen.hasChosenAnAlgorithm()) sort.setEnabled(false); 372 | else sort.setEnabled(!sort.isEnabled()); 373 | break; 374 | case SORT_VISIBILITY: 375 | sort.setVisible(!sort.isVisible()); 376 | break; 377 | case STOP_VISIBILITY: 378 | stop.setVisible(!stop.isVisible()); 379 | break; 380 | case SHUFFLE: 381 | shuffle.setEnabled(!shuffle.isEnabled()); 382 | break; 383 | case SLIDER: 384 | sizeSlider.setVisible(!sizeSlider.isVisible()); 385 | speedSlider.setVisible(!speedSlider.isVisible()); 386 | 387 | current_slider = current_slider == size_slider_name ? 388 | speed_slider_name 389 | : size_slider_name; 390 | sliderName.setText(current_slider); 391 | 392 | int value = current_slider == size_slider_name ? 393 | sizeSlider.getValue() 394 | : speedSlider.getValue(); 395 | 396 | String strValue = current_slider == size_slider_name ? 397 | String.valueOf(value) 398 | : String.valueOf(value) + "ms"; 399 | sliderValue.setText(strValue); 400 | break; 401 | case SIZE_SLIDER_VISIBILITY: 402 | sizeSlider.setVisible(!sizeSlider.isVisible()); 403 | break; 404 | default: 405 | System.out.println("Undefined Component"); 406 | break; 407 | } 408 | } 409 | } 410 | 411 | public void donePicking() { 412 | sort.setEnabled(true); 413 | sort.setToolTipText("SORT"); 414 | } 415 | 416 | public void doneShuffling() { 417 | changeComponentState(COMPONENT.BURGER, COMPONENT.SORT, COMPONENT.SHUFFLE, 418 | COMPONENT.SIZE_SLIDER_VISIBILITY); 419 | resetSorting(); 420 | } 421 | 422 | public void doneSorting() { 423 | changeComponentState(COMPONENT.BURGER, COMPONENT.SHUFFLE, COMPONENT.SLIDER, 424 | COMPONENT.SORT_VISIBILITY, COMPONENT.STOP_VISIBILITY); 425 | resetSorting(); 426 | } 427 | 428 | public void resetSorting() { 429 | wasPaused = false; 430 | mainScreen.startProcess(MainScreen.PROCESS.RESET); 431 | } 432 | } -------------------------------------------------------------------------------- /Sorting Visualizer/src/screen/SidePanel.java: -------------------------------------------------------------------------------- 1 | package screen; 2 | 3 | import java.awt.Color; 4 | import java.awt.Font; 5 | import java.awt.Rectangle; 6 | import java.awt.event.ActionEvent; 7 | 8 | import javax.swing.AbstractAction; 9 | import javax.swing.BorderFactory; 10 | import javax.swing.SwingWorker; 11 | 12 | import customJComponent.CustomJButton; 13 | import customJComponent.CustomJLabel; 14 | import customJComponent.CustomJPanel; 15 | import sortingAlgorithm.SortingAlgorithm; 16 | 17 | public class SidePanel extends CustomJPanel{ 18 | private static final long serialVersionUID = 1L; 19 | 20 | private MainScreen main_screen; 21 | private SwingWorker side_panel_animation1; 22 | private boolean is_showing_in = false; 23 | 24 | public SidePanel(MainScreen mainScreen, Rectangle dim) { 25 | super(dim); 26 | setBackground(Color.DARK_GRAY); 27 | setBorder(BorderFactory.createLineBorder(Color.WHITE, 2)); 28 | 29 | main_screen = mainScreen; 30 | initComponent(dim.width, dim.height); 31 | } 32 | 33 | /* 34 | * selected_algorithm has the only instantiated object 35 | * since its content will the only one that would change 36 | */ 37 | private void initComponent(int width, int height) { 38 | final int fixed_x = 0, title_height = height / 5; 39 | int y = 0, font_size = 30; //these values change for each component 40 | 41 | String title_text = "
SORTING
ALGORITHM
"; 42 | add(new CustomJLabel(new Rectangle(fixed_x, y, width, title_height), 43 | title_text, new Font("Arial", Font.PLAIN, font_size))); 44 | 45 | font_size = 20; 46 | y = title_height; 47 | int selected_algo_height = title_height; 48 | String selected_algorithm_text = "NONE"; 49 | CustomJLabel selected_algorithm = new CustomJLabel(new Rectangle(fixed_x, y, width, selected_algo_height), 50 | selected_algorithm_text, 51 | new Font("Arial", Font.PLAIN, font_size)) { 52 | private static final long serialVersionUID = 1L; 53 | 54 | @Override 55 | public void setText(String text) { 56 | String selected_algorithm = "
SELECTED SORTING :
" + text + "
"; 57 | super.setText(selected_algorithm); 58 | } 59 | }; 60 | add(selected_algorithm); 61 | 62 | AbstractAction action = new AbstractAction() { 63 | private static final long serialVersionUID = 1L; 64 | 65 | @Override 66 | public void actionPerformed(ActionEvent e) { 67 | String text = ((CustomJButton)e.getSource()).getText(); 68 | selected_algorithm.setText(text); 69 | 70 | main_screen.setAlgorithm(SortingAlgorithm.getAlgorithmViaText(text)); 71 | } 72 | }; 73 | 74 | /* 75 | * divide the remaining spaces depending on the number of sorting 76 | * algorithms minus the "NO_ALGORITHM" 77 | */ 78 | int button_height = (height - (title_height + selected_algo_height)) 79 | / (SortingAlgorithm.values().length - 1); 80 | y = selected_algorithm.getY() + selected_algorithm.getHeight(); 81 | 82 | for(SortingAlgorithm algo : SortingAlgorithm.values()) { 83 | if("NO_ALGORITHM".equals(algo.toString())) continue; 84 | 85 | add(new CustomJButton(new Rectangle(fixed_x, y, width, button_height), 86 | action, 87 | algo.toString().replace("_", " "))); 88 | y += button_height; 89 | } 90 | } 91 | 92 | public void startSidePanelAnimation() { 93 | is_showing_in = !is_showing_in; 94 | 95 | // stop execution if it is currently running, 96 | // then execute again, this time in opposite direction 97 | if(side_panel_animation1 != null && !side_panel_animation1.isDone()) 98 | side_panel_animation1.cancel(true); 99 | 100 | side_panel_animation1 = new SwingWorker<>(){ 101 | @Override 102 | protected Void doInBackground() throws InterruptedException { 103 | while(!isCancelled()) { 104 | if(is_showing_in && getX() <= 0) 105 | setLocation(getX() + 1, getY()); 106 | else if(!is_showing_in && getX() >= -1 * CUSTOM_JPANEL_WIDTH) 107 | setLocation(getX() - 1, getY()); 108 | else 109 | break; 110 | } 111 | return null; 112 | } 113 | 114 | @Override 115 | protected void done() { 116 | super.done(); 117 | side_panel_animation1.cancel(true); 118 | } 119 | }; 120 | 121 | side_panel_animation1.execute(); 122 | } 123 | 124 | public boolean isShown() { 125 | return getX() > -getWidth(); 126 | } 127 | } -------------------------------------------------------------------------------- /Sorting Visualizer/src/screen/SortingPanel.java: -------------------------------------------------------------------------------- 1 | package screen; 2 | 3 | import java.awt.BasicStroke; 4 | import java.awt.Color; 5 | import java.awt.Font; 6 | import java.awt.Graphics; 7 | import java.awt.Graphics2D; 8 | import java.awt.Rectangle; 9 | import java.awt.Stroke; 10 | import java.awt.geom.Rectangle2D; 11 | 12 | import javax.swing.SwingWorker; 13 | 14 | import customJComponent.CustomJPanel; 15 | import customJComponent.CustomSwingWorker; 16 | import sortingAlgorithm.SortingAlgorithm; 17 | 18 | public class SortingPanel extends CustomJPanel { 19 | private static final long serialVersionUID = 1L; 20 | 21 | private MainScreen mainScreen; 22 | 23 | private final float BAR_STROKE_THICKNESS = 2f; 24 | private final int FONT_SIZE = 15; 25 | private final Font ALGORITHM_FONT = new Font("Arial", Font.PLAIN, FONT_SIZE); 26 | 27 | /* default values */ 28 | private int size = Menu.INIT_SIZE_SLIDER_VAL; 29 | private long speed = Menu.INIT_SPEED_SLIDER_VAL; 30 | 31 | private SortingAlgorithm current_algorithm = SortingAlgorithm.NO_ALGORITHM; 32 | private double bar_width; 33 | private double bar_height[]; 34 | 35 | private CustomSwingWorker sortingWorker; 36 | 37 | // -1 means the variable is not yet initialized 38 | private int current_bar_index = -1; 39 | private int traversing_bar_index = -1; 40 | private int selected_bar_index = -1; 41 | 42 | public SortingPanel(MainScreen mainScreen, Rectangle rect) { 43 | super(rect); 44 | this.mainScreen = mainScreen; 45 | 46 | initBarsDimension(); 47 | } 48 | 49 | private void initBarsDimension() { 50 | bar_width = (double) CUSTOM_JPANEL_WIDTH / size; 51 | bar_height = new double[size]; 52 | 53 | double height_interval = (double) CUSTOM_JPANEL_HEIGHT / size; 54 | 55 | for(int i = 0; i < size; i++) 56 | bar_height[i] = height_interval * (i + 1.0) - BAR_STROKE_THICKNESS; 57 | 58 | repaint(); 59 | } 60 | 61 | public void randomizeBarHeight() { 62 | SwingWorker worker = new SwingWorker<>() { 63 | @Override 64 | protected Void doInBackground() throws InterruptedException { 65 | final long random_tick_speed = 10; 66 | int left = 0, right = size - 1; 67 | 68 | for(; left < size / 2; left++, right--) { 69 | int rand_index; 70 | double temp; 71 | 72 | //randomizes left -> center 73 | rand_index = (int) (Math.random() * size); 74 | temp = bar_height[left]; 75 | bar_height[left] = bar_height[rand_index]; 76 | bar_height[rand_index] = temp; 77 | 78 | //randomizes right -> center 79 | rand_index = (int) (Math.random() * size); 80 | temp = bar_height[right]; 81 | bar_height[right] = bar_height[rand_index]; 82 | bar_height[rand_index] = temp; 83 | 84 | repaint(); 85 | Thread.sleep(random_tick_speed); 86 | } 87 | 88 | return null; 89 | } 90 | 91 | @Override 92 | protected void done() { 93 | super.done(); 94 | mainScreen.doneProcess(MainScreen.PROCESS.SHUFFLE); 95 | } 96 | }; 97 | worker.execute(); 98 | } 99 | 100 | @Override 101 | public void paintComponent(Graphics g) { 102 | super.paintComponent(g); 103 | super.paintComponents(g); // to paint CustomJComponents 104 | Graphics2D g2d = (Graphics2D) g; 105 | 106 | Stroke old = g2d.getStroke(); 107 | g2d.setStroke(new BasicStroke(BAR_STROKE_THICKNESS)); 108 | 109 | g2d.setColor(Color.CYAN); 110 | 111 | double x, y; 112 | for(int i = 0; i < size; i++) { 113 | x = i * bar_width; 114 | y = CUSTOM_JPANEL_HEIGHT - (BAR_STROKE_THICKNESS + bar_height[i]); 115 | 116 | Rectangle2D.Double rect = new Rectangle2D.Double(x, y, bar_width, bar_height[i]); 117 | g2d.fill(rect); 118 | } 119 | 120 | if(current_algorithm != SortingAlgorithm.NO_ALGORITHM) 121 | drawAlgorithm(g2d); 122 | 123 | g2d.setStroke(old); 124 | g2d.dispose(); 125 | } 126 | 127 | private void drawAlgorithm(Graphics2D g2d) { 128 | double x, y; 129 | 130 | if((current_bar_index = current_algorithm.get_current_index()) != -1) { 131 | g2d.setColor(Color.GREEN); 132 | 133 | x = current_bar_index * bar_width; 134 | y = CUSTOM_JPANEL_HEIGHT - (BAR_STROKE_THICKNESS + bar_height[current_bar_index]); 135 | 136 | Rectangle2D.Double curr_rect = new Rectangle2D.Double(x, y, bar_width, bar_height[current_bar_index]); 137 | g2d.fill(curr_rect); 138 | } 139 | 140 | if((traversing_bar_index = current_algorithm.get_traversing_index()) != -1) { 141 | g2d.setColor(Color.RED); 142 | 143 | x = traversing_bar_index * bar_width; 144 | y = CUSTOM_JPANEL_HEIGHT - (BAR_STROKE_THICKNESS + bar_height[traversing_bar_index]); 145 | 146 | Rectangle2D.Double select_rect = new Rectangle2D.Double(x, y, bar_width, bar_height[traversing_bar_index]); 147 | g2d.fill(select_rect); 148 | } 149 | 150 | if((selected_bar_index = current_algorithm.get_selected_index()) != -1) { 151 | g2d.setColor(Color.MAGENTA); 152 | 153 | x = selected_bar_index * bar_width; 154 | y = CUSTOM_JPANEL_HEIGHT - (BAR_STROKE_THICKNESS + bar_height[selected_bar_index]); 155 | 156 | Rectangle2D.Double select_rect = new Rectangle2D.Double(x, y, bar_width, bar_height[selected_bar_index]); 157 | g2d.fill(select_rect); 158 | } 159 | 160 | // informations 161 | g2d.setColor(Color.WHITE); 162 | g2d.setFont(ALGORITHM_FONT); 163 | 164 | int string_y_padding = 20, 165 | string_x_padding = 200, 166 | string_tab = 20; 167 | 168 | // current algorithm 169 | x = 20; y = 20; 170 | g2d.drawString("Current Algorithm : ", (int)x, (int)y); 171 | 172 | x += string_x_padding; 173 | String algorithm = current_algorithm.toString().replace("_", " "); 174 | g2d.drawString(algorithm, (int)x, (int)y); 175 | 176 | // array access 177 | x -= string_x_padding; 178 | y += string_y_padding; 179 | g2d.drawString("Array Access : ", (int)x, (int)y); 180 | 181 | x += string_x_padding; 182 | String array_access = String.valueOf(current_algorithm.get_array_access()); 183 | g2d.drawString(array_access, (int)x, (int)y); 184 | 185 | // time complexity 186 | x -= string_x_padding; 187 | y += string_y_padding; 188 | g2d.drawString("Time Complexity :", (int)x, (int)y); 189 | 190 | // worst time complexity 191 | x += string_tab; 192 | y += string_y_padding; 193 | g2d.drawString("Worst Time Complexity : ", (int)x, (int)y); 194 | 195 | x += string_x_padding; 196 | String worst_time_complexity = current_algorithm.get_worst_time_complexity(); 197 | g2d.drawString(worst_time_complexity, (int)x, (int)y); 198 | 199 | // average time complexity 200 | x -= string_x_padding; 201 | y += string_y_padding; 202 | g2d.drawString("Average Time Complexity : ", (int)x, (int)y); 203 | 204 | x += string_x_padding; 205 | String average_time_complexity = current_algorithm.get_average_time_complexity(); 206 | g2d.drawString(average_time_complexity, (int)x, (int)y); 207 | 208 | // best time complexity 209 | x -= string_x_padding; 210 | y += string_y_padding; 211 | g2d.drawString("Best Time Complexity : ", (int)x, (int)y); 212 | 213 | x += string_x_padding; 214 | String best_time_complexity = current_algorithm.get_best_time_complexity(); 215 | g2d.drawString(best_time_complexity, (int)x, (int)y); 216 | 217 | // space complexity 218 | y += string_y_padding; 219 | x -= (string_x_padding + string_tab); 220 | String space_complexity = "Space Complexity : "; 221 | g2d.drawString(space_complexity, (int)x, (int)y); 222 | 223 | // worst space complexity 224 | y += string_y_padding; 225 | x += string_tab; 226 | g2d.drawString("Worst Space Complexity : ", (int)x, (int)y); 227 | 228 | x += string_x_padding; 229 | String worst_space_complexity = current_algorithm.get_worst_space_complexity(); 230 | g2d.drawString(worst_space_complexity, (int)x, (int)y); 231 | } 232 | 233 | public void sort() { 234 | sortingWorker = new CustomSwingWorker<>() { 235 | @Override 236 | protected Void doInBackground() { 237 | current_algorithm.performAlgorithm(bar_height, speed); 238 | 239 | return null; 240 | } 241 | 242 | @Override 243 | protected void done() { 244 | if(isCancelled()) return; 245 | 246 | super.done(); 247 | mainScreen.doneProcess(MainScreen.PROCESS.SORT); 248 | } 249 | }; 250 | sortingWorker.execute(); 251 | } 252 | 253 | public void pause() { 254 | System.out.println("Process is paused..."); 255 | current_algorithm.pause(); 256 | } 257 | 258 | public synchronized void resume() { 259 | System.out.println("Continue..."); 260 | current_algorithm.resume(); 261 | } 262 | 263 | public void setBarSize(int size) { 264 | this.size = size; 265 | initBarsDimension(); 266 | } 267 | 268 | public void setSpeed(long speed) { 269 | this.speed = speed; 270 | if(current_algorithm != SortingAlgorithm.NO_ALGORITHM) current_algorithm.set_speed(speed); 271 | } 272 | 273 | public void setAlgorithm(SortingAlgorithm algorithm) { 274 | this.current_algorithm = algorithm; 275 | if(algorithm != SortingAlgorithm.NO_ALGORITHM) current_algorithm.set_sorting_panel(this); 276 | resetScreen(); 277 | } 278 | 279 | public synchronized void resetScreen() { 280 | if(current_algorithm != SortingAlgorithm.NO_ALGORITHM) current_algorithm.reset(); 281 | current_bar_index = -1; 282 | traversing_bar_index = -1; 283 | selected_bar_index = -1; 284 | 285 | /* This is to terminate undone CustomSwingWorker before 286 | * executing another CustomSwingWorker. 287 | */ 288 | if(sortingWorker != null) { 289 | sortingWorker.cancel(true); 290 | } 291 | } 292 | } -------------------------------------------------------------------------------- /Sorting Visualizer/src/sortingAlgorithm/BogoSort.java: -------------------------------------------------------------------------------- 1 | package sortingAlgorithm; 2 | 3 | public class BogoSort extends SortAlgorithm { 4 | @Override 5 | public void sort(double[] array, long initial_speed) { 6 | super.sort(array, initial_speed); 7 | 8 | while(!isSorted()) { 9 | if(isPaused()) actionWhenPaused(); 10 | 11 | bogoSort(); 12 | 13 | try { 14 | current_index = (int)(Math.random() * array.length); 15 | traversing_index= (int)(Math.random() * array.length); 16 | selected_index = (int)(Math.random() * array.length); 17 | sorting_panel.repaint(); 18 | Thread.sleep(speed); 19 | } catch(InterruptedException e) { 20 | e.printStackTrace(); 21 | } 22 | } 23 | } 24 | 25 | private void bogoSort() { 26 | for(int i = 0; i < array.length; i++) { 27 | int rand_index = (int)(Math.random() * array.length); 28 | double temp = array[i]; 29 | array[i] = array[rand_index]; 30 | array[rand_index] = temp; 31 | } 32 | } 33 | 34 | private boolean isSorted() { 35 | for(int i = 0; i < array.length - 1; i++) { 36 | array_access++; 37 | if(array[i] > array[i + 1]) 38 | return false; 39 | } 40 | 41 | return true; 42 | } 43 | } -------------------------------------------------------------------------------- /Sorting Visualizer/src/sortingAlgorithm/BubbleSort.java: -------------------------------------------------------------------------------- 1 | package sortingAlgorithm; 2 | 3 | public class BubbleSort extends SortAlgorithm { 4 | 5 | @Override 6 | public void sort(double[] array, long initial_speed) { 7 | super.sort(array, initial_speed); 8 | 9 | // this is an optimized Bubble Sort since the swapped flag is used 10 | boolean swapped; 11 | for(current_index = array.length - 1; current_index >= 0; current_index--) { 12 | swapped = false; 13 | for(traversing_index = 0, selected_index = traversing_index + 1; 14 | selected_index <= current_index; 15 | traversing_index++, selected_index++) { 16 | 17 | if(isPaused()) actionWhenPaused(); 18 | 19 | try { 20 | array_access++; 21 | sorting_panel.repaint(); 22 | Thread.sleep(speed); 23 | } catch(InterruptedException e) { 24 | e.printStackTrace(); 25 | } 26 | 27 | if(array[traversing_index] > array[selected_index]) { 28 | swapped = true; 29 | swap(traversing_index, selected_index); 30 | } 31 | } 32 | 33 | // the array is already sorted if there's no swapping occured 34 | if(swapped == false) break; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Sorting Visualizer/src/sortingAlgorithm/InsertionSort.java: -------------------------------------------------------------------------------- 1 | package sortingAlgorithm; 2 | 3 | public class InsertionSort extends SortAlgorithm { 4 | @Override 5 | public void sort(double[] array, long initial_speed) { 6 | super.sort(array, initial_speed); 7 | 8 | for(current_index = 1; current_index < array.length; current_index++) 9 | for(traversing_index = current_index, selected_index = traversing_index - 1; 10 | selected_index >= 0 && array[selected_index] > array[traversing_index]; 11 | traversing_index--, selected_index--) { 12 | 13 | if(isPaused()) actionWhenPaused(); 14 | 15 | try { 16 | array_access++; 17 | sorting_panel.repaint(); 18 | Thread.sleep(speed); 19 | swap(traversing_index, selected_index); 20 | } catch (InterruptedException e) { 21 | e.printStackTrace(); 22 | } 23 | } 24 | 25 | current_index = -1; // resets current_index 26 | } 27 | } -------------------------------------------------------------------------------- /Sorting Visualizer/src/sortingAlgorithm/MergeSort.java: -------------------------------------------------------------------------------- 1 | package sortingAlgorithm; 2 | 3 | public class MergeSort extends SortAlgorithm { 4 | 5 | @Override 6 | public void sort(double[] array, long initial_speed) { 7 | super.sort(array, initial_speed); 8 | 9 | mergeSort(0, array.length - 1); 10 | 11 | traversing_index= -1; 12 | selected_index = -1; 13 | sorting_panel.repaint(); 14 | } 15 | 16 | /*** 17 | * double[] array was defined int SortAlgorithm so there's 18 | * no need for it to be in the list of parameters. 19 | * 20 | * @param start defines where to start the lookup in the array 21 | * @param end defines where to end the lookup in the array 22 | */ 23 | private void mergeSort(int start, int end) { 24 | if(start == end) return; 25 | 26 | // add one since the last element is inclusive 27 | int lookup_length = end - start + 1; 28 | // start serves as offset 29 | int middle = ((lookup_length) / 2) + start; 30 | 31 | // subtract 1 to make middle exclusive on left and inclusive on right 32 | mergeSort(start, middle - 1); 33 | mergeSort(middle, end); 34 | 35 | current_index = start; 36 | merge(start, middle, end); 37 | } 38 | 39 | /*** 40 | * double[] array was defined int SortAlgorithm so there's 41 | * no need for it to be in the list of parameters. 42 | * 43 | * The array is being created inside this method to avoid stacking resources on to the memory stack 44 | * and start serves as the offset therefore, in order to copy the array, this method adds the value 45 | * of start to get its value from the main array. Same logic was applied in calculation of the range 46 | * of the lookup. 47 | * 48 | * @param start defines where to start the lookup in the array 49 | * @param middle defines where is the middle within the lookup range 50 | * @param end defines where to end the lookup in the array 51 | */ 52 | private void merge(int start, int middle, int end) { 53 | int lookup_length = end - start + 1; 54 | double[] temp = new double[lookup_length]; 55 | 56 | // copies elements from array to temp 57 | // note that temp = array should not be used since it will create a pointer 58 | // to the array therefore, changing temp would reflect on array (main) 59 | for(int i = 0; i < lookup_length; i++) 60 | temp[i] = array[start + i]; 61 | 62 | // start serves as offset on the main array but not on temp 63 | int temp_middle = middle - start; 64 | int a_ptr = start; 65 | int l_ptr = 0; 66 | int r_ptr = temp_middle; 67 | 68 | while(l_ptr < temp_middle && r_ptr < temp.length) { 69 | if(isPaused()) actionWhenPaused(); 70 | 71 | array_access++; 72 | traversing_index= l_ptr + start; 73 | selected_index = r_ptr + start; 74 | 75 | if(temp[l_ptr] < temp[r_ptr]) 76 | array[a_ptr] = temp[l_ptr++]; 77 | else 78 | array[a_ptr] = temp[r_ptr++]; 79 | 80 | try { 81 | a_ptr++; 82 | sorting_panel.repaint(); 83 | Thread.sleep(speed); 84 | } catch(InterruptedException e) { 85 | e.printStackTrace(); 86 | } 87 | } 88 | 89 | // copy remaining elements 90 | while(l_ptr < temp_middle) { 91 | if(isPaused()) actionWhenPaused(); 92 | 93 | try { 94 | traversing_index= l_ptr + start; 95 | sorting_panel.repaint(); 96 | Thread.sleep(speed); 97 | } catch(InterruptedException e) { 98 | e.printStackTrace(); 99 | } 100 | 101 | array[a_ptr++] = temp[l_ptr++]; 102 | } 103 | 104 | while(r_ptr < temp.length) { 105 | if(isPaused()) actionWhenPaused(); 106 | 107 | try { 108 | selected_index = r_ptr + start; 109 | sorting_panel.repaint(); 110 | Thread.sleep(speed); 111 | } catch(InterruptedException e) { 112 | e.printStackTrace(); 113 | } 114 | 115 | array[a_ptr++] = temp[r_ptr++]; 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /Sorting Visualizer/src/sortingAlgorithm/QuickSort.java: -------------------------------------------------------------------------------- 1 | package sortingAlgorithm; 2 | 3 | public class QuickSort extends SortAlgorithm { 4 | 5 | @Override 6 | public void sort(double[] array, long initial_speed) { 7 | super.sort(array, initial_speed); 8 | 9 | int left = 0; 10 | int right = array.length - 1; 11 | int middle = (left + right) / 2; 12 | int pivot = medianOfThree(left, middle, right); 13 | quickSort(pivot, left, right); 14 | 15 | traversing_index = -1; // reset traversing index 16 | current_index = -1; // reset current index 17 | } 18 | 19 | /*** 20 | * @param pivot result of medianOfThree method 21 | * @param start start pointer of the lookup array 22 | * @param end end pointer of the lookup array 23 | */ 24 | private void quickSort(int pivot, int start, int end) { 25 | if(start >= end) return; 26 | 27 | int selected_index = start - 1; 28 | swap(pivot, end); 29 | pivot = end; 30 | 31 | current_index = pivot; 32 | for(traversing_index = start; traversing_index < pivot; traversing_index++) { 33 | if(isPaused()) actionWhenPaused(); 34 | 35 | if(array[traversing_index] < array[pivot]) 36 | swap(++selected_index, traversing_index); 37 | 38 | try { 39 | array_access++; 40 | sorting_panel.repaint(); 41 | Thread.sleep(speed); 42 | } catch(InterruptedException e) { 43 | e.printStackTrace(); 44 | } 45 | } 46 | int new_pivot_pos = selected_index + 1; 47 | swap(new_pivot_pos, pivot); 48 | 49 | // quick sort the left side 50 | int less_middle = (start + selected_index) / 2; 51 | int less_pivot = medianOfThree(start, less_middle, selected_index); 52 | quickSort(less_pivot, start, selected_index); 53 | 54 | // quick sort the right side 55 | int greater_start = new_pivot_pos + 1; 56 | int greater_middle = (greater_start + end) / 2; 57 | int greater_pivot = medianOfThree(greater_start, greater_middle, end); 58 | quickSort(greater_pivot, greater_start, end); 59 | } 60 | 61 | /*** 62 | * @param a start of array 63 | * @param b middle of array 64 | * @param c end of array 65 | * @return index of median of three 66 | */ 67 | private int medianOfThree(int a, int b, int c) { 68 | double left = array[a]; 69 | double middle = array[b]; 70 | double right = array[c]; 71 | 72 | if((left > middle) != (left > right)) 73 | return a; 74 | else if((middle > left) != (middle > right)) 75 | return b; 76 | else 77 | return c; 78 | } 79 | } -------------------------------------------------------------------------------- /Sorting Visualizer/src/sortingAlgorithm/SelectionSort.java: -------------------------------------------------------------------------------- 1 | package sortingAlgorithm; 2 | 3 | public class SelectionSort extends SortAlgorithm { 4 | 5 | @Override 6 | public void sort(double[] array, long initial_speed) { 7 | super.sort(array, initial_speed); 8 | 9 | for(current_index = 0; current_index < array.length - 1; current_index++) { 10 | selected_index = current_index; // holds the index of lowest value 11 | 12 | for(traversing_index = current_index; traversing_index < array.length; traversing_index++) { 13 | if(isPaused()) actionWhenPaused(); 14 | 15 | try { 16 | array_access++; 17 | sorting_panel.repaint(); 18 | Thread.sleep(speed); 19 | } catch(InterruptedException e) { 20 | e.printStackTrace(); 21 | } 22 | 23 | if(array[traversing_index] < array[selected_index]) 24 | selected_index = traversing_index; 25 | } 26 | 27 | traversing_index = -1; // resets traversing_index 28 | swap(current_index, selected_index); 29 | } 30 | 31 | current_index = -1; // resets current_index 32 | } 33 | } -------------------------------------------------------------------------------- /Sorting Visualizer/src/sortingAlgorithm/SortAlgorithm.java: -------------------------------------------------------------------------------- 1 | package sortingAlgorithm; 2 | 3 | import screen.SortingPanel; 4 | 5 | // this is a framework for sorting algorithms 6 | // this is different from SortingAlgorithm (enum) 7 | abstract class SortAlgorithm { 8 | protected SortingPanel sorting_panel; 9 | 10 | protected int current_index = -1; 11 | protected int traversing_index = -1; 12 | protected int selected_index = -1; 13 | 14 | // increments depending on the given unsorted array 15 | // not theoretical 16 | protected int array_access; 17 | protected volatile boolean isPaused = false; 18 | protected final long PAUSED_INTERVAL = 1000; 19 | protected double[] array; 20 | protected long speed = 0; 21 | 22 | /* 23 | * the sort method will go here once the pause() is triggered. 24 | * pause() method shouldn't call this because the method would 25 | * be the one that'll be interrupted. 26 | */ 27 | protected final synchronized void actionWhenPaused() { 28 | while(isPaused()) { 29 | System.out.println("waiting..."); 30 | 31 | try { 32 | Thread.sleep(PAUSED_INTERVAL); 33 | } catch (InterruptedException e) { 34 | // interrupts the sleep without crashing the program 35 | System.out.println("Thread Closed"); 36 | } 37 | } 38 | } 39 | 40 | protected final void swap(int a_index, int b_index) { 41 | double temp = array[a_index]; 42 | array[a_index] = array[b_index]; 43 | array[b_index] = temp; 44 | 45 | sorting_panel.repaint(); 46 | } 47 | 48 | public final void pause() { 49 | if(!isPaused()) 50 | isPaused = true; 51 | } 52 | 53 | public final void resume() { 54 | if(isPaused()) 55 | isPaused = false; 56 | } 57 | 58 | public final void reset() { 59 | isPaused = false; 60 | current_index = -1; 61 | traversing_index = -1; 62 | selected_index = -1; 63 | speed = 0; 64 | array_access = 0; 65 | } 66 | 67 | public void sort(double[] array, long initial_speed) { 68 | this.array = array; 69 | speed = initial_speed; 70 | } 71 | 72 | public final void set_sorting_panel(SortingPanel sorting_panel) { this.sorting_panel = sorting_panel; } 73 | public final void set_speed(long speed) { this.speed = speed; } 74 | 75 | public final boolean isPaused() { return isPaused; } 76 | public final int get_array_access() { return array_access; } 77 | public final int get_current_index() { return current_index; } 78 | public final int get_traversing_index() { return traversing_index; } 79 | public final int get_selected_index() { return selected_index; } 80 | } -------------------------------------------------------------------------------- /Sorting Visualizer/src/sortingAlgorithm/SortingAlgorithm.java: -------------------------------------------------------------------------------- 1 | package sortingAlgorithm; 2 | 3 | import screen.SortingPanel; 4 | 5 | public enum SortingAlgorithm { 6 | /* 7 | OMEGA = '\u03a9', 8 | THETA = '\u0398', 9 | OMICRON = '\u039f'; 10 | */ 11 | NO_ALGORITHM(), 12 | INSERTION_SORT (new InsertionSort(), new String[] {"\u03a9(n)", "\u0398(n^2)", "\u039f(n^2)"}, "\u039f(1)"), 13 | SELECTION_SORT (new SelectionSort(), new String[] {"\u03a9(n^2)", "\u0398(n^2)", "\u039f(n^2)"}, "\u039f(1)"), 14 | BUBBLE_SORT (new BubbleSort(), new String[] {"\u03a9(n)", "\u0398(n^2)", "\u039f(n^2)"}, "\u039f(1)"), 15 | MERGE_SORT (new MergeSort(), new String[] {"\u03a9(n log(n))", "\u0398(n log(n))", "\u039f(n log(n))"},"\u039f(n)"), 16 | QUICK_SORT (new QuickSort(), new String[] {"\u03a9(n log(n))", "\u0398(n log(n))", "\u039f(n^2)"}, "\u039f(log(n))"), 17 | BOGO_SORT (new BogoSort(), new String[] {"\u03a9(n)", "\u0398((n+1)!)", "\u039f((n+1)!)"}, "\u039f(n)"); 18 | 19 | private final int NUM_OF_COMPLEXITY = 3; 20 | // could use enum but the use of ENUM_NAME.FIELD.ORDINAL() is quite long 21 | private final int BEST = 0, AVERAGE = 1, WORST = 2; 22 | 23 | private String[] time_complexity = new String[NUM_OF_COMPLEXITY]; 24 | private String worst_space_complexity; 25 | private SortAlgorithm algorithm; 26 | 27 | // NO_ALGORITHM 28 | SortingAlgorithm(){ 29 | } 30 | 31 | SortingAlgorithm(SortAlgorithm algorithm, String[] time_complexity, String worst_space_complexity) { 32 | this.algorithm = algorithm; 33 | 34 | //copies the time_complexity of the sorting algorithm 35 | for(int i = 0; i < time_complexity.length; i++) 36 | this.time_complexity[i] = time_complexity[i]; 37 | 38 | this.worst_space_complexity = worst_space_complexity; 39 | } 40 | 41 | /* 42 | * Requires a separate class in performing algorithm 43 | * because some algorithms requires the same data structures 44 | * with different specifications. And also to prevent this enum to be bulky. 45 | */ 46 | public void performAlgorithm(double[] array, long initial_speed) { 47 | algorithm.sort(array, initial_speed); 48 | } 49 | 50 | public String get_worst_space_complexity() { return worst_space_complexity; } 51 | public String get_best_time_complexity() { return time_complexity[BEST]; } 52 | public String get_average_time_complexity() { return time_complexity[AVERAGE]; } 53 | public String get_worst_time_complexity() { return time_complexity[WORST]; } 54 | 55 | public int get_current_index() { return algorithm.get_current_index(); } 56 | public int get_traversing_index() { return algorithm.get_traversing_index(); } 57 | public int get_selected_index() { return algorithm.get_selected_index(); } 58 | public int get_array_access() { return algorithm.get_array_access(); } 59 | public boolean isPaused() { return algorithm.isPaused(); } 60 | 61 | public void pause() { algorithm.pause(); } 62 | public void resume() { algorithm.resume(); } 63 | public void reset() { algorithm.reset(); } 64 | public void set_speed(long speed) { algorithm.set_speed(speed); } 65 | public void set_sorting_panel(SortingPanel sorting_panel) { algorithm.set_sorting_panel(sorting_panel); } 66 | 67 | public static SortingAlgorithm getAlgorithmViaText(String text) { 68 | switch(text) { 69 | case "INSERTION SORT": 70 | return INSERTION_SORT; 71 | case "SELECTION SORT": 72 | return SELECTION_SORT; 73 | case "BUBBLE SORT": 74 | return BUBBLE_SORT; 75 | case "MERGE SORT": 76 | return MERGE_SORT; 77 | case "QUICK SORT": 78 | return QUICK_SORT; 79 | case "BOGO SORT": 80 | return BOGO_SORT; 81 | default: 82 | return NO_ALGORITHM; 83 | } 84 | } 85 | } --------------------------------------------------------------------------------