Difference between revisions of "15-puzzle"

From Free Pascal wiki
Jump to navigationJump to search
 
(One intermediate revision by one other user not shown)
Line 10: Line 10:
 
== Create code ==
 
== Create code ==
  
* Create a new blank GUI application with the form Form1  
+
* Create a new blank GUI application with the form [[TForm|Form1]]
 
* Change caption Form1 to ''15Puzzle'''.
 
* Change caption Form1 to ''15Puzzle'''.
* Add New Unit [[15-puzzle#unitGameBoard.pas|unitGameBoard.pas]]
+
* Add New [[Unit|Unit]] [[15-puzzle#unitGameBoard.pas|unitGameBoard.pas]]
 
* Create the OnCreate event handler for the form, by clicking on your form, use the Object Inspector, the tab events, select the OnCreate event and click the button [...] or double click the button in the form.  
 
* Create the OnCreate event handler for the form, by clicking on your form, use the Object Inspector, the tab events, select the OnCreate event and click the button [...] or double click the button in the form.  
 
* Add following code:
 
* Add following code:
  
<source>
+
<syntaxhighlight lang="pascal">
 
procedure TForm1.FormCreate(Sender: TObject);
 
procedure TForm1.FormCreate(Sender: TObject);
 
var
 
var
Line 43: Line 43:
 
end;   
 
end;   
  
</source>
+
</syntaxhighlight>
  
 
* Create in the Object Inspector the event handler for the event FormDestroy, by clicking on the button [...].
 
* Create in the Object Inspector the event handler for the event FormDestroy, by clicking on the button [...].
 
* Add the following code to the handler:
 
* Add the following code to the handler:
  
<source>
+
<syntaxhighlight lang="pascal">
 
procedure TForm1.FormDestroy(Sender: TObject);
 
procedure TForm1.FormDestroy(Sender: TObject);
 
begin
 
begin
 
   FreeAndNil(Puzzle15);
 
   FreeAndNil(Puzzle15);
 
end;  
 
end;  
</source>
+
</syntaxhighlight>
  
  
 
* Now you must create the event handler for the button clicks.
 
* Now you must create the event handler for the button clicks.
* In the source editor, entering your class TForm1 in the section private.
+
* In the source editor, entering your [[Class|class]] TForm1 in the section [[Private|private]].
* Add procedure aButtonClick(Sender: TObject); and then press the keys {{keypress|Ctrl}}+{{keypress|Shift}}+{{keypress|c}} (the code completion becomes active and creates the procedure TForm1.aButtonClick(Sender: TObject);.
+
* Add [[Procedure|procedure]] <syntaxhighlight lang="pascal" inline> procedure aButtonClick(Sender: TObject);</syntaxhighlight> and then press the keys {{keypress|Ctrl}}+{{keypress|Shift}}+{{keypress|c}} (the code completion becomes active and creates the <syntaxhighlight lang="pascal" inline>procedure TForm1.aButtonClick(Sender: TObject);</syntaxhighlight>.
 
* Paste following code:
 
* Paste following code:
  
<source>
+
<syntaxhighlight lang="pascal">
 
procedure TForm1.aButtonClick(Sender: TObject);  //the event handler for the button
 
procedure TForm1.aButtonClick(Sender: TObject);  //the event handler for the button
 
var
 
var
Line 79: Line 79:
 
       end;
 
       end;
 
end;
 
end;
</source>
+
</syntaxhighlight>
  
 
== Source code ==
 
== Source code ==
Line 85: Line 85:
 
=== unit1.pas ===
 
=== unit1.pas ===
  
<source>
+
<syntaxhighlight lang="pascal">
 
unit Unit1;
 
unit Unit1;
  
Line 171: Line 171:
 
end.
 
end.
  
</source>
+
</syntaxhighlight>
 
=== Unit1.lfm ===
 
=== Unit1.lfm ===
<source>
+
<syntaxhighlight lang="pascal">
 
object Form1: TForm1
 
object Form1: TForm1
 
   Left = 362
 
   Left = 362
Line 184: Line 184:
 
   LCLVersion = '1.6.0.4'
 
   LCLVersion = '1.6.0.4'
 
end  
 
end  
</source>
+
</syntaxhighlight>
  
 
=== unitGameBoard.pas ===
 
=== unitGameBoard.pas ===
  
<source>
+
<syntaxhighlight lang="pascal">
 
unit unitGameBoard;
 
unit unitGameBoard;
  
Line 320: Line 320:
  
  
</source>
+
</syntaxhighlight>
  
 
== See also ==
 
== See also ==
  
 
* [[TButton]]
 
* [[TButton]]

Latest revision as of 16:12, 6 August 2022

English (en) suomi (fi) français (fr)

15-puzzle

puzzle15.png

The 15-puzzle is a sliding puzzle that consists of a frame of numbered square tiles in random order with one tile missing. The object of the puzzle is to place the tiles in order by making sliding moves that use the empty space.

Create code

  • Create a new blank GUI application with the form Form1
  • Change caption Form1 to 15Puzzle'.
  • Add New Unit unitGameBoard.pas
  • Create the OnCreate event handler for the form, by clicking on your form, use the Object Inspector, the tab events, select the OnCreate event and click the button [...] or double click the button in the form.
  • Add following code:
procedure TForm1.FormCreate(Sender: TObject);
var
  i : Integer;
  aButton: TButton;
  point:TPoint;
begin
  Randomize;
  Puzzle15:= TGameBoard.Create;
  i := 1;
  while i < 16 do
    begin                              //create 15 Buttons
      aButton:=TButton.Create(Self);   //create Button, Owner is Form1, where the button is released later
      aButton.Parent:=Self;            //determine where it is to be displayed
      aButton.Caption:=IntToStr(i);    //Captions of the buttons
      aButton.Width:=aButton.Height;   //Width should correspond to the height of the buttons
      point := Puzzle15.ButtonPlace(aButton.Caption);
      aButton.Left:= point.x* aButton.Width;    //Distance from left
      aButton.Top := point.y* aButton.Height;

      aButton.OnClick:=@aButtonClick; //the event handler for the button -> will be created yet
      inc(i);
    end;
  Self.Height:=aButton.Height*6;      //Height of the form should correspond to the height of the buttons
  Self.Width:=aButton.Width*6;        //Width of the form to match the width of all buttons
end;
  • Create in the Object Inspector the event handler for the event FormDestroy, by clicking on the button [...].
  • Add the following code to the handler:
procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(Puzzle15);
end;


  • Now you must create the event handler for the button clicks.
  • In the source editor, entering your class TForm1 in the section private.
  • Add procedure procedure aButtonClick(Sender: TObject); and then press the keys Ctrl+ Shift+c (the code completion becomes active and creates the procedure TForm1.aButtonClick(Sender: TObject);.
  • Paste following code:
procedure TForm1.aButtonClick(Sender: TObject);  //the event handler for the button
var
  i:integer;
  point : TPoint;
begin
  if (Sender is TButton) and                     //called the event handler of a button out?
     TryStrToInt(TButton(Sender).Caption, i)       //then try to convert the label in a integer
    then
      begin
        if Puzzle15.CanMove(TButton(Sender).Caption) then
          begin
            point := Puzzle15.Change(TButton(Sender).Caption);
            TButton(Sender).Left:= point.x* TButton(Sender).Width;    //Distance from left
            TButton(Sender).Top := point.y* TButton(Sender).Height;
          end;
      end;
end;

Source code

unit1.pas

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  unitGameBoard;

type

  { TForm1 }

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { private declarations }
    Puzzle15:TGameBoard;
    procedure aButtonClick(Sender: TObject);

  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
var
  i : Integer;
  aButton: TButton;
  point:TPoint;
begin
  Randomize;
  Puzzle15:= TGameBoard.Create;
  i := 1;
  while i < 16 do
    begin  //create 15 Buttons
      aButton:=TButton.Create(Self);    //create Button, Owner is Form1, where the button is released later
      aButton.Parent:=Self;             //determine where it is to be displayed
      aButton.Caption:=IntToStr(i);     //Captions of the buttons
      aButton.Width:=aButton.Height;    //Width should correspond to the height of the buttons
      point := Puzzle15.ButtonPlace(aButton.Caption);
      aButton.Left:= point.x* aButton.Width;    //Distance from left
      aButton.Top := point.y* aButton.Height;
      aButton.OnClick:=@aButtonClick;   //the event handler for the button -> will be created yet
      inc(i);
    end;
  Self.Height:=aButton.Height*6;        //Height of the form should correspond to the height of the buttons
  Self.Width:=aButton.Width*6;       //Width of the form to match the width of all buttons
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(Puzzle15);
end;

procedure TForm1.aButtonClick(Sender: TObject);  //the event handler for the button
var
  i:integer;
  point : TPoint;
begin
  if (Sender is TButton) and                     //called the event handler of a button out?
     TryStrToInt(TButton(Sender).Caption, i)       //then try to convert the label in a integer
    then
      begin
        if Puzzle15.CanMove(TButton(Sender).Caption) then
          begin
            point := Puzzle15.Change(TButton(Sender).Caption);
            TButton(Sender).Left:= point.x* TButton(Sender).Width;    //Distance from left
            TButton(Sender).Top := point.y* TButton(Sender).Height;
          end;
      end;
end;

end.

Unit1.lfm

object Form1: TForm1
  Left = 362
  Height = 184
  Top = 162
  Width = 432
  Caption = '15Puzzle'
  OnCreate = FormCreate
  OnDestroy = FormDestroy
  LCLVersion = '1.6.0.4'
end

unitGameBoard.pas

unit unitGameBoard;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils;

const
  GB_MAX_BUTTONS = 15;
  GB_MAX_X = 4;
  GB_MAX_Y = 4;
  GB_EMPTY_PLACE ='-';
type


  { TGameBoard }

  TGameBoard = class
  private
     GameArray:array[1..GB_MAX_X, 1..GB_MAX_Y] of string;
     function ValidPoint(a_point:TPoint):boolean;
  public
    constructor Create;
    function ButtonPlace(a_name:string):TPoint;
    function CanMove(a_name:string):Boolean;
    function Change(a_name: string): TPoint;
    procedure RandomArray;
    destructor Destroy; override;
  end;
implementation

{ TGameBoard }

function TGameBoard.ValidPoint(a_point: TPoint): boolean;
begin
  result := true;
  if a_point.y > GB_MAX_Y then result := false;
  if a_point.x > GB_MAX_X then result := false;
  if a_point.y < 1 then result := false;
  if a_point.x < 1 then result := false;
end;

constructor TGameBoard.Create;
var
  i, x, y : integer;
begin
  i := 1;
  for y := 1 to  GB_MAX_Y do
    for x := 1 to GB_MAX_X do
      begin
        if i < GB_MAX_BUTTONS+1
          then GameArray[x,y] := IntToStr(i)
          else GameArray[x,y] := GB_EMPTY_PLACE;
        inc(i);
      end;
  RandomArray;
end;

function TGameBoard.ButtonPlace(a_name: string): TPoint;
var
  x,y:integer;
begin
  result.x := 0;
  result.y := 0;
  for y := 1 to  GB_MAX_Y do
    for x := 1 to GB_MAX_X do
      if  GameArray[x,y] = a_name then
      begin
        result.x := x;
        result.y := y;
      end;
end;

function TGameBoard.CanMove(a_name: string): Boolean;
var
  empty, point:TPoint;
begin
  result := false;
  empty := ButtonPlace( GB_EMPTY_PLACE );
  point := ButtonPlace(a_name);
  if (abs(empty.x-point.x)=1) and (empty.y=point.y) then result := true;
  if (abs(empty.y-point.y)=1) and (empty.x=point.x) then result := true;
end;

function TGameBoard.Change(a_name: string): TPoint;
var
  empty, point:TPoint;
begin
  empty := ButtonPlace( GB_EMPTY_PLACE );
  result := empty;
  point := ButtonPlace(a_name);
  GameArray[point.x, point.y] := '-';
  GameArray[empty.x, empty.y] := a_name;
end;

procedure TGameBoard.RandomArray;
var
   j,i:integer;
   name:string;
   point,point2:TPoint;
begin
  for i := 0 to 1000 do
    begin
      j := random(4);
      point := ButtonPlace( GB_EMPTY_PLACE );
      point2 := point;
      case j of
        0: point2.x := point.x-1;
        1: point2.x := point.x+1;
        2: point2.y := point.y-1;
        3: point2.y := point.y+1;
      end;
      if ValidPoint( point2 ) then
        begin
           name :=  GameArray[point2.x, point2.y];
           GameArray[point.x, point.y] := name;
           GameArray[point2.x, point2.y] := GB_EMPTY_PLACE;
        end;
    end;
end;

destructor TGameBoard.Destroy;
begin
  inherited Destroy;
end;

end.

See also