// 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 Tally 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;
	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
	
	double p = 0.5; // probability of success
	double q = 0.5; // probability of failure
	double E; // Expectation
	double sd; // standard deviation
	
	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("ruin");	
		if ( s != null )
			ruin = s.equals("true");
		else
			ruin = false;
			
		s = getParameter("average");	
		if ( s != null )
			average = s.equals("true");
		else
			average = false;
			
		s = getParameter("ky");	
		if ( s != null )
			ky = Double.valueOf( s ).doubleValue();
			
		s = getParameter("p");	
		if ( s != null ) {
			p = Double.valueOf( s ).doubleValue();
			q = 1 - p;
		}
			
		s = getParameter("xTick");	
		if ( s != null )
			xTick = Integer.parseInt( s );
			
		s = getParameter("yTick");	
		if ( s != null )
			yTick = Integer.parseInt( s );
			
		E = nSteps*(p-q);
		sd = Math.sqrt( nSteps*(1-p+q) ); 
			
		kx = (thisWidth - 2.0*hMargin)/nSteps;
							
		x = 0; y = stake; yy = (double) y;
		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();
		
		
		offscreenG.drawLine( sx(0), sy(0), sx(nSteps), sy(0) );  // x axis
		offscreenG.drawLine( sx(0), thisHeight - vMargin, sx(0), vMargin );  // y axis
		offscreenG.drawLine( sx(nSteps), thisHeight - vMargin, sx(nSteps), vMargin );  // copy of y axis on right
		
		
		// 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) );
			
			offscreenG.drawLine( sx(nSteps - 2/kx), sy(yy), sx(nSteps + 2/kx), sy(yy) );
			offscreenG.drawLine( sx(nSteps - 2/kx), sy(-yy), sx(nSteps + 2/kx), sy(-yy) );
		}
		
		int stringX = hMargin + 40;
		int stringY = thisHeight - 30;
		offscreenG.drawString("p = "+p+", x scale = "+xTick+ ", y scale = "+yTick+"      E = "+E+", sd = "+sd, stringX, stringY + 15 );
		
		while( true ) {
		
			trial++;					
			
			x0 = x;
			y0 = y;
			yy0 = yy;
			
			x++; 
	    	if (( R.nextDouble() - q ) > 0)
	    		y++;
	    	else
	    		y--;		
	    	yy = ( (double) y)/trial;
	    				
			offscreenG.setColor( lineColor );
			if ( average == false )
				offscreenG.drawLine( sx( x0 ), sy( y0 ), sx( x ), sy( y )  );
			else
				offscreenG.drawLine( sx( x0 ), sy( yy0 ), sx( x ), sy( yy )  );
				
			offscreenG.setColor( Color.white);
			offscreenG.fillRect(stringX-2, stringY-20, 260, 22 );
			
			offscreenG.setColor( Color.black);
			offscreenG.drawString("N = "+trial+", Lead = "+y, stringX, stringY );
			
	   		repaint();
	   		
	   		if ( trial == nSteps ) {
	    		running = false;
	    		runner.suspend();
	    		x = 0;
	    		y = 0;
	    		trial = 0;
	    		changeColors();	    		
	    	}
	    	
			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) {	
			if ( mx < hMargin + 1 ) {
				x = 0; y = stake; trial = 0;
				changeColors();
			}
			else {
				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);
		
	}
	
	
}
	