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.