Sign in Join
Wiki copytemporary

15-puzzle: what changed

Revision 2 to 3. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11## 15-puzzle
22
33![](/wiki-images/2/20/Puzzle15.png)
44
55The 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.
66
77## Create code
88
99- Create a new blank GUI application with the form [[TForm|Form1]]
1010- Change caption Form1 to *15Puzzle*'.
1111- Add New [[Unit]] [[15-puzzle|unitGameBoard.pas]]
1212- 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.
1313- Add following code:
1414
1515``` pascal
1616procedure TForm1.FormCreate(Sender: TObject);
1717var
1818 i : Integer;
1919 aButton: TButton;
2020 point:TPoint;
2121begin
2222 Randomize;
2323 Puzzle15:= TGameBoard.Create;
2424 i := 1;
2525 while i < 16 do
2626 begin //create 15 Buttons
2727 aButton:=TButton.Create(Self); //create Button, Owner is Form1, where the button is released later
2828 aButton.Parent:=Self; //determine where it is to be displayed
2929 aButton.Caption:=IntToStr(i); //Captions of the buttons
3030 aButton.Width:=aButton.Height; //Width should correspond to the height of the buttons
3131 point := Puzzle15.ButtonPlace(aButton.Caption);
3232 aButton.Left:= point.x* aButton.Width; //Distance from left
3333 aButton.Top := point.y* aButton.Height;
3434
3535 aButton.OnClick:=@aButtonClick; //the event handler for the button -> will be created yet
3636 inc(i);
3737 end;
3838 Self.Height:=aButton.Height*6; //Height of the form should correspond to the height of the buttons
3939 Self.Width:=aButton.Width*6; //Width of the form to match the width of all buttons
4040end;
4141```
4242
4343- Create in the Object Inspector the event handler for the event FormDestroy, by clicking on the button \[...\].
4444- Add the following code to the handler:
4545
4646``` pascal
4747procedure TForm1.FormDestroy(Sender: TObject);
4848begin
4949 FreeAndNil(Puzzle15);
5050end;
5151```
5252
5353- Now you must create the event handler for the button clicks.
5454- In the source editor, entering your [[Class|class]] TForm1 in the section [[Private|private]].
5555- Add [[Procedure|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);`.
5656- Paste following code:
5757
5858``` pascal
5959procedure TForm1.aButtonClick(Sender: TObject); //the event handler for the button
6060var
6161 i:integer;
6262 point : TPoint;
6363begin
6464 if (Sender is TButton) and //called the event handler of a button out?
6565 TryStrToInt(TButton(Sender).Caption, i) //then try to convert the label in a integer
6666 then
6767 begin
6868 if Puzzle15.CanMove(TButton(Sender).Caption) then
6969 begin
7070 point := Puzzle15.Change(TButton(Sender).Caption);
7171 TButton(Sender).Left:= point.x* TButton(Sender).Width; //Distance from left
7272 TButton(Sender).Top := point.y* TButton(Sender).Height;
7373 end;
7474 end;
7575end;
7676```
7777
7878## Source code
7979
8080### unit1.pas
8181
8282``` pascal
8383unit Unit1;
8484
8585{$mode objfpc}{$H+}
8686
8787interface
8888
8989uses
9090 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
9191 unitGameBoard;
9292
9393type
9494
9595 { TForm1 }
9696
9797 TForm1 = class(TForm)
9898 procedure FormCreate(Sender: TObject);
9999 procedure FormDestroy(Sender: TObject);
100100 private
101101 { private declarations }
102102 Puzzle15:TGameBoard;
103103 procedure aButtonClick(Sender: TObject);
104104
105105 public
106106 { public declarations }
107107 end;
108108
109109var
110110 Form1: TForm1;
111111
112112implementation
113113
114114{$R *.lfm}
115115
116116{ TForm1 }
117117
118118procedure TForm1.FormCreate(Sender: TObject);
119119var
120120 i : Integer;
121121 aButton: TButton;
122122 point:TPoint;
123123begin
124124 Randomize;
125125 Puzzle15:= TGameBoard.Create;
126126 i := 1;
127127 while i < 16 do
128128 begin //create 15 Buttons
129129 aButton:=TButton.Create(Self); //create Button, Owner is Form1, where the button is released later
130130 aButton.Parent:=Self; //determine where it is to be displayed
131131 aButton.Caption:=IntToStr(i); //Captions of the buttons
132132 aButton.Width:=aButton.Height; //Width should correspond to the height of the buttons
133133 point := Puzzle15.ButtonPlace(aButton.Caption);
134134 aButton.Left:= point.x* aButton.Width; //Distance from left
135135 aButton.Top := point.y* aButton.Height;
136136 aButton.OnClick:=@aButtonClick; //the event handler for the button -> will be created yet
137137 inc(i);
138138 end;
139139 Self.Height:=aButton.Height*6; //Height of the form should correspond to the height of the buttons
140140 Self.Width:=aButton.Width*6; //Width of the form to match the width of all buttons
141141end;
142142
143143procedure TForm1.FormDestroy(Sender: TObject);
144144begin
145145 FreeAndNil(Puzzle15);
146146end;
147147
148148procedure TForm1.aButtonClick(Sender: TObject); //the event handler for the button
149149var
150150 i:integer;
151151 point : TPoint;
152152begin
153153 if (Sender is TButton) and //called the event handler of a button out?
154154 TryStrToInt(TButton(Sender).Caption, i) //then try to convert the label in a integer
155155 then
156156 begin
157157 if Puzzle15.CanMove(TButton(Sender).Caption) then
158158 begin
159159 point := Puzzle15.Change(TButton(Sender).Caption);
160160 TButton(Sender).Left:= point.x* TButton(Sender).Width; //Distance from left
161161 TButton(Sender).Top := point.y* TButton(Sender).Height;
162162 end;
163163 end;
164164end;
165165
166166end.
167167```
168168
169169### Unit1.lfm
170170
171-``` pascal
171+``` lfm
172172object Form1: TForm1
173173 Left = 362
174174 Height = 184
175175 Top = 162
176176 Width = 432
177177 Caption = '15Puzzle'
178178 OnCreate = FormCreate
179179 OnDestroy = FormDestroy
180180 LCLVersion = '1.6.0.4'
181181end
182182```
183183
184184### unitGameBoard.pas
185185
186186``` pascal
187187unit unitGameBoard;
188188
189189{$mode objfpc}{$H+}
190190
191191interface
192192
193193uses
194194 Classes, SysUtils;
195195
196196const
197197 GB_MAX_BUTTONS = 15;
198198 GB_MAX_X = 4;
199199 GB_MAX_Y = 4;
200200 GB_EMPTY_PLACE ='-';
201201type
202202
203203 { TGameBoard }
204204
205205 TGameBoard = class
206206 private
207207 GameArray:array[1..GB_MAX_X, 1..GB_MAX_Y] of string;
208208 function ValidPoint(a_point:TPoint):boolean;
209209 public
210210 constructor Create;
211211 function ButtonPlace(a_name:string):TPoint;
212212 function CanMove(a_name:string):Boolean;
213213 function Change(a_name: string): TPoint;
214214 procedure RandomArray;
215215 destructor Destroy; override;
216216 end;
217217implementation
218218
219219{ TGameBoard }
220220
221221function TGameBoard.ValidPoint(a_point: TPoint): boolean;
222222begin
223223 result := true;
224224 if a_point.y > GB_MAX_Y then result := false;
225225 if a_point.x > GB_MAX_X then result := false;
226226 if a_point.y < 1 then result := false;
227227 if a_point.x < 1 then result := false;
228228end;
229229
230230constructor TGameBoard.Create;
231231var
232232 i, x, y : integer;
233233begin
234234 i := 1;
235235 for y := 1 to GB_MAX_Y do
236236 for x := 1 to GB_MAX_X do
237237 begin
238238 if i < GB_MAX_BUTTONS+1
239239 then GameArray[x,y] := IntToStr(i)
240240 else GameArray[x,y] := GB_EMPTY_PLACE;
241241 inc(i);
242242 end;
243243 RandomArray;
244244end;
245245
246246function TGameBoard.ButtonPlace(a_name: string): TPoint;
247247var
248248 x,y:integer;
249249begin
250250 result.x := 0;
251251 result.y := 0;
252252 for y := 1 to GB_MAX_Y do
253253 for x := 1 to GB_MAX_X do
254254 if GameArray[x,y] = a_name then
255255 begin
256256 result.x := x;
257257 result.y := y;
258258 end;
259259end;
260260
261261function TGameBoard.CanMove(a_name: string): Boolean;
262262var
263263 empty, point:TPoint;
264264begin
265265 result := false;
266266 empty := ButtonPlace( GB_EMPTY_PLACE );
267267 point := ButtonPlace(a_name);
268268 if (abs(empty.x-point.x)=1) and (empty.y=point.y) then result := true;
269269 if (abs(empty.y-point.y)=1) and (empty.x=point.x) then result := true;
270270end;
271271
272272function TGameBoard.Change(a_name: string): TPoint;
273273var
274274 empty, point:TPoint;
275275begin
276276 empty := ButtonPlace( GB_EMPTY_PLACE );
277277 result := empty;
278278 point := ButtonPlace(a_name);
279279 GameArray[point.x, point.y] := '-';
280280 GameArray[empty.x, empty.y] := a_name;
281281end;
282282
283283procedure TGameBoard.RandomArray;
284284var
285285 j,i:integer;
286286 name:string;
287287 point,point2:TPoint;
288288begin
289289 for i := 0 to 1000 do
290290 begin
291291 j := random(4);
292292 point := ButtonPlace( GB_EMPTY_PLACE );
293293 point2 := point;
294294 case j of
295295 0: point2.x := point.x-1;
296296 1: point2.x := point.x+1;
297297 2: point2.y := point.y-1;
298298 3: point2.y := point.y+1;
299299 end;
300300 if ValidPoint( point2 ) then
301301 begin
302302 name := GameArray[point2.x, point2.y];
303303 GameArray[point.x, point.y] := name;
304304 GameArray[point2.x, point2.y] := GB_EMPTY_PLACE;
305305 end;
306306 end;
307307end;
308308
309309destructor TGameBoard.Destroy;
310310begin
311311 inherited Destroy;
312312end;
313313
314314end.
315315```
316316
317317## See also
318318
319319- [[TButton]]
320320
321321---
322322*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