Monday, December 12, 2011

Semester is almost over!

DOWNLOAD: Observable Sort Project

It has been a LONG semester. 32 hour work weeks + 12 units = BUSY. But, I came out of it a much stronger developer! Work in C#, PHP, Javascript, and of course, JAVA.

Here is a small sample from the "Observable Sort" program a partner and I wrote this semester. The program has a full GUI interface and allows users to watch sorting algorithms side by side and compare what each "looks" like.

 Main Class -- ObservableSortTest.java:

//Javadoc COMPLETE -- 12/3/2011

/**
 * @Author Jason Campos
 */


import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;

import cs151.project1.ObservableSortDriver;
import cs151.project1.gui.MenuGUI;
import cs151.project1.quantifiable.InventoryItem;
import cs151.project1.quantifiable.qInteger;
import cs151.project1.quantifiable.qString;
import cs151.project1.sorters.bubblesort.BubbleSort;
import cs151.project1.sorters.cocktailsort.CocktailSort;
import cs151.project1.sorters.heapsort.HeapSort;
import cs151.project1.sorters.insertionsort.InsertionSort;
import cs151.project1.sorters.mergesort.MergeSort;
import cs151.project1.sorters.quicksort.Quicksort;
import cs151.project1.sorters.ripplesort.RippleSort;
import cs151.project1.sorters.selectionsort.SelectionSort;
import cs151.project1.views.GraphView;
import cs151.project1.views.LineView;
import cs151.project1.views.PointView;
import cs151.project1.views.TowerView;
import cs151.project1.views.WebView;

public class ObservableSortTest {
    public static ArrayList<Class<?>> sorters;
    public static ArrayList<Class<?>> graphs;
    public static ArrayList<Class<?>> quantifiables;
   
    /**
     * Main method. Displays the GUI menu for the values initialized in init() and the driver that powers the visualizations.
     *
     * @param args
     * @throws InterruptedException
     * @throws SecurityException
     * @throws IllegalArgumentException
     * @throws NoSuchMethodException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    public static void main (String args[]) throws InterruptedException, SecurityException, IllegalArgumentException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException{
        System.out.println("Intializing...");
        init();
        while (ObservableSortDriver.IS_READY == false ){ // restart if ObservableSortDriver is reset
            MenuGUI menu = new MenuGUI(sorters, graphs, quantifiables);
            Thread t = new Thread(menu, "Observable Sort Menu");
            t.start();
            ObservableSortDriver d = new ObservableSortDriver();
            d.run();
            while(ObservableSortDriver.IS_READY == true) { Thread.sleep(1000); } // pause
        }
    }

    /**
     * This method initializes all necessary classes for ObservableSort. To add a new item to
     * the menu (sort, data, or graph), enter the class name in to the appropriate array below.
     * @throws SecurityException
     * @throws IllegalArgumentException
     * @throws NoSuchMethodException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     * @throws InterruptedException
     */
    public static void init() throws SecurityException, IllegalArgumentException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, InterruptedException {
        sorters       = new ArrayList<Class<?>>();
        graphs           = new ArrayList<Class<?>>();
        quantifiables = new ArrayList<Class<?>>();
       
        /* ADD SORTING CLASSES TO THE LIST */
        System.out.println("Creating sorter classes");
        sorters.add(Quicksort.class);
        sorters.add(SelectionSort.class);
        sorters.add(InsertionSort.class);
        sorters.add(CocktailSort.class);
        sorters.add(RippleSort.class);
        sorters.add(BubbleSort.class);
        sorters.add(MergeSort.class);
        sorters.add(HeapSort.class);
       
        /* ADD GRAPHS TO THE LIST */
        graphs.add(TowerView.class);
        graphs.add(GraphView.class);
        graphs.add(PointView.class);
        graphs.add(LineView.class);
        graphs.add(WebView.class);
       
        /* ADD QUANTIFIABLE CLASSES TO THE LIST */
        quantifiables.add(InventoryItem.class);
        quantifiables.add(qString.class);
        quantifiables.add(qInteger.class);
    }
}

ObservableSortDriver.java

// JAVADOC COMPLETE 12/3/2011
package cs151.project1;
/**
 * @Author Jason Campos
 */

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.JTableHeader;

import cs151.project1.views.ObserverGraph;

/**
 * This class creates the JFrame which holds all animations, creates the SortVisualizations based on input from
 * the MenuGUI, manages threads which contain those animations. Invoking this class' run() method sends the class into
 * a state of waiting which is terminated when the IS_READY flag is flipped to true (in this case, done by MenuGUI when
 * the "run" button is clicked).
 *
 * @author Jason Campos, Vuong Scott Tran
 *
 */
@SuppressWarnings("rawtypes")
public class ObservableSortDriver{
    /** Sort classes selected for visualization */
    public static ArrayList<Class> chosenSorts = new ArrayList<Class>();
    /** Graph class selected for visualization */
    public static Class chosenGraph;
    /** Comparable data to sort */
    public static Comparable<?>[] chosenData;
    /** Flag inidacting whether or not chosenSorts, chosenGraph, and chosenData are ready to be processed */
    public static boolean IS_READY = false ;
   
    /**
     * Creates a JFrame which holds all animations and a set of threads to place
     * SortVisualizations in.
     *
     * @throws InterruptedException
     */
    public ObservableSortDriver() throws InterruptedException{
        appFrame = new JFrame();
        threads  = new ArrayList<Thread>();
        sorters = new ArrayList<ObservableSort<?>>();
    }
   
    /**
     * Sets visibility of the application frame.
     * @param b - true/false flag for visibility of the application frame
     */
    public void setVisible(boolean b){
        appFrame.setVisible(b);
    }
   
    /**
     * Waits for the IS_READY flag to be changed by an external thread. Upon this flag being flipped,
     * the application frame is constructed, SortVisualizations are built, and their threads are executed.
     */
    @SuppressWarnings("unchecked")
    public void run() {
        while (!IS_READY)
        {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
       
        initializeDimensions(chosenSorts.size());
       
        for (Class<?> s: chosenSorts)
        {
            SortVisualization visualization = null;
            try {
                if (DATA_FORMAT == DATA_COLLECTION_TYPE.ARRAY){
                    visualization = new SortVisualization(
                            (ObservableSort) s.getConstructor(new Class[] { }).newInstance(),
                            (ObserverGraph) chosenGraph.getConstructor(new Class[] { }).newInstance()
                            , chosenData.clone()
                        );
                }
                else if (DATA_FORMAT == DATA_COLLECTION_TYPE.LIST){
                    List<Comparable<?>> dataAsList = Arrays.asList(chosenData);
                    visualization = new SortVisualization(
                            (ObservableSort) s.getConstructor(new Class[] { }).newInstance(),
                            (ObserverGraph) chosenGraph.getConstructor(new Class[] { }).newInstance()
                            , dataAsList
                        );
                }
                sorters.add(visualization.getSorter());
                appFrame.add(visualization.getGraph(WINDOW_WIDTH, WINDOW_HEIGHT));
                threads.add(new Thread(visualization, s.getSimpleName()));
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }

        setVisible(true);   
       
        for (Thread t: threads){
            t.setPriority(Thread.MAX_PRIORITY);
            t.start();
        }
       
        for (Thread t: threads){
            try {
                t.join();
            } catch (InterruptedException e) {
                completedSort = false;
                System.out.println(e.getMessage());
            }   
        }
       
        appFrame.dispose();
        displayResults(getResultsTable(chosenSorts));
    }

    /**
     * Returns a JTable
     * @param chosenSorts the chosen sorts by user
     */
    public JTable getResultsTable(ArrayList<Class> chosenSorts)
    {
        if (!completedSort)
            return null;
       
        // Now perform a quick insertion sort on the list
        // Sort by specified index
        for (int i = 1; i < sorters.size(); i++){
            ObservableSort<?> subject = sorters.get(i);
            for (int j = 0; j < i; j++)
            {
                ObservableSort<?> comparison = sorters.get(j);
                boolean toSwap = false;

                if (sortResultsBy == SORT_RESULTS_BY.COMPARISONS)
                    toSwap = subject.getComparisons() < comparison.getComparisons();
                else if (sortResultsBy == SORT_RESULTS_BY.SWAPS)
                    toSwap = subject.getSwaps() < comparison.getSwaps();
                else //sort by time
                    toSwap = subject.getElapsedTime() < comparison.getElapsedTime();
               
                if (toSwap){
                    sorters.set(i,comparison);
                    sorters.set(j,subject);
                    subject = comparison;
                }
            }
        }
       
        // Create results table values
        int i = 0;
        final String[] columnNames = {"Name", "Elapsed Time", "Swaps", "Comparisons"};
        final Object[][] data = new Object[sorters.size()][];
        for (ObservableSort s: sorters)
            data[i++] = new Object[] { s.getName(), s.getElapsedTime(), s.getSwaps(), s.getComparisons() };
       
        final JTable resultsTable = new JTable(data, columnNames); // keep handle so we can sort
       
        resultsTable.setPreferredScrollableViewportSize(new Dimension(450, 16 * sorters.size()));
        resultsTable.setFillsViewportHeight(true);
        resultsTable.setEnabled(false);
       
        resultsTable.getColumnModel().getColumn(0).setPreferredWidth(150);
        resultsTable.getColumnModel().getColumn(1).setPreferredWidth(100);
        resultsTable.getColumnModel().getColumn(2).setPreferredWidth(100);
        resultsTable.getColumnModel().getColumn(3).setPreferredWidth(100);
       
        return resultsTable;
    }
   
    /**
     * Displays the results of the sorting algorithms in a JFrame
     * This method was developed by Vuong Scott Tran
     */
    public void displayResults(JTable resultsTable)
    {       
        final Font titleFont = new Font("sansserif", Font.BOLD, 18);
           
        // Construct components
        final JFrame frame = new JFrame("Sorting Algorithm Results");
        final JMenuBar menuBar = new JMenuBar();
        final JMenu fileMenu = new JMenu("File");
        final JMenuItem exitItem = new JMenuItem("Exit");
        final JButton runAgain = new JButton();
       
        // Format components
        frame.setAlwaysOnTop(true);
        frame.setLayout(new BorderLayout());
        frame.setJMenuBar(menuBar);
       
        // Set text/labels
        runAgain.setText("Return to Menu");
       
        // Build components
        menuBar.add(fileMenu);
        fileMenu.add(exitItem);
        final JScrollPane results = new JScrollPane(resultsTable);
        results.setBorder(BorderFactory.createTitledBorder(null, "Results", 0, 0, titleFont));
        frame.add(results, BorderLayout.NORTH);
        frame.add(runAgain, BorderLayout.SOUTH);
       
        final JTableHeader header = resultsTable.getTableHeader();
        header.setReorderingAllowed(false);
        header.addMouseListener(new MouseAdapter()
        {
            public void mouseClicked(MouseEvent e)
            {
                int column = header.columnAtPoint(e.getPoint());
                if (column == 1)
                    sortResultsBy = SORT_RESULTS_BY.TIME;
                else if (column == 2)
                    sortResultsBy = SORT_RESULTS_BY.SWAPS;
                else if (column == 3)
                    sortResultsBy = SORT_RESULTS_BY.COMPARISONS;
               
                displayResults(getResultsTable(chosenSorts));
                frame.dispose();
            }
        });
   
        // Display
        frame.pack();
        frame.setLocationRelativeTo(null); 
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       
        // Set listeners
        exitItem.addActionListener(new
           ActionListener()
           {
              public void actionPerformed(ActionEvent event)
              {
                 System.exit(0);
              }
           });
      
        runAgain.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent arg0) {
                try {
                    ObservableSortDriver.RESET();
                    frame.dispose();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
   
    /**
     * Sets the size of the Comparable[] data array
     * @see DATA_SIZE
     * @param i
     */
    public static void setDataSize(int i){
        SIZE = i;
    }
   
    /**
     * Gets the size of the Comparable[] data array
     * @return @see DATA_SIZE
     */
    public static int getDataSize(){
        return SIZE;
    }

    public static int getDataCollectionType(){
        return DATA_FORMAT;
    }

    public static void setDataCollectionType(int format){
        DATA_FORMAT = format;
    }
   
    /**
     * Specifies constant values for data size.
     * @author Jason Campos
     */
    public static final class DATA_SIZE {
        /** Sort 25 items */
        public static final int SMALL = 25;
        /** Sort 50 items */
        public static final int MEDIUM = 50;
        /** Sort 100 items */
        public static final int LARGE = 100;
        /** Do not allow class instantiation */
        private DATA_SIZE(){
            throw new AssertionError("DATA_SIZE");
        }
    }
   
    /**
     * Specifies constant values for result sorting
     * @author Jason Campos
     */
    public static final class SORT_RESULTS_BY {
        /** Sort by fastest completion time */
        public static final int TIME = 0;
        /** Sort by least number of swaps */
        public static final int SWAPS = 1;
        /** Sort by least number of comparisons */
        public static final int COMPARISONS = 2;
        /** Do not allow class instantiation */
        private SORT_RESULTS_BY(){
            throw new AssertionError("Cannot instantiate class SORT_RESULTS_BY");
        }
    }
   
    /** Specifies what type of data is being sorted */
    public static final class DATA_COLLECTION_TYPE {
        /** Sort an array */
        public static final int ARRAY = 0;
        /** Sort a {@link java.util.List} */
        public static final int LIST = 1;
        /** Do not allow class instantiation */
        private DATA_COLLECTION_TYPE(){
            throw new AssertionError("Cannot instantiate class DATA_COLLECTION_TYPE");
        }
    }

    /**
     * Establishes the number of columns and rows to display based on the number of desired windows to display.
     * @param windows -- number of disired windows to display
     */
    private void initializeDimensions(int windows){
        System.out.println("Setting graph dimensions");
        // Adjust window size based on # of sorters
        // First just add a column. If there is still not enough room, add another row also
        while (windows > ROWS * COLUMNS){
            COLUMNS++;
            if (windows > ROWS * COLUMNS)
                ROWS++;
        }       
        WINDOW_WIDTH  = (int) SCREEN_WIDTH / COLUMNS;
        WINDOW_HEIGHT = (int) SCREEN_HEIGHT / ROWS;
        appFrame = new JFrame();
        appFrame.setSize((int) SCREEN_WIDTH, (int) SCREEN_HEIGHT);
        GridLayout l = new GridLayout(ROWS, COLUMNS);
        l.preferredLayoutSize(appFrame);
        l.setHgap(3);
        appFrame.setLayout(l);
        appFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    /**
     * Resets all static variables to their default state.
     */
    private static void RESET(){
        ObservableSortDriver.IS_READY = false;
        ObservableSortDriver.chosenData = null;
        ObservableSortDriver.chosenGraph = null;
        ObservableSortDriver.chosenSorts = new ArrayList<Class>();
        COLUMNS = 1;
        ROWS = 1;
    }

    private JFrame appFrame;
    private ArrayList<Thread> threads;
    private ArrayList<ObservableSort<?>> sorters;
    private boolean completedSort = true;
   
    private static int COLUMNS = 1;
    private static int ROWS = 1;
    private static int WINDOW_WIDTH;
    private static int WINDOW_HEIGHT;
    private static int SIZE = DATA_SIZE.MEDIUM;
    private static int sortResultsBy = SORT_RESULTS_BY.TIME;
    private static int DATA_FORMAT = DATA_COLLECTION_TYPE.ARRAY;
    private static final double SCREEN_WIDTH = Toolkit.getDefaultToolkit().getScreenSize().getWidth();
    private static final double SCREEN_HEIGHT = Toolkit.getDefaultToolkit().getScreenSize().getHeight();
}


Needless to say, there is quite a bit more to it, but I will get around to posting that soon!