/*
	Module: 	AnimApplet.java
	Author: 	F. Michael O'Brien (michael@obrienm.com)
	Version:	0.10.5
	Date:		05 Oct 2000
	Documents:	_projv[nnn].doc
	Notes:		
				written for the Sun JDK 1.2.2
	History:
	28 Sep 2000	- Project started
	01 Oct 2000 - subclass RouterAnimApplet	from AnimApplet
	05 OCt 2000 - fixed adjacency fitness calculation

*/

import java.applet.Applet;
import java.awt.*;
import java.util.StringTokenizer;
import java.lang.Exception;
import java.awt.event.*;
import java.util.BitSet;
import java.io.*;

//----------------------------------------------------------------
// Implements:		Circuit, Board
// Inherits:		AnimApplet
// Implementors:	-
//----------------------------------------------------------------
public class RouterAnimApplet extends AnimApplet { //implements MouseListener, MouseMotionListener, ActionListener {
   	private int	ivGridCounter=0;
	private static int izGridHeight,
				izGridWidth;
//				ivFirstTime=0,
//				ivGridGreen2=0;
	private int ivBestFitness=0;
	private int izMaxAdjacency;	// max fitness attainable, for statistics
	private int ivBestGeneration=0;
	private int izDeviceNodes=0;

/*	private int			izMaxWidth,
						izMaxHeight;
*/

	// constants
	// fitness criteria
	private int		izFitnessCriteriaLowerUnconnected=1;
	private int		izFitnessCriteriaLowerConnected=4;
	private int		izFitnessCriteriaUpperUnconnected=1;
	private int		izFitnessCriteriaUpperConnected=4;
	private int		izFitnessCriteriaBothUnconnected=4;
	private int		izFitnessCriteriaBothConnected=16;

	private long lvGeneration=0;
	private int ivIndividual=0;
	protected int ivFrameFlipCount=10;

	private int izSpacing,izSpacing2,izSpacing3,izSpacing6;
	private Color color_top, color_bottom, color_both, color_none;
	private Color color_connect1, color_connect2, color_connect3;
	private Color color_connect3_lower, color_connect3_upper, color_connect3_both, color_device;

	private static short	ndir[]={9,8,11,10,5,4,7,6};
	private static short	xdir[]={1,0,-1,0};
	private static short	ydir[]={0,-1,0,1};

	// cell state
	private int ivBoard[][];
	private int ivBoardGenome[][][];
	private int ivBoardGenomeParents[][][];
	private static int izMaxGeneration;
	private static int izReplacementRatio;
	private static int izMutationMultiplier;
	private int ivAdjacencyCount[];
	private int ivTopIndividuals[];
	private int	ivTopIndividualsFitness[];
	private int izCrossoverCount;

	// adjacency fitness
	private int deviceNodeX[],deviceNodeY[];
	private int adjacencyMatrix[][];
	private int deviceNodeCount;

	//
	private boolean bvPerformCrossover=false;
	private boolean bvInitializeIndividuals=true;
	private boolean bvSwitchOverNow=false;

	// for statistics
	private	long	lvFitnessTotal=0;
	private int		ivFitnessAverage=0;

	// for file output
	//private	byte fileBuffer[] = new byte[80];
	private DataOutputStream outFile;  
	// target nodes
	//private short

	// trace path vectors


	// connection adjacency matrix



	private int connectedAbove, connectedBelow;

	// private custom objects

	// popup menu
//	private String svPopupNames[] = {"Erase","Reset","Randomize"};
//	private MenuItem thePopupMenuItems[];
//	private	PopupMenu aPopupMenu;


//	private OctTree getOctTreeFor(int x, int y) {
		
//	}




   	// load the images when the applet begins executing
   	public void init()
   	{
		izSleepTime=0;    // milliseconds to sleep
		// set colors
		color_top = new Color(0,255,64);				
		color_bottom = new Color(0,64,255);
		color_both = new Color(255,0,0);
		color_none = Color.darkGray;
		color_device = new Color(160,160,160);
		color_connect1 = new Color(128,128,255);
		color_connect2 = new Color(128,255,128);
		//color_connect3 = new Color(255,128,128);
		color_connect3_lower = new Color(255,0,255);
		color_connect3_upper = new Color(255,255,0);
		color_connect3_both = new Color(255,255,255);
		super.init();

		// applet listen for mouse events, ok
//		addMouseListener(this);
//		addMouseMotionListener(this);
		
		if(bvApplet) {
			izGridHeight=Integer.parseInt(getParameter("gridSize"));
			izMaxGeneration=Integer.parseInt(getParameter("population"));	
			izMutationMultiplier=Integer.parseInt(getParameter("mutationMult"));
			izReplacementRatio=Integer.parseInt(getParameter("replacementPercent"));
/*			System.out.println(getParameter("gridSize"));
			System.out.println(getParameter("population"));
			System.out.println(getParameter("mutationMult"));
			System.out.println(getParameter("replacementPercent"));
*/
		} else {
			//izGridHeight=10;
		}
					
		izGridWidth=izGridHeight;
		izMaxAdjacency=(izGridHeight*izGridWidth-izDeviceNodes-(izGridHeight*2)-((izGridWidth-2)*2))*4*16;
		System.out.println("i" + (new Integer(izMaxAdjacency)).toString());

		izSpacing=(int)(izMaxHeight-60)/izGridHeight;
		izSpacing2=(int)(izMaxHeight-60)/izGridHeight/2;
		izSpacing3=(int)(izMaxHeight-60)/izGridHeight/3;
		izSpacing6=(int)(izMaxHeight-60)/izGridHeight/12;

		// initialize board grid
		izCrossoverCount=(int)(izMaxGeneration*izReplacementRatio/100);
		//ivBoard = new BitSet(izGridHeight*izGridWidth*2);
		ivBoard = new int[izGridWidth][izGridHeight];
   		ivBoardGenome = new int[izGridWidth][izGridHeight][izMaxGeneration];
   		ivBoardGenomeParents = new int[izGridWidth][izGridHeight][izCrossoverCount];
		ivAdjacencyCount = new int[izMaxGeneration];
		ivTopIndividualsFitness = new int[(int)(izMaxGeneration*izReplacementRatio/100)];

		ivTopIndividuals = new int[(int)(izMaxGeneration*izReplacementRatio/100)];

		deviceNodeX = new int[10];
		deviceNodeY = new int[10];
		deviceNodeCount=2;
		deviceNodeX[0]=1;
		deviceNodeY[0]=1;
		deviceNodeX[1]=1;
		deviceNodeY[1]=izGridHeight-2;
		adjacencyMatrix = new int[izGridWidth][izGridHeight];
		

		// initialize arrays
		for(int i=0;i<izMaxGeneration;i++) {
			ivAdjacencyCount[i]=0;
		}


		// create popup menu
//		aPopupMenu = new PopupMenu("Popup");
//		thePopupMenuItems = new MenuItem[svPopupNames.length];

//		for(int i=0;i<svPopupNames.length;i++)
//		{
//			thePopupMenuItems[i] = new MenuItem(svPopupNames[i]);
//			aPopupMenu.add(thePopupMenuItems[i]);
//			thePopupMenuItems[i].addActionListener(this);
//		}

		// add popup menu to this canvas
//		add(aPopupMenu);
//		enableEvents(AWTEvent.MOUSE_EVENT_MASK);

		// preset some values
		loadBoardExample1(0, 0);
		loadRandomPopulation();


		// write output header to disk for non-applets
		if(!bvApplet) {
			try {
				// create output stream
				outFile = new DataOutputStream(new FileOutputStream("out.txt",true));
				outFile.writeBytes("RouterAnimApplet:\r\n");
				outFile.writeBytes("Population: \t" + (new Integer(izMaxGeneration)).toString() + "\r\n");
				outFile.writeBytes("Crossover: \t" + (new Integer((int)(izReplacementRatio))).toString() + " Percent\r\n");
				outFile.writeBytes("izGridHeight: \t" + (new Integer(izGridHeight)).toString() + "\r\n");
				outFile.writeBytes("izGridWidth: \t" + (new Integer(izGridWidth)).toString() + "\r\n");
				outFile.writeBytes("izMutationMultiplier: \t" + (new Integer(izMutationMultiplier)).toString() + "\r\n");
				//outFile.writeBytes("izGridWidth: \t" + (new Integer(izGridWidth)).toString() + "\r\n");

				outFile.writeBytes("gen\tfit\tafit\r\n");
				outFile.close();
			} catch (Exception e) {
				String err = e.toString();
				System.out.println(err);
			}
		System.out.println("F.Michael O'Brien: RouterAnimApplet.java");
		System.out.println("must alt-tab out and back in to step past");
		System.out.println("sun.awt.windows.WGraphics.drawImage(WGraphics.java:360) bug");
		System.out.println("when using double-buffering");

		}  
	}

   	// start the applet
   	public void start() {
		super.start();
   	}

	public void stop() {
		super.stop();
	}

   	// display the image in the Applet's Graphics context
   	public void paint(Graphics g) {
		int xd,yd;
		int tempx, tempy;
		int ivDirx, ivDiry;
		String stringRep;	// string binary rep of grid cell 0-1024	
		boolean connected;
		int cellColor;
		int ivMaxConnections=0;
		int lastIndex;
		int p1,p2;
		int tempBitPos;
		BitSet aBitSet;
									// 0-11 10du swne swne
									//      0123 4567 8901
									//    p 1098 7654 3210
									//                6745

		super.paint(g);

		// initialize arrays?
		if(bvInitializeIndividuals==true) {
			loadRandomPopulation();
			// copy population to storage
			copyGenerationTo(ivIndividual);			
		}

		ivAdjacencyCount[ivIndividual]=0;

		// display current solution
		for(int i=0;i<izGridWidth;i++) {
			//System.out.println(i);
			for(int j=0;j<izGridHeight;j++) {
				stringRep = Integer.toBinaryString(2048+ivBoardGenome[i][j][ivIndividual]);
				// get lower layer config
				//System.out.println("\n" + stringRep);
				for(int p=0;p<4;p++) {
					connected=false;
					connectedBelow=0; connectedAbove=0;
					cellColor=0;
					//ivDirx=(int)Math.cos(Math.PI/2*p);
					//ivDiry=-(int)Math.sin(Math.PI/2*p);
					//System.out.println("\n" + stringRep.substring(11-p,11-p+1));
					if((new Integer(stringRep.substring(11-p,11-p+1))).intValue()>0) {
						connectedBelow++;
						// adjust fitness parameters
						//ivAdjacencyCount[ivIndividual]+=izFitnessCriteriaLowerUnconnected;
						if((new Integer(stringRep.substring(11-p-4,11-p-3))).intValue()>0) {
							connectedAbove++;
							//
							//	cell exists above and below
							//
							// adjust fitness parameters
							//ivAdjacencyCount[ivIndividual]+=izFitnessCriteriaBothUnconnected;

							// check if neighboor is connected
 							// short-circuit non-torodial topology
							if((i>0)&(j>0)&(i<izGridWidth-1)&(j<izGridHeight-1)) {
								//if((new Integer(Integer.toBinaryString(2048+ivBoard[i+ivDirx][j+ivDiry]
								//	).substring(11-(p+2-((int)Math.floor(p/2+.1)*2))-4,
								//	11-(p+2-((int)Math.floor(p/2+.1)*2))-3))).intValue()>0) {
								// connected across upper layer?
								// verify connection across same level
								if((new Integer(Integer.toBinaryString(2048+ivBoardGenome[i+xdir[p]][j+ydir[p]][ivIndividual]
									).substring(ndir[p],ndir[p]+1))).intValue()>0 ||
									(new Integer(Integer.toBinaryString(2048+ivBoardGenome[i+xdir[p]][j+ydir[p]][ivIndividual]
									).substring(2,3))).intValue()>0) { // verify connection across lower level as well
									// connected across lower layer
									if((new Integer(Integer.toBinaryString(2048+ivBoardGenome[i+xdir[p]][j+ydir[p]][ivIndividual]
										).substring(ndir[p+4],ndir[p+4]+1))).intValue()>0 ||
										(new Integer(Integer.toBinaryString(2048+ivBoardGenome[i+xdir[p]][j+ydir[p]][ivIndividual]
										).substring(2,3))).intValue()>0) {
										// connected across both layers
										gContext.setColor(color_connect3_both);
										cellColor=6;
										// adjust fitness parameters
										ivAdjacencyCount[ivIndividual]+=izFitnessCriteriaBothConnected;
										connected=true;
									} else {
										// connected across upper layers
										gContext.setColor(color_connect3_upper);
										cellColor=4;
										// adjust fitness parameters
										ivAdjacencyCount[ivIndividual]+=izFitnessCriteriaUpperConnected;
										connected=true;					  
									}
								} else {
									// connected across lower layer
									if((new Integer(Integer.toBinaryString(2048+ivBoardGenome[i+xdir[p]][j+ydir[p]][ivIndividual]
										).substring(ndir[p+4],ndir[p+4]+1))).intValue()>0 ||
										(new Integer(Integer.toBinaryString(2048+ivBoardGenome[i+xdir[p]][j+ydir[p]][ivIndividual]
										).substring(2,3))).intValue()>0) {
										// connected across both layers
										gContext.setColor(color_connect3_lower);
										cellColor=4;
										// adjust fitness parameters
										ivAdjacencyCount[ivIndividual]+=izFitnessCriteriaLowerConnected;
										connected=true;
									} else {
										// no connection on either layer
										gContext.setColor(color_both);
										cellColor=3;				   
										// adjust fitness parameters
										ivAdjacencyCount[ivIndividual]+=izFitnessCriteriaLowerUnconnected;
									}
								} // if((new
							} else {
								gContext.setColor(color_both);
								cellColor=3;
							} // if((i>0)
  						} else { // if((new  : below=true, above=false
							//
							//	cell exists only  below
							//

							// check if neighboor is connected
 							// short-circuit non-torodial topology
							if((i>0)&&(j>0)&&(i<izGridWidth-1)&&(j<izGridHeight-1)) {
								//if((new Integer(Integer.toBinaryString(2048+ivBoard[i+ivDirx][j+ivDiry]
								//	).substring(11-(p+2-((int)Math.floor(p/2+.1)*2))-4,
								//	11-(p+2-((int)Math.floor(p/2+.1)*2))-3))).intValue()>0) {
								if((new Integer(Integer.toBinaryString(2048+ivBoardGenome[i+xdir[p]][j+ydir[p]][ivIndividual]
									).substring(ndir[p],ndir[p]+1))).intValue()>0) {
									//
									//	cell exists only below,connection across below
									//

 								//if(p==2) {
									/*System.out.println("\np " + (new Integer(p)).toString());
									System.out.println("i" + (new Integer(i)).toString());
									System.out.println("j" + (new Integer(j)).toString());
									System.out.println("ivDirx " + (new Integer(ivDirx)).toString());
									System.out.println("ivDiry " + (new Integer(ivDiry)).toString());
									System.out.println("ndir[p] " + (new Integer(ndir[p])).toString());
									*///} 

									gContext.setColor(color_connect1);
									connected=true;
									cellColor=1;

									// adjust fitness parameters
									ivAdjacencyCount[ivIndividual]+=izFitnessCriteriaLowerConnected;
								} else { // above=false, below=false
									//
									//	cell exists only below,no connection
									//

									gContext.setColor(color_bottom);
									cellColor=1;
									// adjust fitness parameters
									ivAdjacencyCount[ivIndividual]+=izFitnessCriteriaLowerUnconnected;
								} // if((new
							} else { // cell is on the peripheral of grid
								gContext.setColor(color_bottom);
								cellColor=1;
							} // if((i>0)
  						} // if((new
					} else { // if((new : cellbelow=false
						//
						//	no cell exists only below,connection across below
						//

						if((new Integer(stringRep.substring(11-p-4,11-p-3))).intValue()>0) {
							connectedAbove++;

							// check if neighboor is connected
							// short-circuit non-torodial topology
							//if((new Integer(Integer.toBinaryString(2048+ivBoard[i+ivDirx][j+ivDiry]
							//	).substring(11-(p+2-((int)Math.floor(p/2+.1)*2))-4,
							//	11-(p+2-((int)Math.floor(p/2+.1)*2))-3))).intValue()>0) {
							if((i>0)&(j>0)&(i<izGridWidth-1)&(j<izGridHeight-1)) {
								if((new Integer(Integer.toBinaryString(2048+ivBoardGenome[i+xdir[p]][j+ydir[p]][ivIndividual]
									).substring(ndir[p+4],ndir[p+4]+1))).intValue()>0) {
									gContext.setColor(color_connect2);
									connected=true;
									cellColor=2;

									// adjust fitness parameters
									ivAdjacencyCount[ivIndividual]+=izFitnessCriteriaUpperConnected;

								} else {  
									gContext.setColor(color_top);
									cellColor=2;
									// adjust fitness parameters
									ivAdjacencyCount[ivIndividual]+=izFitnessCriteriaUpperUnconnected;
								} // if((new
							} else { // if((i>0)
								gContext.setColor(color_top);
								cellColor=2;
							} // if((i>0)
  						} else {
							gContext.setColor(Color.black);
							cellColor=0;																								
	 					} // if((new	
					} //if((new

					if(connected) {
						gContext.fillRect(
							10+i*izSpacing+izSpacing2+xdir[p]*(izSpacing3),
							10+j*izSpacing+izSpacing2+ydir[p]*(izSpacing3),
							izSpacing3,izSpacing3);	
					} else { // if(connected) {
						if(cellColor>0) {
							gContext.drawRect(
								10+i*izSpacing+izSpacing2+xdir[p]*(izSpacing3),
								10+j*izSpacing+izSpacing2+ydir[p]*(izSpacing3),
								izSpacing3,izSpacing3);	
						} else {
							//gContext.drawRect(
							//	10+i*izSpacing+izSpacing2+ivDirx*(izSpacing3),
							//	10+j*izSpacing+izSpacing2+ivDiry*(izSpacing3),
						   //		izSpacing3,izSpacing3);	
						} // if(cellColor>0) {
					} // if(connected) {

					//} // for p ?

					//System.out.println((new Integer(connectedBelow)).toString());				
					// set center post if filled
				   	if((new Integer(stringRep.substring(3,4))).intValue()>0) {
				   		gContext.setColor(color_device);
			   			gContext.fillRect(
			   				10+i*izSpacing+izSpacing2,
			   				10+j*izSpacing+izSpacing2,
				   			izSpacing3,izSpacing3);
				   	} else { // if((new
						if(connectedBelow>0) {
							if(connectedAbove>0) {
								gContext.setColor(color_both);
								cellColor=3;
							} else {
								gContext.setColor(color_bottom);
								cellColor=1;
							}
						} else {
							if(connectedAbove>0) {
								gContext.setColor(color_top);
								cellColor=2;
							} else {
								gContext.setColor(color_none);
								cellColor=0;
							} // if(connectedAbove>0) {
						} // if(connectedBelow>0) {

						if(cellColor>0) {
 							gContext.drawRect(
								10+i*izSpacing+izSpacing2,
								10+j*izSpacing+izSpacing2,
  								izSpacing3,izSpacing3);
						} else { // if(cellColor>0) {
							// check for device
							if(bvOddFrame) {
								if((new Integer(stringRep.substring(2,3))).intValue()>0) {
									gContext.setColor(Color.yellow);
	 								gContext.fillRect(
									  	10+i*izSpacing+izSpacing2,
										10+j*izSpacing+izSpacing2,
  										izSpacing3,izSpacing3);
								} // if((new
							} // if(bvOddFrame) {
						} //if(cellColor>0) {
					} // if((new
 			   	} // for p	
			} // for j
		} // for i

	gContext.setColor(Color.cyan);
	gContext.drawString("F: " + (new Integer(ivFrames)).toString(),10,izMaxHeight-16);
	gContext.drawString("I: " + (new Integer(ivIndividual)).toString(),80,izMaxHeight-16);
	gContext.drawString("G: " + (new Integer((int)lvGeneration)).toString(),120,izMaxHeight-16);
	gContext.drawString("A: " + (new Integer(ivAdjacencyCount[ivIndividual])).toString(),180,izMaxHeight-16);
	gContext.drawString("P: " + (new Integer((int)Math.floor(100*ivAdjacencyCount[ivIndividual]/izMaxAdjacency+.5))).toString(),240,izMaxHeight-16);

	// compute path fitness
	for(int node=0;node<deviceNodeCount;node+=2) {
		int n1x=deviceNodeX[node];
		int n1y=deviceNodeY[node];
		int n2x=deviceNodeX[node+1];
		int n2y=deviceNodeY[node+1];

		// check all 8 directions
/*		stringRep = Integer.toBinaryString(2048+ivBoardGenome[n1x][n1y][ivIndividual]);
		for(int p=0;p<4;p++) {
			connected=false;
			connectedBelow=0; connectedAbove=0;
			cellColor=0;
  			if((new Integer(stringRep.substring(11-p,11-p+1))).intValue()>0) {
  				connectedBelow++;
 				if((new Integer(stringRep.substring(11-p-4,11-p-3))).intValue()>0) {
					connectedAbove++;
				}
			}
		}
*/
		// get oct-tree for source node


		// get oct-tree for dest node


		// are any nodes within both oct-trees?


		// yes, path exists, determine if any other exclusive nodes are in oct-trees


		// no, no path yet, but compute dist between closest approach


	}


	// compute fitness
	lvFitnessTotal+=ivAdjacencyCount[ivIndividual];
	if(ivIndividual<izMaxGeneration-1)	{
		ivIndividual++;
	} else {
		ivIndividual=0;
		bvPerformCrossover=true;

		// turn off randomization for initial individuals
		bvInitializeIndividuals=false;

		// select top 10% of population for crossover
		// find maximum

		//System.out.println("\n");
		for(int j=0;j<izCrossoverCount;j++) {
			ivMaxConnections=0;
			lastIndex=0;
			for(int i=0;i<izMaxGeneration;i++) {
				if(ivMaxConnections<ivAdjacencyCount[i]) { 
					ivMaxConnections=ivAdjacencyCount[i];
					lastIndex=i;
					//System.out.println("i,j,ivmax,ivadj " +  (new Integer(i)).toString() + " " +
					//		(new Integer(j)).toString() + " " +
					//		(new Integer(ivMaxConnections)).toString() + " " + 
					//		(new Integer(ivAdjacencyCount[i])).toString() + " ");				  				
				} 			
			}
			ivTopIndividuals[j]=lastIndex;
			ivTopIndividualsFitness[j]=ivMaxConnections;
			ivAdjacencyCount[lastIndex]=0;

			// update best scores
			if(ivBestFitness<ivMaxConnections) {
				ivBestFitness=ivMaxConnections;
				ivBestGeneration=(int)lvGeneration;
				System.out.println("g,f,af,pf " +  (new Integer(ivBestGeneration)).toString() + " " +
					(new Integer(ivBestFitness)).toString() + " " + 
					(new Integer((int)(Math.floor(lvFitnessTotal/izMaxGeneration+.5)))).toString() + " " +
					(new Integer((int)(Math.floor(100*ivBestFitness/izMaxAdjacency+0.5)))).toString()
					);

				// output to disk for non-applets
				if(!bvApplet) {
					try {
						// create output stream
						outFile = new DataOutputStream(new FileOutputStream("out.txt",true));
						//FileOutputStream fileOut = new FileOutputStream("out.txt",true); // append
						// create a Writer to convert String's to byte[]'s
						//outFile.writeBytes((int)Byte.valueOf(aString.substring(z+1,z+2)));
						outFile.writeBytes(
							(new Integer(ivBestGeneration)).toString() + "\t" +
							(new Integer(ivBestFitness)).toString() + "\t" +
							(new Integer((int)Math.floor(100*ivBestFitness/izMaxAdjacency+0.5))).toString() + "\t" +
							(new Integer((int)(Math.floor(lvFitnessTotal/izMaxGeneration+.5)))).toString() + "\t" +
							"\r\n");
						outFile.close();
					} catch (Exception e) {
						String err = e.toString();
						System.out.println(err);
					}
				}
			}
		}

		// perform crossover
		lvGeneration++;
		if(bvPerformCrossover==true) {
			bvPerformCrossover=false;

		// copy parents
		// copy parents out of grid before copying to top of main grid 05 oct 1400
		for(int c=0;c<izCrossoverCount;c++) 
			for(int i=0;i<izGridWidth;i++)
				for(int j=0;j<izGridHeight;j++) 
					ivBoardGenomeParents[i][j][c]=ivBoardGenome[i][j][ivTopIndividuals[c]];

		// mate top x% to create other 100-x%

		// move parents to the top
		for(int c=0;c<izCrossoverCount;c++) 
			for(int i=0;i<izGridWidth;i++)
				for(int j=0;j<izGridHeight;j++)
					ivBoardGenome[i][j][c]=ivBoardGenomeParents[i][j][c];
					//ivBoardGenome[i][j][c]=ivBoardGenome[i][j][ivTopIndividuals[c]];
				
			for(int c=izCrossoverCount;c<izMaxGeneration;c++) {
				// get two random parents
				p1=(int)(Math.floor(Math.random()*izCrossoverCount));
				do { // no asexual reproduction thank you
					p2=(int)(Math.floor(Math.random()*izCrossoverCount)); // was *4 oct5 1330
				} while (p1==p2);

				//System.out.println("p1,p2 " +  (new Integer(p1)).toString() + " " +
				//	(new Integer(p2)).toString());
				bvSwitchOverNow=false;

				for(int i=0;i<izGridWidth;i++) {
					if(!bvSwitchOverNow)
						if((int)(Math.floor(Math.random()*100))==1)
							bvSwitchOverNow=true;  
					for(int j=0;j<izGridHeight;j++)
						//if(bvSwitchOverNow)	{
						if((int)(Math.floor(Math.random()*100))>50)	{
							ivBoardGenome[i][j][c]=ivBoardGenomeParents[i][j][p1];
						} else {
							//if(!bvSwitchOverNow)
							//	if((int)(Math.floor(Math.random()*100))==1) {
							//		bvSwitchOverNow=true;
								//System.out.println("i,j " +  (new Integer(i)).toString() + " " +
								//	(new Integer(j)).toString());													
							//	}
							ivBoardGenome[i][j][c]=ivBoardGenomeParents[i][j][p2];
						}
				}

				// perform mutations

				// modify grid
				int mutations=(int)(Math.floor(Math.random()*izMutationMultiplier));
				for(int i=0;i<mutations;i++) {				
					tempx = (int)(Math.floor(Math.random()*izGridWidth));
					tempy = (int)(Math.floor(Math.random()*izGridHeight));	
					if((int)(Math.floor(Math.random()*256))>128)
				 		if(ivBoardGenome[tempx][tempy][c]<512) {
							tempBitPos=(int)(Math.floor(Math.random()*9));
//							if((int)(Math.floor(Math.random()*256))>128) {
							ivBoardGenome[tempx][tempy][c]=(int)(Math.floor(Math.random()*512));
// 								|(1|2|4|8|16|32|64|128);
// 								&-(1|2|4|8|16|32|64|128);
/*
						System.out.println("\nMutate:");
						if(ivBoardGenome[tempx][tempy][c]< (2 << tempBitPos)) {
							ivBoardGenome[tempx][tempy][c]=ivBoardGenome[tempx][tempy][c]+(2 << tempBitPos);	
							System.out.println("-v,p1,p2,b " +  (new Integer(ivBoardGenome[tempx][tempy][c])).toString() + " " + (new Integer(c)).toString() + " " +
								(new Integer(p2)).toString() + " " + (new Integer((2 << tempBitPos))).toString());
						} else {
							ivBoardGenome[tempx][tempy][c]=ivBoardGenome[tempx][tempy][c]-(2 << tempBitPos);	
							System.out.println("+v,p1,p2,b " +  (new Integer(ivBoardGenome[tempx][tempy][c])).toString() + " " +  (new Integer(c)).toString() + " " +
								(new Integer(p2)).toString() + " " + (new Integer((2 << tempBitPos))).toString());

						}
//*/
					}
				}												 			
			}
			// re-initialize statistics
			lvFitnessTotal=0;
			ivFitnessAverage=0;	
		} else {

		}	
	}
	
	// 
//	for(int i=0;i<izCrossoverCount;i++) {
//		gContext.drawString(" " + (new Integer(ivTopIndividualsFitness[i])).toString(),240+30*i,izMaxHeight-16);
//	}

  	//try {Thread.sleep( izSleepTime );}
	//catch ( InterruptedException e ){showStatus(e.toString());}
	repaint();  // display buffered image
   	} // paint()

   	// override update to eliminate flicker
   	public void update(Graphics g){paint(g);}

	private void loadRandomPopulation() {
		//if((int)(Math.floor(Math.random()*512))>500) {
		//	for(int i=0;i<izGridWidth;i++)
		//		for(int j=0;j<izGridHeight;j++)
		//			if(ivBoard[i][j]<512)
		//				//ivBoard[i][j]=(int)(Math.floor(Math.random()*512));
		//				ivBoard[i][j]=511;//i*izGridHeight+j;
		//} else {
			for(int i=0;i<izGridWidth;i++)
				for(int j=0;j<izGridHeight;j++)
					if(ivBoard[i][j]<512)
						ivBoard[i][j]=(int)(Math.floor(Math.random()*512));
		//}
	}

	private void copyGenerationTo(int gen) {
		for(int i=0;i<izGridWidth;i++)
			for(int j=0;j<izGridHeight;j++)
					ivBoardGenome[i][j][gen]=ivBoard[i][j];
	}


	private void loadBoardExample1(int x, int y) {
		ivBoard[0+x][0+y]=512;
		ivBoard[1+x][0+y]=512;
		ivBoard[2+x][0+y]=512;
		ivBoard[3+x][0+y]=512;
 //		ivBoard[7+x][5+y]=512;
 //		ivBoard[7+x][6+y]=512;
 //		ivBoard[7+x][7+y]=512;

		ivBoard[izGridWidth-1][izGridHeight-3]=512;
		ivBoard[izGridWidth-2][izGridHeight-3]=512;
		ivBoard[izGridWidth-3][izGridHeight-3]=512;
		ivBoard[izGridWidth-3][izGridHeight-3]=512;
									// 0-11 00dm swne swne
									//      0123 4567 8901
									//    p           3210
									//                6745
									// p x y
									// 0 5,6 
									// 1 4,5
									// 2 5,6
									// 3 4,5
	
		//ivBoard[2+x][2+y]=
		izDeviceNodes+=3;
	}

	public String getAppletInfo() {
		super.getAppletInfo();
		return "Written by F.Michael O'Brien (michael_obrien@mitel.com)";
	}

	//static boolean bvApplet=true;
	// allow application use outside of browser, appletviewer
	public static void main(String args[]) {
		bvApplet=false;
/*		izMaxHeight=300;
		izMaxWidth=300;
		izGridHeight=10;
		izMutationMultiplier=20;
		izMaxGeneration=200;	
		izReplacementRatio=20;
*/
		// cl-parameters = Population MaxHeight MaxWidth GridHeight MutationMultiplier dzReplacementRatio
		// enumerate arguments passed from the console
		if(args.length > 5) {
			//for(int i=0;i<args.length;i++)
			//	if(args[i].equals("-debug")) 
					//bzDebug = true; // set global debug flag
			//	else { usage(); System.exit(0); }
			// get arguments
			izMaxGeneration=Integer.parseInt(args[0]);	
			izMaxHeight=Integer.parseInt(args[1]);
			izMaxWidth=Integer.parseInt(args[2]);
			izGridHeight=Integer.parseInt(args[3]);
			izMutationMultiplier=Integer.parseInt(args[4]);
			izReplacementRatio=Integer.parseInt(args[5]);



		} else {
			// set defaults
			//bzDebug = false;
			usage(); System.exit(0);
		}


		Frame aFrame = new Frame("Router:Genetic Algorithm-3 (c) F.Michael O'Brien V0.10.6");
		RouterAnimApplet anApplet=new RouterAnimApplet();
		aFrame.add("Center",anApplet);
		aFrame.setSize(izMaxWidth+10,izMaxHeight+30);
		aFrame.show();	
		// must alt-tab out and back in to step past 
		// sun.awt.windows.WGraphics.drawImage(WGraphics.java:360) bug
		// when using double-buffering
		anApplet.init();
		anApplet.start();
    }

	/** print the expected parameters to the console */
	public static void usage() {
		/** 
		-debug : turn console debugging output on, default=off
		 : select grid size
		*/
				
		System.out.println("\nCommand-Line Options are...\njava RouterAnimApplet " +
			"Population MaxHeight MaxWidth GridHeight MutationMultiplier ReplacementPercent" + 
			"[-debug]\n");
	}

 }


