diff --git a/src/com/example/algorithmvisualizer/AlgVisualizer.java b/src/com/example/algorithmvisualizer/AlgVisualizer.java index 5916c2f..97ee297 100644 --- a/src/com/example/algorithmvisualizer/AlgVisualizer.java +++ b/src/com/example/algorithmvisualizer/AlgVisualizer.java @@ -18,18 +18,29 @@ import java.awt.Dimension; import java.util.*; import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + import java.awt.event.*; -public class AlgVisualizer implements ActionListener { +public class AlgVisualizer implements ActionListener, ChangeListener { + private final int CONTENT_WIDTH = 900; + private final int CONTENT_HEIGHT = 960; + private final int ARR_DISPLAY_HEIGHT = 900; + private final int FPS_MIN = 1; + private final int FPS_INIT = 10; + private final int FPS_MAX = 100; + private final String[] SIZE_OPTIONS = { "10", "50", "100", "300", "450", "900" }; // array size options private int n; - private final int CONTENT_WIDTH = 800; - private final int CONTENT_HEIGHT = 860; - private final int ARR_DISPLAY_HEIGHT = 800; - private final String[] SIZE_OPTIONS = { "10", "50", "100", "200", "400", "800" }; // array size options + private int numSwaps; + private int delay; + private long totalDelay; private Integer indexComparisons; private long startTime; // start time of a sort private long endTime; // end time of a sort + private long visualizationTime; + private long sortingTime; private boolean doBubbleSort; private boolean doInsertionSort; private boolean doSelectionSort; @@ -47,8 +58,9 @@ public class AlgVisualizer implements ActionListener { private JButton selectionButton; private JButton mergeButton; private JButton quickButton; - private JButton performanceButton; private JComboBox sizeChanger; + private JSlider FPSslider; + private JLabel performanceLabel; private SwingWorker arrSort; /* @@ -83,6 +95,11 @@ public void initializeVars() { arr = shuffleArr(arr); indexComparisons = 0; + startTime = 0; + endTime = 0; + visualizationTime = 0; + sortingTime = 0; + setDelay(1000 / FPS_INIT); // Initialize objects that will display and sort the array @@ -131,10 +148,13 @@ public void initializeVars() { sizeChanger.addActionListener(this); sizeChanger.setBackground(Color.WHITE); - performanceButton = new JButton("Performance"); - performanceButton.addActionListener(this); - performanceButton.setBackground(Color.WHITE); - performanceButton.setEnabled(false); // This button is not available until a sort is complete + FPSslider = new JSlider(JSlider.HORIZONTAL, FPS_MIN, FPS_MAX, FPS_INIT); + FPSslider.addChangeListener(this); + FPSslider.setBackground(Color.DARK_GRAY); + // Initialize the performance label and center it + + performanceLabel = new JLabel(); + performanceLabel.setHorizontalAlignment(SwingConstants.CENTER); } /* @@ -152,7 +172,7 @@ public void setFrame() { buttonPanel.add(mergeButton); buttonPanel.add(quickButton); buttonPanel.add(sizeChanger); - buttonPanel.add(performanceButton); + buttonPanel.add(FPSslider); // Initialize and make the frame visible frame = new JFrame("Algorithm Visualizer"); @@ -160,6 +180,7 @@ public void setFrame() { frame.setResizable(false); // Cannot be resizable, causes visual issues frame.add(buttonPanel, BorderLayout.PAGE_START); // Button panel added to the top of the frame frame.add(arrPanel, BorderLayout.PAGE_END); // Array display is added to the bottom of the frame + frame.add(performanceLabel); frame.pack(); frame.setLocationRelativeTo(null); // center of the screen frame.setVisible(true); @@ -215,14 +236,16 @@ public void actionPerformed(ActionEvent event) { // reset and paint the new array reset(); arrSort.execute(); - } else if (event.getSource() == performanceButton) { - int numSwaps = arrDisplay.getSwappedIndexes().size(); - long visualizationTime = endTime - startTime; // net time - long sortingTime = visualizationTime - (60 * numSwaps + 1); // - NEED TO FIX - String statsMessage = String.format( - "Index Comparisons : %d Index Swaps : %d Visualization Time : %dms Sorting Time : %dms", - indexComparisons, numSwaps, visualizationTime, sortingTime); - JOptionPane.showMessageDialog(frame, statsMessage, "Performance", JOptionPane.PLAIN_MESSAGE); + } + } + + @Override + public void stateChanged(ChangeEvent e) { + JSlider source = (JSlider) e.getSource(); + if (!source.getValueIsAdjusting()) { + int fps = (int) source.getValue(); + delay = 1000 / fps; // ms + setDelay(delay); } } @@ -239,7 +262,6 @@ public void reset() { setStopSort(true); arr = shuffleArr(arr); arrDisplay.clearSwappedIndexes(); - arrDisplay.setNumChunk(0); arrDisplay.setComplete(false); arrDisplay.setArr(arr); indexComparisons = 0; @@ -257,6 +279,9 @@ public void resetSwingWorker(AlgVisualizer alg, Integer[] arr, ArrDisplay displa public void resetTime() { startTime = 0; endTime = 0; + visualizationTime = 0; + sortingTime = 0; + totalDelay = 0; } public Integer[] shuffleArr(Integer[] arr) { @@ -274,6 +299,40 @@ public Integer[] fillArr(Integer[] arr) { return arr; } + /* + * updatePerformance will be called every time the array is repainted. This + * makes it slower / not real time when there is a high delay. + * + * We get the values for each performance statistic we want to track (number of + * swaps, number of comparisons, visualization time, sorting time), format them + * into a string that will then be assigned to the JLabel's text. + * + * frame.pack() makes sure that our new text will fit in the frame, and will + * adjust if it does not. + */ + public void updatePerformance() { + numSwaps = arrDisplay.getSwappedIndexes().size(); + System.out.println("total delay " + totalDelay); + if (!getSort().equals("Not Sorting") && arrDisplay.getNumChunks() == 1) { + visualizationTime = System.currentTimeMillis() - startTime; + sortingTime = visualizationTime - totalDelay; + } else if (arrDisplay.getNumChunks() > 1) { + visualizationTime = System.currentTimeMillis() - startTime; + sortingTime = visualizationTime - totalDelay; + } + if(stopSort) { + resetTime(); + } + + String performance = String.format( + "Index Comparisons : %d Index Swaps : %d Visualization Time : %dms Sorting Time : %dms", + indexComparisons, numSwaps, visualizationTime, sortingTime); + + performanceLabel.setText(performance); + + frame.pack(); + } + public Integer[] getArr() { return arr; } @@ -366,10 +425,6 @@ public void setN(int n) { this.n = n; } - public JButton getPerformanceButton() { - return performanceButton; - } - public Integer getIndexComparisons() { return indexComparisons; } @@ -393,4 +448,44 @@ public long getEndTime() { public void setEndTime(long endTime) { this.endTime = endTime; } + + public JLabel getPerformanceLabel() { + return performanceLabel; + } + + public void setPerformanceLabel(JLabel performanceLabel) { + this.performanceLabel = performanceLabel; + } + + public int getNumSwaps() { + return numSwaps; + } + + public void setNumSwaps(int numSwaps) { + this.numSwaps = numSwaps; + } + + public int getDelay() { + return delay; + } + + public void setDelay(int delay) { + this.delay = delay; + } + + public JSlider getFPSslider() { + return FPSslider; + } + + public void setFPSslider(JSlider fPSslider) { + FPSslider = fPSslider; + } + + public long getTotalDelay() { + return totalDelay; + } + + public void setTotalDelay(long totalDelay) { + this.totalDelay = totalDelay; + } } diff --git a/src/com/example/algorithmvisualizer/ArrDisplay.java b/src/com/example/algorithmvisualizer/ArrDisplay.java index a47d5af..f7ec896 100644 --- a/src/com/example/algorithmvisualizer/ArrDisplay.java +++ b/src/com/example/algorithmvisualizer/ArrDisplay.java @@ -22,7 +22,7 @@ public class ArrDisplay extends JComponent { private static final long serialVersionUID = 1L; private int swappedIndex1; private int swappedIndex2; - private int numChunk; // amount of frames painted since the array was shuffled + private int numChunks; // amount of frames painted since the array was shuffled private boolean isComplete; // if the array is sorted private ArrayList swappedIndexes; private Integer[] arr; @@ -61,8 +61,9 @@ public void paintComponent(Graphics g) { swappedIndex1 = -1; swappedIndex2 = -1; } else if (!algVisualizer.stopSort()) { - swappedIndex1 = swappedIndexes.get(numChunk - 1)[0]; - swappedIndex2 = swappedIndexes.get(numChunk - 1)[1]; + // exclude the first chunk as its used to draw the first array, not related to the sorting + swappedIndex1 = swappedIndexes.get(numChunks - 1)[0]; // index out of bounds exception? + swappedIndex2 = swappedIndexes.get(numChunks - 1)[1]; } // Iterate through the array and drawn every index @@ -89,6 +90,7 @@ public void paintComponent(Graphics g) { // Draw the current indexes bar graphics2d.fillRect(x, y, width, height); } + algVisualizer.updatePerformance(); } public ArrayList getSwappedIndexes() { @@ -104,12 +106,12 @@ public void clearSwappedIndexes() { swappedIndexes = new ArrayList(); } - public void setNumChunk(int numChunk) { - this.numChunk = numChunk; + public void setNumChunk(int numChunks) { + this.numChunks = numChunks; } - public int getNumChunk() { - return numChunk; + public int getNumChunks() { + return numChunks; } public boolean isComplete() { @@ -117,10 +119,6 @@ public boolean isComplete() { } public void setComplete(boolean complete) { - // Performance Button's availability is based on whether or not the array is - // sorted. - algVisualizer.getPerformanceButton().setEnabled(complete); - this.isComplete = complete; } diff --git a/src/com/example/algorithmvisualizer/ArrSorting.java b/src/com/example/algorithmvisualizer/ArrSorting.java index 36f74f1..cecdb6e 100644 --- a/src/com/example/algorithmvisualizer/ArrSorting.java +++ b/src/com/example/algorithmvisualizer/ArrSorting.java @@ -18,12 +18,11 @@ public class ArrSorting extends SwingWorker { - private Integer delay = 10; private int n; private Integer[] arr; private AlgVisualizer algVisualizer; private ArrDisplay arrDisplay; - private int numChunk; + private int numChunks; public ArrSorting(AlgVisualizer algVisualizer, Integer[] arr, ArrDisplay arrDisplay) { this.algVisualizer = algVisualizer; @@ -87,8 +86,8 @@ protected Void doInBackground() throws Exception { protected void process(List chunks) { while (chunks.size() > 0) { // Paint each cloned array and update number of chunks - numChunk++; - arrDisplay.setNumChunk(this.numChunk); + numChunks++; + arrDisplay.setNumChunk(this.numChunks); arrDisplay.setArr(chunks.get(0)); arrDisplay.repaint(); chunks.remove(0); @@ -101,7 +100,9 @@ protected void process(List chunks) { */ private void sleep() { try { - Thread.sleep(delay); + Thread.sleep(algVisualizer.getDelay()); + if (!algVisualizer.stopSort()) + algVisualizer.setTotalDelay(algVisualizer.getTotalDelay() + algVisualizer.getDelay()); } catch (InterruptedException e) { e.printStackTrace(); }