import java.util.*;

public class Vex {

    Vector dice;
    Random random = new Random();

    public Vex( int numdice ) {
	dice = new Vector();
	for ( int i=0; i<numdice; i++ ) {
	    dice.addElement( new Dice( random ));
	}
    } // end of Vex() constructor


    public static void main( String[] args ) {
	String tmp;
	int    numdice;
	if ( args.length < 1 ) {
	    System.out.println( "usage: java Vex <numdice>" );
	    System.exit( 1 );
	}
	numdice = Integer.parseInt( args[0].trim() );
	Vex vex = new Vex( numdice );

	System.out.println();
	vex.permute();
	vex.print( "before blortSort:" );
	vex.blortSort();
	vex.print( ">after blortSort:" );

	System.out.println();
	vex.permute();
	vex.print( "before selectionSort1:" );
	vex.selectionSort1();
	vex.print( ">after selectionSort1:" );

	System.out.println();
	vex.permute();
	vex.print( "before selectionSort2:" );
	vex.selectionSort2();
	vex.print( ">after selectionSort2:" );

	System.out.println();
	vex.permute();
	vex.print( "before insertionSort1:" );
	vex.insertionSort1();
	vex.print( ">after insertionSort1:" );

	System.out.println();
	vex.permute();
	vex.print( "before insertionSort2:" );
	vex.insertionSort2();
	vex.print( ">after insertionSort2:" );

	System.out.println();
	vex.permute();
	vex.print( "before bubbleSort:" );
	vex.bubbleSort();
	vex.print( ">after bubbleSort:" );

	System.exit( 0 );

    } // end of main() method


    public void print( String s ) {
	System.out.print( s+" -->  " );
	for ( int i=0; i<dice.size(); i++ ) {
	    System.out.print( ((Dice)dice.elementAt( i )).toString()+" " );
	}
	System.out.println();
    } // end of print() method


    public void swap( int x1, int x2 ) {
	Dice b1 = (Dice)dice.elementAt( x1 );
	Dice b2 = (Dice)dice.elementAt( x2 );
	Dice tmp = new Dice( b1 );
	b1.copy( b2 );
	b2.copy( tmp );
    } // end of swap() method


    boolean isSorted() {
	int i = 0;
	boolean anyErrors = false;
	while (( ! anyErrors ) && ( i < dice.size()-1 )) {
	    if ( ((Dice)dice.elementAt(i)).getValue() > 
		 ((Dice)dice.elementAt(i+1)).getValue() ) {
		anyErrors = true;
	    }
	    else {
		i++;
	    }
	} /* end while */
	return( ! anyErrors );
    } /* end of isSorted() */
    

    void permute() {
	int i, r;
	for ( i=0; i<dice.size()-1; i++ ) {
	    r = Math.abs(random.nextInt()) % (dice.size()-i) + i;
	    swap( i,r );
	} /* end for i */
    } /* end of permute() */


    public int findMin( int startIndex ) {
	Dice d = (Dice)dice.elementAt( startIndex );
	int min = d.getValue();
	int minx = startIndex;
	for ( int i=startIndex+1; i<dice.size(); i++ ) {
	    d = (Dice)dice.elementAt( i );
	    if ( d.getValue() < min ) {
		min = d.getValue();
		minx = i;
	    }
	}
	return( minx );
    } // end of findMin() method


    void blortSort() {
	int count=0;
	while ( ! isSorted()) {
	    permute();
	    print( "after pass#"+count );
	    count++;
	} /* end of while */
    } /* end of blortSort() */


    public void insertionSort1() {
	Vector aux = new Vector();
	Dice tmp;
	for ( int i=0; i<dice.size(); i++ ) {
	    int j = 0;
	    while (( j < aux.size() ) && 
		   ((Dice)dice.elementAt( i )).getValue() >
		   ((Dice)aux.elementAt( j )).getValue() ) {
		j++;
	    } // end while
	    tmp = new Dice( (Dice)dice.elementAt( i ));
	    aux.addElement( tmp );
	    for ( int k=aux.size()-1; k>j; k-- ) {
		Dice d1 = (Dice)aux.elementAt( k-1 );
		Dice d2 = (Dice)aux.elementAt( k );
		d2.copy( d1 );
	    } // end for k
	    tmp = (Dice)aux.elementAt( j );
	    tmp.copy( (Dice)dice.elementAt( i ));
	    System.out.print( "after pass #" + i + ": ");
	    for ( int k=0; k<aux.size(); k++ ) {
		System.out.print(
			 ((Dice)aux.elementAt( k )).toString()+" " );
	    }
	    System.out.println();
	} // end for j
	dice.removeAllElements();
	for ( int i=0; i<aux.size(); i++ ) {
	    dice.addElement( (Dice)aux.elementAt( i ) );
	} // end for i
    } // end of insertionSort1() method


    public void insertionSort2() {
	Dice key, b1, b2;
	for ( int i=1; i<dice.size(); i++ ) {
	    key = new Dice( (Dice)dice.elementAt( i ));
	    int pos = i;
	    while ((pos > 0) &&
		   (((Dice)dice.elementAt(pos-1)).getValue() >
		    key.getValue())) {
		dice.setElementAt( (Dice)dice.elementAt(pos-1),
				   pos );
		pos--;
	    } // end while
	    dice.setElementAt( key,pos );
	    print( "after pass#"+i );
	} // end for
    } // end of insertionSort2() method


    public void selectionSort1() {
	Vector aux = new Vector();
	Dice tmp;
	while ( dice.size() > 0 ) {
	    int minx = findMin( 0 );
	    aux.addElement( (Dice)dice.elementAt( minx ));
	    dice.removeElementAt( minx );
	    System.out.print( "after pass #" + aux.size() + " ");
	    for ( int k=0; k<aux.size(); k++ ) {
		System.out.print(
			 ((Dice)aux.elementAt( k )).toString()+" " );
	    }
	    System.out.println();
	} // end for nsorted
	for ( int i=0; i<aux.size(); i++ ) {
	    dice.addElement( (Dice)aux.elementAt( i ) );
	} // end for i
    } // end of selectionSort1() method

    public void selectionSort2() {
	for ( int nsorted=0; nsorted<dice.size(); nsorted++ ) {
	    int minx = findMin( nsorted );
	    swap( nsorted,minx );
	    print( "after pass #"+nsorted );
	} // end for nsorted
    } // end of selectionSort2() method


    public void bubbleSort() {
	for ( int pass=1; pass<=dice.size()-1; pass++ ) {
	    for ( int i=0; i<=dice.size()-2; i++ ) {
		Dice di = (Dice)dice.elementAt( i );
		Dice di1 = (Dice)dice.elementAt( i+1 );
		if ( di.getValue() > di1.getValue() ) {
		    swap( i,i+1 );
		}
	    } // end for i
	    print( "after pass#"+pass );
	} // end for pass
    } // end of bubbleSort() method


} // end of class Vex
