// Author: Jim Carlson (copyright) 1996
// Date: June 17, 1996
// Web: http://www.math.utah.edu
// E-mail: carlson@math.utah.edu



import java.applet.*;
import java.awt.*;
import java.util.Random;

public class Diffusion extends Applet implements Runnable {

	int thisHeight, thisWidth;
	
	Thread runner;
	boolean running;
	int delay;
	boolean ruin = true;
	boolean average = false;
	
	Image offscreenImg;
	Graphics offscreenG;
	Color lineColor = Color.red;
	
	
	int trial, nSteps, stake;
	int x0, y0, x, y, T;
	// double yy, yy0;
	int hMargin = 20; int vMargin = 20;  // margins around drawing area
	double kx = 5;    double ky = 5;    // scale for drawing
	int xTick = 10;   int yTick = 10;    // scae for tick marks on axes
	int dotSize;
	
	double p1, p2, q; 
	Color c1, c2;
	
	public void init() {
	
		thisHeight = this.size().height; thisWidth = this.size().width;
		offscreenImg = createImage( thisWidth, thisHeight );
		offscreenG = offscreenImg.getGraphics();
		
		String s = getParameter("delay");
		if ( s != null )
			delay = Integer.parseInt( s );
		else
			delay = 100;
		
		s = getParameter("nSteps");	
		if ( s != null )
			nSteps = Integer.parseInt( s );
		else
			nSteps = 60;
			
		s = getParameter("stake");	
		if ( s != null )
			stake = Integer.parseInt( s );
		else
			stake = 0;
			
		s = getParameter("T");	
		if ( s != null )
			T = Integer.parseInt( s );
		else
			T = 0;
			
		s = getParameter("dotSize");	
		if ( s != null )
			dotSize = Integer.parseInt( s );
		else
			dotSize = 2;
			
		s = getParameter("ky");	
		if ( s != null )
			ky = Double.valueOf( s ).doubleValue();
			
		s = getParameter("p1");	
		if ( s != null )
			p1 = Double.valueOf( s ).doubleValue();
		else
			p1 = 0.8;
			
		s = getParameter("c1");	
		if ( s == null )
			c1 = Color.black;
		else if ( s == "red" )
			c1 = Color.red;
		else if ( s == "blue" )
			c1 = Color.blue;
		else if ( s == "green" )
			c1 = Color.green;
		else
			c1 = Color.black;
			
		s = getParameter("p2");	
		if ( s != null )
			p2 = Double.valueOf( s ).doubleValue();
		else
			p2 = 0.99;	
			
		s = getParameter("c2");	
		if ( s == null )
			c2 = Color.black;
		else if ( s == "red" )
			c2 = Color.red;
		else if ( s == "blue" )
			c2 = Color.blue;
		else if ( s == "green" )
			c2 = Color.green;
		else
			c2 = Color.black;
			
		s = getParameter("xTick");	
		if ( s != null )
			xTick = Integer.parseInt( s );
			
		s = getParameter("yTick");	
		if ( s != null )
			yTick = Integer.parseInt( s );
			
		kx = (thisWidth - 2.0*hMargin)/nSteps;
							
		x = stake;
		trial = 0;
				
		offscreenG.setColor( Color.white );
		offscreenG.fillRect( 0, 0, thisWidth, thisHeight );
		offscreenG.setColor( Color.black );
			
	}
	
	public void start() {
		
		if ( runner == null ) {
			runner = new Thread(this);
			running = true;
			runner.start();
		}
	}
	
	public void stop() {
	
		if ( runner != null ) {
			runner.stop();
			runner = null;
		}
		
	}
	
	
	public void run() {
	
		Random R = new Random();
		
		int stringX = hMargin + 40;
		int stringY = thisHeight - 30;
		
		offscreenG.drawLine( sx(0), sy(0), sx(nSteps), sy(0) );  // x axis
		offscreenG.drawLine( sx(0), thisHeight - vMargin, sx(0), vMargin );  // y axis
		offscreenG.drawString("p1 = "+p1+", p2 = "+p2+", T = "+T+", scale = "+xTick, stringX, stringY + 15 );
		
		
		// Draw tickmarks on x-axis
		for (int i = 1; i < nSteps/xTick; i++ ) {
			int xx = xTick*i;
			offscreenG.drawLine( sx(xx), sy(-2/ky), sx(xx), sy(2/ky) );
		}
		
		// Draw tickmarks on y-axis
		for (int i = 1; i < (thisHeight/2 - vMargin)/yTick - 1; i++ ) {
			int yy = yTick*i;
			offscreenG.drawLine( sx(-2/kx), sy(yy), sx(2/kx), sy(yy) );
			offscreenG.drawLine( sx(-2/kx), sy(-yy), sx(2/kx), sy(-yy) );
		}
		
		
		int i = 0;  // loop counter
		Color dotColor = Color.black;
		
		while( true ) {				
						
			if ( i == 0 ) {
				y =  (int)(stake*(2*R.nextDouble() - 1));
				x = 0;
				if ( (R.nextDouble() - 0.5) > 0 ) {
					q = 1 - p1;
					dotColor = c1;
				}
				else {
					q = 1 - p2;
					dotColor = c2;
				}
			}
				
				
			i++;	
	    	if (( R.nextDouble() - q ) > 0)
	    		x++;
	    	else
	    		x--;
	    	if ( x < 0 )
	    		x = 0;
		    
		    	
		    if ( i == T )	{
		    	offscreenG.setColor( dotColor );			
				offscreenG.fillRect( sx( x ), sy( y ), dotSize, dotSize  );
				i = 0;
				trial++;
						
				offscreenG.setColor( Color.white);
				offscreenG.fillRect(stringX-2, stringY-20, 260, 20 );
				offscreenG.setColor( Color.black);
				offscreenG.drawString("m = "+trial, stringX, stringY );
				
		   		repaint();
	   		
	   	}
	    	
			try { Thread.sleep( delay ); }
			catch ( InterruptedException e ) { }
		
		}
	}
	
	public void update( Graphics g ) {
		paint (g);
	}
	
	public void paint( Graphics g ) {
		
		g.drawImage( offscreenImg, 0, 0, this );
		
	}
	
	int changeColor( int c, int dc ) {
	
		c = c + dc;
		c = c%256;
		if ( c < 0 )
			c += 256;
		return c;
	}
	
	void changeColors() {
	
		int dColor = 60;
		int red = lineColor.getRed();
		red = changeColor( red, -dColor );
		int blue = lineColor.getBlue();
		blue = changeColor( blue, dColor );
		int green = lineColor.getGreen();
		lineColor = new Color( red , green, blue );
	}
	
	
	public boolean mouseDown( Event evt, int mx, int my ) {
	
		if (running) {	
			running = false;
			runner.suspend();
		}
		else {
			running = true;
			runner.resume();
		}
		return true;
		
	}
	
	int sx( double x ) {
	
		return (int) (kx*x + hMargin);
		
	}
	
	int sy( double y ) {
	
		
		return (int) (-ky*y + thisHeight/2);
		
	}
	
	
}
	