/******************************************************************
Java Applet buff.java
March 1998 - Michael J. Hurben
This applet provides a _simulation_ of the famous Buffon's Needle
experiment. Buffon's Needle is a Monte Carlo simulation for the
determination of the value of pi.
******************************************************************/
import java.applet.*;
import java.awt.*;
public class buff extends Applet implements Runnable
{
Dimension offDimension, d; // Variables used to create an
Image offImage; // offscreen image via the update()
Graphics offGraphics; // method, to reduce flicker
int needleLength = 20;
int numRows = 10;
int xBorder = 15; // Basic layout variables
int yBorder = 45;
int margin = 50;
int tableHeight = needleLength*numRows; //
int tableWidth = 200; // Define size of table
int tableXcorner = xBorder; // where needles are thrown
int tableYcorner = yBorder; //
int barWidth = 20; // Define size of bar graph
int barHeight = tableHeight;
int barXcorner = xBorder+tableXcorner+tableWidth+margin;
int barYcorner = tableYcorner;
double barTop = 3.24; // Set limits for limits of bar graph
double barBot = 3.04;
double barMid = (barTop+barBot)/2;
int barValue; // Dynamic value of the bar graph
int plotWidth = 200; // Define size of plot
int plotHeight = tableHeight;
int plotXcorner = barXcorner+margin+barWidth+xBorder;
int plotYcorner = tableYcorner;
double plotMax = 4; // Set limits on the plot
double plotMin = 2;
double plotMid = (plotMax+plotMin)/2;
int barMaxPlot = (int) (plotHeight*(plotMax-barTop)/
(plotMax-plotMin));
int barMinPlot = (int) (plotHeight*(plotMax-barBot)/
(plotMax-plotMin));
int barThick=(barMaxPlot==barMinPlot? 1 :
barMinPlot-barMaxPlot);
int pointerWidth=30; // Bar graph pointer
int pointerTop, pointerBot;
int power = 5; // Orders of magnitude for the x-axis of the plot
int n = 0; // The number of needles thrown
int hit = 0; // The number of needles which hit lines
int i = 1; //
double needleX1, needleX2, needleY1, needleY2;
double deltaX, deltaY;
int ysign;
final double piValue=2.0*Math.atan(1.0);
int x1, x2, y1, y2; // Used to draw needles
int gx1, gx2, gy1, gy2; // Used to make the plot
int speed = 20; // Sets speed with try-catch block
double h = 0; // double version of the number of hits
double estPi, prevEstPi; // Estimates of pi
double prob = 1; // Ratio of hits to trys
double prev = 1; // Ratio on the previous trial
boolean oldScreen = false;
boolean begin = false;
Thread t;
Button b1, b2, b3, b4;
public void init()
{
setLayout(new FlowLayout(FlowLayout.LEFT));
b1 = new Button("Start");
b2 = new Button("Slower");
b3 = new Button("Faster");
b4 = new Button("Done");
add(b1);
add(b2);
add(b3);
add(b4);
t = new Thread(this);
t.start();
}
public boolean action(Event e, Object o)
{
if (o.equals("Start"))
{
n = 0;
hit = 0;
oldScreen = false;
begin = true;
}
else if (o.equals("Done"))
{
t.stop();
}
else if (o.equals("Faster"))
{
speed = (speed>10? speed-10 : 10);
}
else if (o.equals("Slower"))
{
speed = speed+10;
}
return true;
}
public void run()
{
while(true)
{
if(begin)
{
// Calculate the position of the needle ends...
needleX1 = tableWidth*Math.random();
needleY1 = tableHeight*Math.random();
deltaX = needleLength*Math.sin(2*piValue*Math.random()-piValue);
deltaY = Math.sqrt(needleLength*needleLength-deltaX*deltaX);
needleX2 = needleX1+deltaX;
ysign = (Math.random()<0.5? -1 : 1);
needleY2 = needleY1+ysign*deltaY;
// Check to see if it crosses a line...
for (int yLine=0; yLine<=needleLength*numRows; yLine+=needleLength)
{
if((needleY1<=yLine && needleY2>=yLine) ||
(needleY1>=yLine && needleY2<=yLine))
{
hit++;
break;
}
}
n++;
prev = prob;
h = hit;
prob = h/n;
prevEstPi = 2/prev;
estPi = 2/prob;
// Calculation for the plot
gx1 = (int)(plotXcorner+Math.log(n)*plotWidth/(power*Math.log(10)));
gx2 = (int)(plotXcorner+Math.log(n+1)*plotWidth/(power*Math.log(10)));
gy1 = (int)(plotYcorner+(plotHeight/(plotMin-plotMax))*
(prevEstPi-plotMax));
if (gy1<=plotYcorner) gy1 = plotYcorner+1;
if (gy1==plotYcorner+plotHeight) gy1=gy1-1;
gy2 = (int)(plotYcorner+(plotHeight/(plotMin-plotMax))*
(estPi-plotMax));
if (gy2<=plotYcorner) gy2 = plotYcorner+1;
if (gy2==plotYcorner+plotHeight) gy2=gy2-1;
// Calculation for drawing the needles
x1 = (int) (xBorder+needleX1);
x2 = (int) (xBorder+needleX2);
y1 = (int) (yBorder+needleY1);
y2 = (int) (yBorder+needleY2);
repaint();
}
try
{
Thread.currentThread().sleep(speed);
}
catch(InterruptedException e)
{
}
}
}
public void paint(Graphics g)
{
d = size();
update(g);
}
public void update(Graphics g)
{
if((offGraphics==null) // Setup an off-screen image
||(d.width!=offDimension.width) // via the update() method.
|| (d.height!=offDimension.height)) //
{
offDimension = d;
offImage = createImage(d.width, d.height);
offGraphics = offImage.getGraphics();
}
if(!oldScreen)
{
offGraphics.setColor(getBackground());
offGraphics.fillRect(0,0, d.width, d.height);
offGraphics.setColor(Color.gray);
offGraphics.fillRect(plotXcorner, plotYcorner+barMaxPlot,
plotWidth, barMinPlot-barMaxPlot);
offGraphics.drawString(" "+barMid+"-", barXcorner-45,
barYcorner+barHeight/2);
offGraphics.drawString(" "+barTop+"-", barXcorner-45,
barYcorner+5);
offGraphics.drawString(" "+barBot+"-", barXcorner-45,
barYcorner+3+barHeight);
offGraphics.drawString("-"+plotMax, plotXcorner+plotWidth+2,
plotYcorner+5);
offGraphics.drawString("-"+plotMin, plotXcorner+plotWidth+2,
plotYcorner+plotHeight+5);
offGraphics.drawString("-"+plotMid, plotXcorner+plotWidth+2,
plotYcorner+plotHeight/2+5);
offGraphics.drawString("Estimate vs. log(number of tries)",
plotXcorner+5, plotYcorner+plotHeight+20);
// Draw lines which relate the bar graph and the plot...
offGraphics.drawLine(barXcorner+barWidth+5, barYcorner,
plotXcorner-5, barMaxPlot+plotYcorner);
offGraphics.drawLine(barXcorner+barWidth+5, barYcorner+barHeight,
plotXcorner-5, barMinPlot+plotYcorner);
// Draw tabletop and the plot axes
offGraphics.setColor(Color.blue);
offGraphics.drawRect(tableXcorner,tableYcorner, tableWidth, tableHeight);
offGraphics.drawRect(plotXcorner, plotYcorner,plotWidth, plotHeight);
for(i=1; itableXcorner+tableWidth?
tableXcorner+tableWidth:x1);
x2 = (x2tableXcorner+tableWidth?
tableXcorner+tableWidth:x2);
y1 = (y1tableYcorner+tableHeight?
tableYcorner+tableHeight:y1);
y2 = (y2tableYcorner+tableHeight?
tableYcorner+tableHeight:y2);
offGraphics.drawLine(x1,y1,x2,y2);
// Draw the bar graph
offGraphics.setColor(Color.gray);
offGraphics.fillRect(barXcorner, barYcorner, 20, barHeight);
offGraphics.setColor(Color.red);
barValue = (int)(barHeight*(estPi-barTop)/(barBot-barTop));
if (barValue<0-pointerWidth/2) barValue=0-pointerWidth/2;
if (barValue>barHeight+pointerWidth/2) barValue=barHeight+
pointerWidth/2;
pointerTop = (barValue-pointerWidth/2<0 ?
0 : barValue-pointerWidth/2);
pointerBot = (barValue+pointerWidth/2>barHeight?
barHeight : barValue+pointerWidth/2);
offGraphics.fillRect(barXcorner, barYcorner+pointerTop,
barWidth, pointerBot-pointerTop);
// Center line in the pointer
offGraphics.setColor(Color.gray);
if (barValue<0) barValue=0;
if (barValue>barHeight) barValue=barHeight;
offGraphics.drawLine(barXcorner, barYcorner+barValue,
barXcorner+barWidth-1, barYcorner+barValue);
// Finally, draw the plot
offGraphics.setColor(Color.red);
offGraphics.drawLine(gx1,gy1,gx2,gy2);
g.drawImage(offImage, 0, 0, this);
}
}