unit U_RandomTriangles;
{Copyright © 2004, Gary Darby, www.DelphiForFun.org
This program may be used or modified for any non-commercial purpose
so long as this original notice remains in place.
All other rights are reserved
}
{What is probability that a stick broken into 3 random pieces can be
reassembled to form a triangle?}
interface
...snip....
public
{ Public declarations }
L:array[1..3] of EXTENDED; {The 3 lengths}
OKCount, TotCount:integer; {Counts of successful and total trials}
function Maketriangle:boolean;
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure swap(var a,b:extended);
{Swap two variables - used for sorting piece lengths}
var x:extended;
begin x:=a; a:=b; b:=x; end;
{***************** MakeTriangle ************}
function TForm1.maketriangle:boolean;
{try to make a random triangle by cutting a stick of unit length to into
3 random length pieces}
var
j,k:integer;
p1,p2:extended;
begin
{MAKE TWO RANDOM CUTS IN A PIECE 1 UNIT LONG}
p1:=random; {1st point - random # between 0 and 1}
p2:=random; {2nd point - random # between 0 and 1}
{CALCULATE LENGTHS OF THE PIECES}
IF p1>p2 then {p2 is the leftmost cut point}
begin
L[1]:=p2;
L[2]:=p1-p2;
end
else
begin {p1 is the leftmost cut point}
L[1]:=p1;
L[2]:=p2-p1;
end;
L[3]:=1-L[1]-L[2]; {Either way, final piece is whatever is left over}
{Now sort descending by length}
for j:= 1 to 2 do
for k:= j+1 to 3 do if L[j]<L[k] then swap(L[j],L[k]);
{If L[1], longest piece, is greater than sum of the other two pieces,
no triangle is possible}
if L[1]>0.5 {L[2]+L[3]} then result:=false else result:=true;
end;
{************* MakeManyBtnClick **************}
procedure TForm1.MakeManyBtnClick(Sender: TObject);
var i:integer;
begin
randomize;
for i:=1 to 100000 do
begin
inc(totcount);
if maketriangle then inc(OKcount);
end;
memo1.lines.add(format('%6.0n out of %7.0n can form triangle',[0.0+OkCount,0.0+totcount]));
end;
{************** MakeOneBtnClick *************}
procedure TForm1.MakeOneBtnClick(Sender: TObject);
{try a single triangle and draw an image of results}
var
scale:extended;
s,a:extended;
begin
with image1, canvas do
begin
pen.width:=3;
rectangle(clientrect); {clear the image}
moveto( 20,height-10); {move pen to start of base line}
if maketriangle then
begin
{If we draw L[1] as the base, we need only to compute the point where
L[2] and L[3] intersect. See web site for derivation of the foillowig
equations for "s" (x offset from left end of base) and "a" (y offset to
top vertex)}
s:=(L[2]*L[2]-L[3]*L[3]+L[1]*L[1])/L[1]/2; {compute x offset to 3rd vertex}
a:=sqrt(l[2]*L[2]-s*s); {compute altitude to 3rd vertex}
scale:=0.8*width/L[1]; {make longest line cover 80% of image width}
{or scale by altitude if peak would be offscreen}
if scale*a+10>height then scale:=0.8*(height/a);
memo1.lines.add(format('Valid - L1= %5.3f L2=%5.3f L3=%5.3f',[L[1],L[2],L[3]]));
{finish drawing the triangle}
lineto(20+trunc(scale*L[1]),height-10);
lineto(20+trunc(scale*L[1])-trunc(scale*s),height-10-trunc(scale*a));
lineto(20,height-10);
textout(5,5,'Yes!');
end
else
begin
memo1.lines.add(format('Invalid - L1= %5.3f L2=%5.3f L3=%5.3f',[L[1],L[2],L[3]]));
scale:=width;
lineto(20+trunc(scale*L[1]),height-10); {draw base line}
{draw the two short lines parallel and above the base line}
moveto( 20,height-20);
lineto(20+trunc(scale*L[2]),height-20);
moveto(20+trunc(scale*L[1]),height-20);
lineto(20+trunc(scale*(L[1]-L[3])),height-20);
textout(5,5, 'No :>(');
end;
end;
end;
{************ FormActivate *************}
procedure TForm1.FormActivate(Sender: TObject);
begin
randomize; {make random results not repeatable}
clearbtnclick(sender);
end;
{************** ClearBtnClick ***********}
procedure TForm1.ClearBtnClick(Sender: TObject);
{reset everything}
begin
okcount:=0;
totcount:=0;
memo1.clear;
image1.canvas.rectangle(image1.clientrect);
end;
end.