Sign in Join
Wiki copytemporary

15-puzzle: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: 15-puzzle

OldNewLine
1+## 15-puzzle
2+
3+<figure>
4+<img src="puzzle15.png" title="puzzle15.png" />
5+<figcaption>puzzle15.png</figcaption>
6+</figure>
7+
8+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.
9+
10+## Create code
11+
12+- Create a new blank GUI application with the form [[TForm|Form1]]
13+- Change caption Form1 to *15Puzzle*'.
14+- Add New [[Unit]] [[15-puzzle|unitGameBoard.pas]]
15+- 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.
16+- Add following code:
17+
18+``` pascal
19+procedure TForm1.FormCreate(Sender: TObject);
20+var
21+ i : Integer;
22+ aButton: TButton;
23+ point:TPoint;
24+begin
25+ Randomize;
26+ Puzzle15:= TGameBoard.Create;
27+ i := 1;
28+ while i < 16 do
29+ begin //create 15 Buttons
30+ aButton:=TButton.Create(Self); //create Button, Owner is Form1, where the button is released later
31+ aButton.Parent:=Self; //determine where it is to be displayed
32+ aButton.Caption:=IntToStr(i); //Captions of the buttons
33+ aButton.Width:=aButton.Height; //Width should correspond to the height of the buttons
34+ point := Puzzle15.ButtonPlace(aButton.Caption);
35+ aButton.Left:= point.x* aButton.Width; //Distance from left
36+ aButton.Top := point.y* aButton.Height;
37+
38+ aButton.OnClick:=@aButtonClick; //the event handler for the button -> will be created yet
39+ inc(i);
40+ end;
41+ Self.Height:=aButton.Height*6; //Height of the form should correspond to the height of the buttons
42+ Self.Width:=aButton.Width*6; //Width of the form to match the width of all buttons
43+end;
44+```
45+
46+- Create in the Object Inspector the event handler for the event FormDestroy, by clicking on the button \[...\].
47+- Add the following code to the handler:
48+
49+``` pascal
50+procedure TForm1.FormDestroy(Sender: TObject);
51+begin
52+ FreeAndNil(Puzzle15);
53+end;
54+```
55+
56+- Now you must create the event handler for the button clicks.
57+- In the source editor, entering your [[Class|class]] TForm1 in the section [[Private|private]].
58+- Add [[Procedure|procedure]] `procedure aButtonClick(Sender: TObject);` and then press the keys <span class="kbd">Ctrl</span>+<span class="kbd">Shift</span>+<span class="kbd">c</span> (the code completion becomes active and creates the `procedure TForm1.aButtonClick(Sender: TObject);`.
59+- Paste following code:
60+
61+``` pascal
62+procedure TForm1.aButtonClick(Sender: TObject); //the event handler for the button
63+var
64+ i:integer;
65+ point : TPoint;
66+begin
67+ if (Sender is TButton) and //called the event handler of a button out?
68+ TryStrToInt(TButton(Sender).Caption, i) //then try to convert the label in a integer
69+ then
70+ begin
71+ if Puzzle15.CanMove(TButton(Sender).Caption) then
72+ begin
73+ point := Puzzle15.Change(TButton(Sender).Caption);
74+ TButton(Sender).Left:= point.x* TButton(Sender).Width; //Distance from left
75+ TButton(Sender).Top := point.y* TButton(Sender).Height;
76+ end;
77+ end;
78+end;
79+```
80+
81+## Source code
82+
83+### unit1.pas
84+
85+``` pascal
86+unit Unit1;
87+
88+{$mode objfpc}{$H+}
89+
90+interface
91+
92+uses
93+ Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
94+ unitGameBoard;
95+
96+type
97+
98+ { TForm1 }
99+
100+ TForm1 = class(TForm)
101+ procedure FormCreate(Sender: TObject);
102+ procedure FormDestroy(Sender: TObject);
103+ private
104+ { private declarations }
105+ Puzzle15:TGameBoard;
106+ procedure aButtonClick(Sender: TObject);
107+
108+ public
109+ { public declarations }
110+ end;
111+
112+var
113+ Form1: TForm1;
114+
115+implementation
116+
117+{$R *.lfm}
118+
119+{ TForm1 }
120+
121+procedure TForm1.FormCreate(Sender: TObject);
122+var
123+ i : Integer;
124+ aButton: TButton;
125+ point:TPoint;
126+begin
127+ Randomize;
128+ Puzzle15:= TGameBoard.Create;
129+ i := 1;
130+ while i < 16 do
131+ begin //create 15 Buttons
132+ aButton:=TButton.Create(Self); //create Button, Owner is Form1, where the button is released later
133+ aButton.Parent:=Self; //determine where it is to be displayed
134+ aButton.Caption:=IntToStr(i); //Captions of the buttons
135+ aButton.Width:=aButton.Height; //Width should correspond to the height of the buttons
136+ point := Puzzle15.ButtonPlace(aButton.Caption);
137+ aButton.Left:= point.x* aButton.Width; //Distance from left
138+ aButton.Top := point.y* aButton.Height;
139+ aButton.OnClick:=@aButtonClick; //the event handler for the button -> will be created yet
140+ inc(i);
141+ end;
142+ Self.Height:=aButton.Height*6; //Height of the form should correspond to the height of the buttons
143+ Self.Width:=aButton.Width*6; //Width of the form to match the width of all buttons
144+end;
145+
146+procedure TForm1.FormDestroy(Sender: TObject);
147+begin
148+ FreeAndNil(Puzzle15);
149+end;
150+
151+procedure TForm1.aButtonClick(Sender: TObject); //the event handler for the button
152+var
153+ i:integer;
154+ point : TPoint;
155+begin
156+ if (Sender is TButton) and //called the event handler of a button out?
157+ TryStrToInt(TButton(Sender).Caption, i) //then try to convert the label in a integer
158+ then
159+ begin
160+ if Puzzle15.CanMove(TButton(Sender).Caption) then
161+ begin
162+ point := Puzzle15.Change(TButton(Sender).Caption);
163+ TButton(Sender).Left:= point.x* TButton(Sender).Width; //Distance from left
164+ TButton(Sender).Top := point.y* TButton(Sender).Height;
165+ end;
166+ end;
167+end;
168+
169+end.
170+```
171+
172+### Unit1.lfm
173+
174+``` pascal
175+object Form1: TForm1
176+ Left = 362
177+ Height = 184
178+ Top = 162
179+ Width = 432
180+ Caption = '15Puzzle'
181+ OnCreate = FormCreate
182+ OnDestroy = FormDestroy
183+ LCLVersion = '1.6.0.4'
184+end
185+```
186+
187+### unitGameBoard.pas
188+
189+``` pascal
190+unit unitGameBoard;
191+
192+{$mode objfpc}{$H+}
193+
194+interface
195+
196+uses
197+ Classes, SysUtils;
198+
199+const
200+ GB_MAX_BUTTONS = 15;
201+ GB_MAX_X = 4;
202+ GB_MAX_Y = 4;
203+ GB_EMPTY_PLACE ='-';
204+type
205+
206+ { TGameBoard }
207+
208+ TGameBoard = class
209+ private
210+ GameArray:array[1..GB_MAX_X, 1..GB_MAX_Y] of string;
211+ function ValidPoint(a_point:TPoint):boolean;
212+ public
213+ constructor Create;
214+ function ButtonPlace(a_name:string):TPoint;
215+ function CanMove(a_name:string):Boolean;
216+ function Change(a_name: string): TPoint;
217+ procedure RandomArray;
218+ destructor Destroy; override;
219+ end;
220+implementation
221+
222+{ TGameBoard }
223+
224+function TGameBoard.ValidPoint(a_point: TPoint): boolean;
225+begin
226+ result := true;
227+ if a_point.y > GB_MAX_Y then result := false;
228+ if a_point.x > GB_MAX_X then result := false;
229+ if a_point.y < 1 then result := false;
230+ if a_point.x < 1 then result := false;
231+end;
232+
233+constructor TGameBoard.Create;
234+var
235+ i, x, y : integer;
236+begin
237+ i := 1;
238+ for y := 1 to GB_MAX_Y do
239+ for x := 1 to GB_MAX_X do
240+ begin
241+ if i < GB_MAX_BUTTONS+1
242+ then GameArray[x,y] := IntToStr(i)
243+ else GameArray[x,y] := GB_EMPTY_PLACE;
244+ inc(i);
245+ end;
246+ RandomArray;
247+end;
248+
249+function TGameBoard.ButtonPlace(a_name: string): TPoint;
250+var
251+ x,y:integer;
252+begin
253+ result.x := 0;
254+ result.y := 0;
255+ for y := 1 to GB_MAX_Y do
256+ for x := 1 to GB_MAX_X do
257+ if GameArray[x,y] = a_name then
258+ begin
259+ result.x := x;
260+ result.y := y;
261+ end;
262+end;
263+
264+function TGameBoard.CanMove(a_name: string): Boolean;
265+var
266+ empty, point:TPoint;
267+begin
268+ result := false;
269+ empty := ButtonPlace( GB_EMPTY_PLACE );
270+ point := ButtonPlace(a_name);
271+ if (abs(empty.x-point.x)=1) and (empty.y=point.y) then result := true;
272+ if (abs(empty.y-point.y)=1) and (empty.x=point.x) then result := true;
273+end;
274+
275+function TGameBoard.Change(a_name: string): TPoint;
276+var
277+ empty, point:TPoint;
278+begin
279+ empty := ButtonPlace( GB_EMPTY_PLACE );
280+ result := empty;
281+ point := ButtonPlace(a_name);
282+ GameArray[point.x, point.y] := '-';
283+ GameArray[empty.x, empty.y] := a_name;
284+end;
285+
286+procedure TGameBoard.RandomArray;
287+var
288+ j,i:integer;
289+ name:string;
290+ point,point2:TPoint;
291+begin
292+ for i := 0 to 1000 do
293+ begin
294+ j := random(4);
295+ point := ButtonPlace( GB_EMPTY_PLACE );
296+ point2 := point;
297+ case j of
298+ 0: point2.x := point.x-1;
299+ 1: point2.x := point.x+1;
300+ 2: point2.y := point.y-1;
301+ 3: point2.y := point.y+1;
302+ end;
303+ if ValidPoint( point2 ) then
304+ begin
305+ name := GameArray[point2.x, point2.y];
306+ GameArray[point.x, point.y] := name;
307+ GameArray[point2.x, point2.y] := GB_EMPTY_PLACE;
308+ end;
309+ end;
310+end;
311+
312+destructor TGameBoard.Destroy;
313+begin
314+ inherited Destroy;
315+end;
316+
317+end.
318+```
319+
320+## See also
321+
322+- [[TButton]]
323+
324+---
325+*From the Free Pascal wiki, page "15-puzzle", as it stood on 2022-08-06 after a change by Kai Burghardt, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history