This applet simulates how random distribution creates a bell-curve and make it easier to understand the normal distribution which is used in many life problems .
[code=java5]import java.util.*;
import java.awt.*;
import java.awt.image.*;
import java.applet.*;
class Ball implements ImageObserver {
static final double slowdown = .75;
static final double getout = 1;
double x,y,vx,vy,vlen,r;
int w,h;
Image itsImage = null;
AudioClip itsBoink;
Ball(double tx,double ty) {
x=tx;
y=ty;
vx=0;
vy=0;
vlen=0;
}
void SetBoinkSound(AudioClip aClip) {
itsBoink=aClip;
}
void Move() {
x += vx;
y += vy;
}
void Accelerate(double ax,double ay) {
vx += ax;
vy += ay;
vlen=Math.sqrt(vx*vx+vy*vy);
}
boolean Boink(int pinx,int piny,double pinr) {
double dx,dy,dist;
dx=x-(double)pinx;
dy=y-(double)piny;
dist=Math.sqrt(dx*dx+dy*dy);
if(dist<=pinr+r) {
double tvx,tvy,proj;
if(itsBoink != null) {
itsBoink.stop();
itsBoink.play();
}
tvx = vx/vlen;
tvy = vy/vlen;
dx /= dist;
dy /= dist;
proj=tvx*dx+tvy*dy;
tvx -= 2.0*proj*dx;
tvy -= 2.0*proj*dy;
vx = tvx*vlen;
vy = tvy*vlen;
do {
x += vx;
y += vy;
dx=x-(double)pinx;
dy=y-(double)piny;
dist=Math.sqrt(dx*dx+dy*dy);
} while(dist<=pinr+r);
vx *= slowdown;
vy *= slowdown;
vlen=Math.sqrt(vx*vx+vy*vy);
return true;
}
else return false;
}
void SetImage(Image aImage) {
itsImage=aImage;
w=itsImage.getWidth(this);
h=itsImage.getHeight(this);
r=w/2.0;
}
void Draw(Graphics g) {
if(itsImage != null)
g.drawImage(itsImage,(int)x-w/2,(int)y-h/2, this);
}
public boolean imageUpdate(Image img,
int infoflags,
int x,
int y,
int width,
int height)
{
if((infoflags & (WIDTH | HEIGHT)) == (WIDTH | HEIGHT)) {
if(img == itsImage) {
w=width;
h=height;
r=w/2;
}
return false;
}
return true;
}
}
public class BallDrop extends Applet implements Runnable {
Thread itsThread = null;
MediaTracker itsTracker = null;
AudioClip itsBoink = null;
Vector itsBalls;
Dimension offDimension,backDimension;
Image offImage,backImage;
static final int numrows=8,numcolumns=20,numballs=10,delay=10,
topspace=30,sidespace=20;
Image pin,ball;
double pinr;
int ballw,ballh,pinw,pinh,numracks,rackheight[],rackdel[];
public void init() {
Dimension d = size();
Ball aBall;
itsTracker=new MediaTracker(this);
ball = getImage(getDocumentBase(), "smallball.gif");
pin = getImage(getDocumentBase(), "smallpin.gif");
itsTracker.addImage(ball,0);
itsTracker.addImage(pin,0);
try {
itsTracker.waitForAll();
}
catch (InterruptedException e) {
return;
}
// itsBoink = getAudioClip(getDocumentBase(),"boink.au");
itsBalls=new Vector();
for(int i=0;i
aBall = new Ball(d.width/2,0);
aBall.Accelerate((Math.random()-.5)*.5,0);
// aBall.SetBoinkSound(itsBoink);
itsBalls.addElement(aBall);
}
}
public void start() {
if (itsThread == null) {
itsThread = new Thread(this);
itsThread.start();
}
}
public void stop() {
itsThread = null;
offImage = null;
backImage = null;
}
public boolean mouseDown(Event e, int x, int y) {
if (itsThread == null) {
start();
}
else {
itsThread = null;
}
return false;
}
public void run() {
Ball aBall;
// Remember the starting time
long startTime = System.currentTimeMillis();
// Use the media tracker to get the images
try {
itsTracker.waitForAll();
}
catch (InterruptedException e) {
return;
}
pinw = pin.getWidth(this);
pinh = pin.getHeight(this);
pinr = pinw/2.0;
ballw = ball.getWidth(this);
ballh = ball.getHeight(this);
for(Enumeration e = itsBalls.elements();e.hasMoreElements();) {
aBall=(Ball)e.nextElement();
aBall.SetImage(ball);
}
// Allocate rack information
numracks=size().width/ballw;
rackheight=new int[numracks];
rackdel=new int[numracks];
for(int i=0;i
rackheight[i]=0;
rackdel[i]=0;
}
while (Thread.currentThread() == itsThread) {
UpdateBalls();
repaint();
// Delay depending on how far we are behind.
try {
startTime += delay;
Thread.sleep(Math.max(0,
startTime-System.currentTimeMillis()));
}
catch (InterruptedException e) {
break;
}
}
}
// Paint the previous frame (if any).
public void paint(Graphics g) {
Graphics offGraphics;
Ball aBall;
Dimension d = size();
// Create the background image if necessary
if ( (backImage == null)
|| (d.width != backDimension.width)
|| (d.height != backDimension.height) ) {
Graphics backGraphics;
backDimension = d;
backImage = createImage(d.width, d.height);
backGraphics = backImage.getGraphics();
// Erase the previous image.
backGraphics.setColor(getBackground());
backGraphics.fillRect(0, 0, d.width, d.height);
backGraphics.setColor(Color.black);
//Paint the frame into the image.
paintBackground(backGraphics);
}
else {
updateRack(backImage.getGraphics());
}
if ( (offImage == null)
|| (d.width != offDimension.width)
|| (d.height != offDimension.height) ) {
offDimension = d;
offImage = createImage(d.width, d.height);
}
offGraphics = offImage.getGraphics();
offGraphics.drawImage(backImage,0,0, this);
for(Enumeration e = itsBalls.elements();e.hasMoreElements();) {
aBall=(Ball)e.nextElement();
aBall.Draw(offGraphics);
}
g.drawImage(offImage, 0, 0, this);
}
public void update(Graphics g) {
paint(g);
}
void paintBackground(Graphics g) {
Dimension d = size();
int i,j,pinx,piny;
double scale,x,y,oy;
// Draw the pins
for(i=0;i
piny=i*(d.height-2*topspace)/(numrows*2)+topspace;
scale=(double)(d.width-2*sidespace)/(double)numcolumns;
for(j=0;j
pinx=(int)((j+(i%2)/2.0)*scale)+sidespace;
g.drawImage(pin,pinx-pinw/2,piny-pinh/2, this);
}
}
// Draw density curve
scale=(double)d.width/numracks;
g.setColor(Color.black);
oy=0;
for(i=0;i<=numracks;++i) {
x=numracks/2;
y=d.height*(1.0-.5*Math.exp(-(double)(i-x)*(i-x)/(2*81)));
if(i>0) g.drawLine((int)((i-1)*scale),(int)oy,(int)(i*scale),(int)y);
oy=y;
}
// Draw 'racks'
for(i=0;i
for(j=0;j
pinx=i*ballw;
piny=d.height-(j+1)*ballh;
g.drawImage(ball,pinx,piny, this);
}
}
}
void updateRack(Graphics g) {
int i,pinx,piny;
Dimension d = size();
/*
double sumr,sumrr,mean,stdev,num;
sumr=0;
sumrr=0;
num=0;
*/
for(i=0;i
while(rackdel[i]>0) {
++rackheight[i];
pinx=i*ballw;
piny=d.height-rackheight[i]*ballh;
g.drawImage(ball,pinx,piny, this);
--rackdel[i];
}
/*
num += rackheight[i];
sumr += rackheight[i]*i;
sumrr += rackheight[i]*i*i;
*/
}
/*
if(num>0) {
mean=sumr/num;
stdev=Math.sqrt(sumrr/num - mean*mean);
System.out.println(mean + " " + stdev);
}
*/
}
void UpdateBalls() {
int i,j,k,pinx,piny,rack,bottomy,fr,lr,fc,lc;
double scale;
Ball aBall;
Dimension d = size();
bottomy=d.height;
for(Enumeration e = itsBalls.elements();e.hasMoreElements();) {
aBall=(Ball)e.nextElement();
aBall.Move();
if(aBall.y>bottomy-aBall.r) {
if(itsBoink != null) {
itsBoink.stop();
itsBoink.play();
}
if(aBall.vlen>.25) {
aBall.vx = 0;
aBall.vy = -aBall.vy*.25;
aBall.y = bottomy-aBall.r;
}
else {
rack=(int)(aBall.x/ballw);
if(rack>=0 && rack
++rackdel[rack];
}
aBall.x=d.width/2;
aBall.y=aBall.r;
aBall.vx=(Math.random()-.5)/3;
aBall.vy=0;
}
}
else {
k=(int)((aBall.y-topspace)*2*numrows/(d.height-2*topspace));
fr= k<=0 ? 0 : k-1;
lr= k>=numrows-1 ? numrows-1 : k+1;
for(i=fr;i<=lr;++i) { // Rows
piny=i*(d.height-2*topspace)/(2*numrows)+topspace;
scale=(double)(d.width-2*sidespace)/(double)numcolumns;
k=(int)((aBall.x-sidespace)/scale-(i%2)/2.0);
fc= k<=0 ? 0 : k-1;
lc= k>=numcolumns-1 ? numcolumns-1 : k+1;
for(j=fc;j<=lc;++j) { // Columns
pinx=(int)((j+(i%2)/2.0)*scale+sidespace);
aBall.Boink(pinx,piny,pinr);
}
}
}
aBall.Accelerate(0,.075);
}
}
}
[/code]