├── 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 | }
--------------------------------------------------------------------------------