// A revision of the GaltonBoard applet// Written by Julian Devlin, 8/97, for the text book// "Introduction to Probability," by Charles M. Grinstead & J. Laurie Snell// A few necessary packagesimport java.awt.*;import java.applet.Applet;import java.util.Random;// The GaltonBoard applet classpublic class GaltonBoard extends Applet {	Board myboard;							// Pins, slots, etc.						// UI elements	Panel contpanel;	Scrollbar pausebar, probbar, rowsbar;	Label pauselabel, problabel, rowslabel;	//Checkbox soundon;		// State variables	int screenwidth = 400;	int screenheight = 500;		// Initialization	public void init() {				//resize(screenwidth, screenheight);				// Make applet correct size		setBackground(new Color(255, 255, 255));		// Set color		myboard= new Board(this);							// Instantiate Board class		// Set up UI controls		contpanel = new Panel();		contpanel.setLayout(new GridLayout(6, 1, 5, 5));		contpanel.setBackground(new Color(255, 255, 255));				pausebar = new Scrollbar(Scrollbar.HORIZONTAL, 100, 20, 1, 2000);		probbar = new Scrollbar(Scrollbar.HORIZONTAL, 50, 20, 0, 100);		rowsbar = new Scrollbar(Scrollbar.HORIZONTAL, 10, 20, 1, 30);		pauselabel = new Label("Delay - " + String.valueOf(pausebar.getValue()) + " microseconds");		problabel = new Label("Chance of falling right - " + String.valueOf(probbar.getValue()) + "/100");		rowslabel = new Label("Rows of pins - " + String.valueOf(rowsbar.getValue()));		//soundon = new Checkbox("Sound", null, false);				setLayout( new BorderLayout(5,5));		add("South", contpanel);		add("Center", myboard);				contpanel.add(pausebar);		contpanel.add(pauselabel);				contpanel.add(probbar);		contpanel.add(problabel);		contpanel.add(rowsbar);		contpanel.add(rowslabel);		//contpanel.add(soundon);				myboard.pinrows = rowsbar.getValue();				validate();				//myboard.init();		myboard.start();		// Run board....	} 			// If it is run as an application, make a window with an applet in it	public static void main(String arg[]) {		Frame f = new Frame("My Window");		GaltonBoard myGalt = new GaltonBoard();		myGalt.init();		//myGalt.start();		f.setLayout(new GridLayout(1, 1));//		f.resize(myGalt.screenwidth, myGalt.screenheight);		f.add(myGalt);		f.show();	}	 public boolean handleEvent(Event evt)        {        		// If user is changing options            if(evt.target instanceof Scrollbar)            {                if (evt.target==pausebar) {                	myboard.pauselength = ((Scrollbar)evt.target).getValue();                	pauselabel.setText("Delay - "                 		+ String.valueOf(pausebar.getValue()) + " microseconds");                }           		if (evt.target==probbar) {           			myboard.leftprob = (float) ((Scrollbar)evt.target).getValue()/100;						problabel.setText("Chance of falling right - " 							+ String.valueOf(probbar.getValue()) + "/100");           		}           		if (evt.target==rowsbar) {           			myboard.pinrows = ((Scrollbar)evt.target).getValue();           			rowslabel.setText("Rows of pins - "            				+ String.valueOf(rowsbar.getValue()));           		}                return true;            }				// Otherwise, handle as usual            return super.handleEvent(evt);         }}// Board class - does all the workclass Board extends Canvas implements Runnable{	// Constants	final int NUMBALLS = 100;	final int PINSIZE = 4;	final int BALLSIZE = 8;	final int SIDE = 20;	final int HEIGHT = (int) Math.round((Math.sqrt(3)/2)*SIDE);	final int DROPCOORD = 20;	final int CUTCOORD = 20;		// Variables	int pinrows;		int maxy;	int barwidth;	int firstcol;		int curball = 0;	int xpos;	int ypos;	int oldx, oldy;	int slotno;	int pauselength = 100;		float leftprob = (float) .5;		int flatball;		//jd- 30 is actuall max pin num		int slotballs[] = new int[31];		int oldclipx, oldclipy;	Rectangle cliparea;		int screenwidth = size().width;				// DUPLICATE	int screenheight = size().height;		Thread runner;	Random randGen = new Random();	//AudioClip myclip;	boolean isrunning;	boolean painted;	GaltonBoard mydad;			public Board(GaltonBoard parent) {		mydad = parent;	}		public void doinit()	{		//for (int k=0; k<slotballs.length; k++) {		//	slotballs[k]=0;		//	}		//System.out.println(String.valueOf(size().width) + " " + String.valueOf(size().height));		//System.out.println(String.valueOf(mydad.soundon.getState()));		screenwidth = size().width;				// DUPLICATE		screenheight = size().height;						maxy=DROPCOORD+(HEIGHT*pinrows)+1;		firstcol=screenwidth/2-((pinrows)*(SIDE/2))-(BALLSIZE/2);		barwidth=SIDE-BALLSIZE-4;		//pauselength = 100;		//leftprob=(float) .5;		//myclip = getAudioClip(getCodeBase(), "collide.au");		//cliparea=new Rectangle(0, 0, screenwidth, screenheight);		//this.start();		}		public Dimension preferredSize() {		return minimumSize();	}		 public synchronized Dimension minimumSize() {	 	return new Dimension(screenwidth, screenheight);	}		// Start running a thread	public void start() {		if (runner == null) {			runner = new Thread(this);			runner.start();			isrunning=true;		}	}		// Stop the thread	public void stop() {		if (runner != null) {			runner.stop();			runner = null;			isrunning=false;		}	}		// Continually initialize, and drop balls	public void run() {		//System.out.println("H");		while (true) {			dropAll();		}	}						// Stop/start the simulation	public boolean mouseDown(Event evt, int x, int y) {		if (runner != null) {			if (isrunning==true) {				runner.suspend();				isrunning=false;			}			else {				runner.resume();				isrunning=true;			}		}		return true;		}		// Return coordinates of a certain pin	public Point pinCoord(int row, int col) {		Point coord = new Point(screenwidth/2 - ((int) (((float) row/2 - col) * SIDE) + (PINSIZE/2)), 			DROPCOORD + (row * HEIGHT) - (PINSIZE/2));		return coord;	}		public void paint(Graphics g) {		//System.out.println("paint1");		g.setColor(new Color(255, 255, 255));				g.fillRect(0, 0, screenwidth, screenheight);				g.setColor(new Color(0, 100, 0));				// Draw each pin		for (int r = 0; r < pinrows; r++) {			for (int c = 0; c <= r; c++) {				g.drawOval(pinCoord(r, c).x, pinCoord(r, c).y, PINSIZE, PINSIZE);			}		}				g.setColor(new Color(100, 0, 0));				for (int m = 0; m < pinrows+2; m++) {			//System.out.println("bars");			g.fillRect((screenwidth/2-((pinrows+1)*(SIDE/2))+(m*SIDE)-(barwidth/2)), maxy, barwidth, (screenheight-CUTCOORD)-maxy);			//System.out.println(String.valueOf(screenwidth/2-(pinrows*(SIDE/2))+(m*SIDE)-(barwidth/2)) + " " + String.valueOf(maxy) + " " + String.valueOf(barwidth) + " " + String.valueOf(CUTCOORD-maxy));		}				g.setColor(new Color(0, 0, 100));				g.drawOval(xpos, ypos, BALLSIZE, BALLSIZE );				g.setColor(new Color(0, 0, 0));				for (int j = 0; j<=pinrows; j++) {			for (int k = 1; k<=slotballs[j]; k++) {			g.drawOval(firstcol+(j*SIDE), screenheight-CUTCOORD-(flatball*k), BALLSIZE, flatball);		}		//System.out.println("painting");		}	}		public void update(Graphics g) {		painted=true;		//System.out.println("update1");		//g.drawRect(cliparea.x-1, cliparea.y-1, cliparea.width+2, cliparea.height+2);//		g.clearRect(cliparea.x, cliparea.y, cliparea.width, cliparea.height);		g.clipRect(cliparea.x, cliparea.y, cliparea.width, cliparea.height);		paint(g);		//System.out.println("updating");	}		// Return random bounded integer (unused at the moment)	public int myRand(int range) {		float randFloat;		int randInt;		randFloat = randGen.nextFloat();		randInt = (int) Math.floor(randFloat*range)+1;		return randInt;	}		// Drop all balls	public void dropAll() {		doinit();		flatball = BALLSIZE;		// Initialize number of balls in each slot to 0		for (int k = 0; k < slotballs.length; k++) {			slotballs[k] = 0;			}		//xpos = screenwidth/2 - (BALLSIZE/2);		//ypos = (DROPCOORD - (PINSIZE/2) - BALLSIZE + 1);		cliparea = new Rectangle(0, 0, screenwidth, screenheight);		painted = false;				for (curball = 0; curball<= NUMBALLS-1; curball++) {			xpos = screenwidth/2 - (BALLSIZE/2);			ypos = (DROPCOORD - (PINSIZE/2) - BALLSIZE + 1);			dropBall();		}		isrunning = false;		runner.suspend();	}		// Drop one ball all the way down	public void dropBall() {		//xpos = screenwidth/2-(BALLSIZE/2);		//ypos = (DROPCOORD-(PINSIZE/2)-BALLSIZE+1);		slotno = 0;		for (int i = 1; i<= pinrows; i++) {			nextPin();		}		dropSlot();		}			// drop down one pin	public void nextPin() {		pause(pauselength);		oldx = xpos;		oldy = ypos;				if (randGen.nextFloat() > leftprob)			xpos -= (SIDE/2);		else {			xpos += (SIDE/2);			slotno++;		}		ypos += HEIGHT;				if (painted==true) {			//System.out.println("smallset");			cliparea.x=Math.min(xpos, oldx);			cliparea.y=oldy;			cliparea.width=Math.max(xpos, oldx) - cliparea.x + BALLSIZE + 1;			cliparea.height=ypos - oldy + BALLSIZE + 1;		}		else {			//System.out.println("bigset");		oldclipx = cliparea.x;		oldclipy = cliparea.y;		cliparea.x = Math.min(Math.min(xpos, oldx), oldclipx);		cliparea.y = Math.min(Math.min(oldy, oldclipy), ypos);		cliparea.width = (Math.max(Math.max(xpos, oldx), (oldclipx+cliparea.width-(BALLSIZE+1)))-cliparea.x)+BALLSIZE+1;		cliparea.height = (Math.max(Math.max(ypos, (oldclipy+cliparea.height-(BALLSIZE+1))), oldy)-cliparea.y)+BALLSIZE+1;	}		//myclip.play();		painted = false;		repaint();			}		// Drop the ball into its final slot	public void dropSlot() {		pause(pauselength);		oldy=ypos;		ypos = (screenheight - CUTCOORD) - ((slotballs[slotno]+1) * flatball);		slotballs[slotno] = slotballs[slotno]+1;		if (ypos <= maxy) {			flatball=flatball/2;			cliparea=new Rectangle(0, 0, screenwidth, screenheight);			repaint();		}		else {			if (painted == true) {				//System.out.println("smallset");				cliparea.x = xpos;				cliparea.y = oldy;				cliparea.width = BALLSIZE+1;				cliparea.height = ypos-oldy+BALLSIZE+1;			}			else {				//System.out.println("bigset");			oldclipy = cliparea.y;			cliparea.y = Math.min(Math.min(oldy, oldclipy), ypos);			cliparea.height = (Math.max(Math.max(ypos, (oldclipy+cliparea.height-(BALLSIZE+1))), oldy)-cliparea.y)+BALLSIZE+1;			}		}		//xpos = screenwidth/2-(BALLSIZE/2);		//ypos = (DROPCOORD-(PINSIZE/2)-BALLSIZE+1);		painted=false;		repaint();	}		// Return basic info	public String getAppletInfo() {		return "This applet was written by Julian Devlin. It simulates a Galton board.";		}		// Wait a certain amount of time	void pause(int time) {		try { Thread.sleep(time); }		catch (InterruptedException e) { }	}				}
