Blame lazarus/snake/unit1.pas

ec1092
unit Unit1;
ec1092
ec1092
{$mode objfpc}{$H+}
ec1092
ec1092
interface
ec1092
ec1092
uses
ec1092
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
ec1092
  ExtCtrls, Math;
ec1092
ec1092
type
ec1092
ec1092
  { TForm1 }
ec1092
ec1092
  TForm1 = class(TForm)
ec1092
    Label1: TLabel;
ec1092
    Label2: TLabel;
ec1092
    Timer1: TTimer;
ec1092
    procedure FormCreate(Sender: TObject);
ec1092
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
ec1092
    procedure FormPaint(Sender: TObject);
ec1092
    procedure Timer1Timer(Sender: TObject);
ec1092
  private
ec1092
    { private declarations }
ec1092
  public
ec1092
    { public declarations }
ec1092
  end;
ec1092
ec1092
const
ec1092
  ballR = 20;
ec1092
  pointR = 5;
ec1092
ec1092
var
ec1092
  Form1: TForm1;
ec1092
  points: array of TPoint;
ec1092
  count: integer;
ec1092
  ball: TPoint;
ec1092
  maxLen: single = 200;
ec1092
  len: single;
ec1092
ec1092
  lenLabel, maxlenLabel: integer;
ec1092
ec1092
implementation
ec1092
ec1092
{$R *.lfm}
ec1092
ec1092
function getLen: single;
ec1092
var
ec1092
  i: integer;
ec1092
begin
ec1092
  Result := 0;
ec1092
  for i:=1 to count-1 do
ec1092
    Result := Result + sqrt(sqr(points[i].x-points[i-1].x) + sqr(points[i].y-points[i-1].y));
ec1092
  len := Result;
ec1092
end;
ec1092
ec1092
function IntersectsCircles(p1, p2: TPoint; r1, r2: single): boolean;
ec1092
begin
ec1092
  Result := sqr(p1.x-p2.x) + sqr(p1.Y-p2.y) < sqr(r1+r2);
ec1092
end;
ec1092
ec1092
function IntersectsLines(a1, a2, b1, b2: TPoint): boolean;
ec1092
var
ec1092
  x1, y1, x2, y2, r, d2, d1: single;
ec1092
begin
ec1092
  Result := false;
ec1092
ec1092
  r := sqr(a2.x-a1.x) + sqr(a2.y-a1.y);
ec1092
  if r = 0 then exit;
ec1092
  x1 := ((a2.x-a1.x)*(b1.x-a1.x) + (a2.y-a1.y)*(b1.y-a1.y))/r;
ec1092
  y1 := ((a1.y-a2.y)*(b1.x-a1.x) + (a2.x-a1.x)*(b1.y-a1.y))/r;
ec1092
  x2 := ((a2.x-a1.x)*(b2.x-a1.x) + (a2.y-a1.y)*(b2.y-a1.y))/r;
ec1092
  y2 := ((a1.y-a2.y)*(b2.x-a1.x) + (a2.x-a1.x)*(b2.y-a1.y))/r;
ec1092
ec1092
  if y1 = y2 then exit;
ec1092
ec1092
  d2 := y1/(y1-y2);
ec1092
  if (d2 <= 0) or (d2 > 1) then exit;
ec1092
  d1 := d2*(x2-x1) + x1;
ec1092
  if (d1 <= 0) or (d1 > 1) then exit;
ec1092
  Result := true;
ec1092
end;
ec1092
ec1092
procedure GenerateBall;
ec1092
var
ec1092
  i: integer;
ec1092
  retry: boolean;
ec1092
begin
ec1092
  retry := true;
ec1092
  while retry do begin
ec1092
    ball.x := RandomRange(ballR, Form1.ClientWidth-ballR);
ec1092
    ball.y := RandomRange(ballR, Form1.ClientHeight-ballR);
ec1092
    retry := false;
ec1092
    for i := 0 to count - 1 do
ec1092
      if IntersectsCircles(ball, points[i], ballR, pointR) then
ec1092
        retry := true;
ec1092
  end;
ec1092
end;
ec1092
ec1092
procedure RemovePoints(cnt: integer);
ec1092
var
ec1092
  i: integer;
ec1092
begin
ec1092
  with Form1 do begin
ec1092
    Canvas.Pen.Color := Color;
ec1092
    Canvas.Pen.Width := 2*pointR;
ec1092
    Canvas.MoveTo(points[0].x, points[0].y);
ec1092
    for i := 0 to min(cnt, count-1) do Canvas.LineTo(points[i].x, points[i].y);
ec1092
    for i := cnt to count-1 do points[i-cnt] := points[i];
ec1092
    count := count - cnt;
ec1092
    setLength(points, count);
ec1092
    FormPaint(nil);
ec1092
  end;
ec1092
end;
ec1092
ec1092
procedure AddPoint(p: TPoint);
ec1092
var
ec1092
  i: integer;
ec1092
  len: single;
ec1092
begin
ec1092
  if count > 0 then begin
ec1092
    len := sqrt(sqr(points[count-1].x-p.x) + sqr(points[count-1].y-p.y));
ec1092
    if len < pointR then exit;
ec1092
  end;
ec1092
ec1092
  while getLen > maxLen do RemovePoints(1);
ec1092
ec1092
  count := count + 1;
ec1092
  setLength(points, count);
ec1092
  points[count-1] := p;
ec1092
ec1092
  for i := count-10 downto 1 do begin
ec1092
    if IntersectsLines(points[count-1], points[count-2], points[i], points[i-1]) then begin
ec1092
      RemovePoints(i);
ec1092
      maxLen := getLen;
ec1092
      break;
ec1092
    end;
ec1092
  end;
ec1092
ec1092
  if IntersectsCircles(p, ball, pointR, ballR) then begin
ec1092
    GenerateBall;
ec1092
    maxLen := maxLen + 2*ballR;
ec1092
  end;
ec1092
ec1092
  Form1.Refresh();
ec1092
end;
ec1092
ec1092
procedure TForm1.FormCreate(Sender: TObject);
ec1092
begin
ec1092
  Randomize;
ec1092
  GenerateBall;
ec1092
end;
ec1092
ec1092
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
ec1092
  Y: Integer);
ec1092
begin
ec1092
  AddPoint(Point(x, y));
ec1092
end;
ec1092
ec1092
procedure TForm1.FormPaint(Sender: TObject);
ec1092
begin
ec1092
  Canvas.Pen.Color := clBlack;
ec1092
  Canvas.Pen.Width := 2*pointR;
ec1092
  Canvas.Polyline(points);
ec1092
ec1092
  Canvas.Pen.Color := clBlue;
ec1092
  Canvas.Pen.Width := 2*ballR;
ec1092
  Canvas.MoveTo(round(ball.x), round(ball.y));
ec1092
  Canvas.LineTo(round(ball.x), round(ball.y));
ec1092
end;
ec1092
ec1092
procedure TForm1.Timer1Timer(Sender: TObject);
ec1092
begin
ec1092
  if round(len) <> lenLabel then begin
ec1092
    lenLabel := round(len);
ec1092
    Label1.Caption := 'length ' + IntToStr(lenLabel);
ec1092
    Label2.Caption := 'max length ' + IntToStr(maxlenLabel);
ec1092
  end;
ec1092
  if round(len) > maxlenLabel then begin
ec1092
    maxlenLabel := round(len);
ec1092
    Label2.Caption := 'max length ' + IntToStr(maxlenLabel);
ec1092
  end;
ec1092
end;
ec1092
ec1092
end.
ec1092