source: tags/1.0.0/UGame.pas

Last change on this file was 21, checked in by chronos, 5 years ago
  • Added: Debian packaging information.
File size: 19.3 KB
Line 
1unit UGame;
2
3{$mode delphi}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, Dialogs, fgl, Graphics, Types, Forms, Math, DateUtils,
9 Controls, URegistry;
10
11type
12
13 { TTile }
14
15 TTile = class
16 Value: Integer;
17 NewValue: Integer;
18 Merged: Boolean;
19 Moving: Boolean;
20 Shift: TPoint;
21 procedure Assign(Source: TTile);
22 end;
23
24 TTiles = class(TFPGObjectList<TTile>)
25 end;
26
27 { TBoard }
28
29 TBoard = class
30 private
31 FSize: TPoint;
32 procedure SetSize(AValue: TPoint);
33 public
34 Tiles: array of array of TTile;
35 procedure Assign(Source: TBoard);
36 procedure Clear;
37 procedure ClearMerged;
38 function GetHighestTileValue: Integer;
39 function GetEmptyTilesCount: Integer;
40 procedure GetEmptyTiles(EmptyTiles: TTiles);
41 procedure SaveToRegistry(RegContext: TRegistryContext);
42 procedure LoadFromRegistry(RegContext: TRegistryContext);
43 destructor Destroy; override;
44 property Size: TPoint read FSize write SetSize;
45 end;
46
47 TDirection = (drLeft, drUp, drRight, drDown);
48
49 { TGame }
50
51 TGame = class
52 private
53 FMoving: Boolean;
54 FOnChange: TNotifyEvent;
55 FRunning: Boolean;
56 FScore: Integer;
57 FCanUndo: Boolean;
58 FBoardUndo: TBoard;
59 function CanMoveDirection(Direction: TDirection): Boolean;
60 function GetTileColor(Value: Integer): TColor;
61 procedure SetScore(AValue: Integer);
62 procedure DoChange;
63 procedure RenderTile(Canvas: TCanvas; Tile: TTile; TileRect: TRect);
64 procedure GameOver;
65 procedure Win;
66 function FillRandomTile: Integer;
67 public
68 Board: TBoard;
69 TopScore: Integer;
70 AnimationDuration: Integer;
71 WinScore: Integer;
72 function CanUndo: Boolean;
73 procedure Undo;
74 function CanMove: Boolean;
75 procedure Assign(Source: TGame);
76 procedure New;
77 procedure Render(Canvas: TCanvas; CanvasSize: TPoint);
78 function MoveAll(Direction: TDirection): Integer;
79 procedure MoveTile(SourceTile, TargetTile: TTile);
80 function IsValidPos(Pos: TPoint): Boolean;
81 procedure SaveToRegistry(RegContext: TRegistryContext);
82 procedure LoadFromRegistry(RegContext: TRegistryContext);
83 constructor Create;
84 destructor Destroy; override;
85 property Score: Integer read FScore write SetScore;
86 property Running: Boolean read FRunning write FRunning;
87 property OnChange: TNotifyEvent read FOnChange write FOnChange;
88 property Moving: Boolean read FMoving;
89 end;
90
91const
92 DirectionDiff: array[TDirection] of TPoint = (
93 (X: -1; Y: 0), (X: 0; Y: -1), (X: 1; Y: 0), (X: 0; Y: 1)
94 );
95
96resourcestring
97 SGameOverCaption = 'Lost';
98 SGameOverMessage = 'Game over!';
99 SWinCaption = 'Win';
100 SWinMessage = 'You reached %d and won! You can continue to play to get higher score.';
101 SScore = 'Score';
102 STopScore = 'Top score';
103
104implementation
105
106{ TBoard }
107
108procedure TBoard.SetSize(AValue: TPoint);
109var
110 X, Y: Integer;
111begin
112 if FSize = AValue then Exit;
113 for Y := 0 to FSize.Y - 1 do
114 for X := 0 to FSize.X - 1 do
115 Tiles[Y, X].Free;
116 FSize := AValue;
117 SetLength(Tiles, FSize.Y, FSize.X);
118 for Y := 0 to FSize.Y - 1 do
119 for X := 0 to FSize.X - 1 do
120 Tiles[Y, X] := TTile.Create;
121end;
122
123procedure TBoard.Assign(Source: TBoard);
124var
125 X, Y: Integer;
126begin
127 Size := Source.Size;
128 for Y := 0 to Size.Y - 1 do
129 for X := 0 to Size.X - 1 do
130 Tiles[Y, X].Assign(Source.Tiles[Y, X]);
131end;
132
133procedure TBoard.GetEmptyTiles(EmptyTiles: TTiles);
134var
135 X, Y: Integer;
136begin
137 EmptyTiles.Clear;
138 for Y := 0 to Size.Y - 1 do
139 for X := 0 to Size.X - 1 do
140 if Tiles[Y, X].Value = 0 then
141 EmptyTiles.Add(Tiles[Y, X]);
142end;
143
144procedure TBoard.SaveToRegistry(RegContext: TRegistryContext);
145var
146 X, Y: Integer;
147 Value: string;
148begin
149 with TRegistryEx.Create do
150 try
151 CurrentContext := RegContext;
152
153 WriteInteger('SizeX', Size.X);
154 WriteInteger('SizeY', Size.Y);
155 Value := '';
156 for Y := 0 to Size.Y - 1 do begin
157 for X := 0 to Size.X - 1 do begin
158 Value := Value + IntToStr(Tiles[Y, X].Value);
159 if X < Size.X - 1 then Value := Value + ',';
160 end;
161 if Y < Size.Y - 1 then Value := Value + ';'
162 end;
163 WriteString('TileValues', Value);
164 finally
165 Free;
166 end;
167end;
168
169procedure TBoard.LoadFromRegistry(RegContext: TRegistryContext);
170var
171 X, Y: Integer;
172 Items: TStringList;
173 Lines: TStringList;
174 Number: Integer;
175begin
176 with TRegistryEx.Create do
177 try
178 CurrentContext := RegContext;
179
180 Size := Point(ReadIntegerWithDefault('SizeX', 4), ReadIntegerWithDefault('SizeY', 4));
181 Items := TStringList.Create;
182 Items.Delimiter := ',';
183 Lines := TStringList.Create;
184 Lines.Delimiter := ';';
185 Lines.DelimitedText := ReadStringWithDefault('TileValues', '');
186 for Y := 0 to Lines.Count - 1 do begin
187 Items.DelimitedText := Lines[Y];
188 for X := 0 to Items.Count - 1 do begin
189 if TryStrToInt(Items[X], Number) and (X < Size.X) and (Y < Size.Y) then
190 Tiles[Y, X].Value := Number;
191 end;
192 end;
193 finally
194 Free;
195 end;
196end;
197
198destructor TBoard.Destroy;
199begin
200 Size := Point(0, 0);
201 inherited Destroy;
202end;
203
204procedure TBoard.ClearMerged;
205var
206 X, Y: Integer;
207begin
208 for Y := 0 to Size.Y - 1 do
209 for X := 0 to Size.X - 1 do
210 Tiles[Y, X].Merged := False;
211end;
212
213function TBoard.GetEmptyTilesCount: Integer;
214var
215 X, Y: Integer;
216begin
217 Result := 0;
218 for Y := 0 to Size.Y - 1 do
219 for X := 0 to Size.X - 1 do
220 if Tiles[Y, X].Value = 0 then
221 Inc(Result);
222end;
223
224function TBoard.GetHighestTileValue: Integer;
225var
226 X, Y: Integer;
227begin
228 Result := 0;
229 for Y := 0 to Size.Y - 1 do
230 for X := 0 to Size.X - 1 do
231 if Result < Tiles[Y, X].Value then Result := Tiles[Y, X].Value;
232end;
233
234procedure TBoard.Clear;
235var
236 X, Y: Integer;
237begin
238 for Y := 0 to Size.Y - 1 do
239 for X := 0 to Size.X - 1 do
240 Tiles[Y, X].Value := 0;
241end;
242
243
244{ TTile }
245
246procedure TTile.Assign(Source: TTile);
247begin
248 Value := Source.Value;
249 Merged := Source.Merged;
250end;
251
252{ TGame }
253
254procedure TGame.DoChange;
255begin
256 if Assigned(FOnChange) then FOnChange(Self);
257end;
258
259procedure TGame.GameOver;
260begin
261 if Running then MessageDlg(SGameOverCaption, SGameOverMessage, mtInformation, [mbOK], 0);
262 Running := False;
263end;
264
265procedure TGame.Win;
266begin
267 MessageDlg(SWinCaption, Format(SWinMessage, [WinScore]), mtInformation, [mbOk], 0);
268end;
269
270function TGame.FillRandomTile: Integer;
271var
272 EmptyTiles: TTiles;
273begin
274 Result := 0;
275 EmptyTiles := TTiles.Create(False);
276 Board.GetEmptyTiles(EmptyTiles);
277 if EmptyTiles.Count > 0 then begin
278 EmptyTiles[Random(EmptyTiles.Count)].Value := 2;
279 Result := 1;
280 end;
281 EmptyTiles.Free;
282end;
283
284function TGame.CanMove: Boolean;
285begin
286 Result := CanMoveDirection(drLeft) or CanMoveDirection(drRight) or
287 CanMoveDirection(drUp) or CanMoveDirection(drDown);
288end;
289
290procedure TGame.Assign(Source: TGame);
291begin
292 FScore := Source.FScore;
293 TopScore := Source.TopScore;
294 AnimationDuration := Source.AnimationDuration;
295 Board.Assign(Source.Board);
296end;
297
298procedure TGame.New;
299var
300 I: Integer;
301begin
302 FCanUndo := False;
303 Board.Clear;
304 Score := 0;
305 Running := True;
306 for I := 0 to 1 do FillRandomTile;
307 DoChange;
308end;
309
310procedure TGame.Render(Canvas: TCanvas; CanvasSize: TPoint);
311var
312 X, Y: Integer;
313 TileSize: TPoint;
314 ValueStr: string;
315 Frame: TRect;
316 TileRect: TRect;
317 TopBarHeight: Integer;
318 TileMargin: Integer;
319begin
320 TopBarHeight := ScaleY(24, 96);
321 TileMargin := Round(CanvasSize.X / Board.Size.X * 0.02);
322 Canvas.Brush.Style := bsSolid;
323 Canvas.Brush.Color := clBlack;
324 Canvas.FillRect(0, 0, Canvas.Width, Canvas.Height);
325
326 ValueStr := SScore + ': ' + IntToStr(Score);
327 Canvas.Font.Color := clWhite;
328 Canvas.Font.Height := Trunc(TopBarHeight * 0.7);
329 Canvas.TextOut(ScaleY(16, 96), (TopBarHeight - Canvas.TextHeight(ValueStr)) div 2, ValueStr);
330
331 ValueStr := STopScore + ': ' + IntToStr(TopScore);
332 Canvas.Font.Color := clWhite;
333 Canvas.Font.Height := Trunc(TopBarHeight * 0.7);
334 Canvas.TextOut(ScaleY(136, 96), (TopBarHeight - Canvas.TextHeight(ValueStr)) div 2, ValueStr);
335
336 // Form.Canvas.Width and Form.Canvas.Height is not working correctly under Windows.
337 // So dimensions are provided by CanvasSize parameter.
338 Frame := Rect(2, TopBarHeight, CanvasSize.X - 2, CanvasSize.Y - 2);
339 TileSize := Point(Frame.Width div Board.Size.X, Frame.Height div Board.Size.Y);
340 if TileSize.X < TileSize.Y then TileSize.Y := TileSize.X;
341 if TileSize.Y < TileSize.X then TileSize.X := TileSize.Y;
342 Frame := Rect(Frame.Width div 2 - (Board.Size.X * TileSize.X) div 2,
343 Frame.Top + Frame.Height div 2 - (Board.Size.Y * TileSize.Y) div 2,
344 Frame.Width div 2 + (Board.Size.X * TileSize.X) div 2,
345 Frame.Top + Frame.Height div 2 + (Board.Size.Y * TileSize.Y) div 2);
346
347 Canvas.Brush.Style := bsSolid;
348 Canvas.Brush.Color := clGray;
349 Canvas.FillRect(Frame);
350
351 Canvas.Font.Color := clBlack;
352
353 // Draw static tiles
354 for Y := 0 to Board.Size.Y - 1 do
355 for X := 0 to Board.Size.X - 1 do begin
356 if Board.Tiles[Y, X].Moving then Canvas.Brush.Color := GetTileColor(0)
357 else Canvas.Brush.Color := GetTileColor(Board.Tiles[Y, X].Value);
358 Canvas.Brush.Style := bsSolid;
359 TileRect := Bounds(
360 Frame.Left + X * TileSize.X + TileMargin,
361 Frame.Top + Y * TileSize.Y + TileMargin,
362 TileSize.X - 2 * TileMargin, TileSize.Y - 2 * TileMargin);
363 RenderTile(Canvas, Board.Tiles[Y, X], TileRect);
364 end;
365
366 // Draw moving Tiles
367 for Y := 0 to Board.Size.Y - 1 do
368 for X := 0 to Board.Size.X - 1 do
369 if Board.Tiles[Y, X].Moving then begin
370 Canvas.Brush.Color := GetTileColor(Board.Tiles[Y, X].Value);
371 Canvas.Brush.Style := bsSolid;
372 TileRect := Bounds(
373 Frame.Left + X * TileSize.X + Trunc(Board.Tiles[Y, X].Shift.X / 100 * TileSize.X + TileMargin),
374 Frame.Top + Y * TileSize.Y + Trunc(Board.Tiles[Y, X].Shift.Y / 100 * TileSize.Y + TileMargin),
375 TileSize.X - 2 * TileMargin, TileSize.Y - 2 * TileMargin);
376 RenderTile(Canvas, Board.Tiles[Y, X], TileRect);
377 end;
378end;
379
380procedure TGame.RenderTile(Canvas: TCanvas; Tile: TTile; TileRect: TRect);
381var
382 ValueStr: string;
383 TextSize: TSize;
384begin
385 Canvas.FillRect(TileRect);
386 if Tile.Value <> 0 then begin
387 ValueStr := IntToStr(Tile.Value);
388 Canvas.Brush.Style := bsClear;
389 Canvas.Font.Height := Trunc(TileRect.Height * 0.7);
390 TextSize := Canvas.TextExtent(ValueStr);
391 if TextSize.Width > TileRect.Width then
392 Canvas.Font.Height := Trunc(Canvas.Font.Height / TextSize.Width * TileRect.Width);
393 TextSize := Canvas.TextExtent(ValueStr);
394 Canvas.TextOut(TileRect.Left + TileRect.Width div 2 - TextSize.Width div 2,
395 TileRect.Top + TileRect.Height div 2 - TextSize.Height div 2, ValueStr);
396 end;
397end;
398
399function TGame.CanUndo: Boolean;
400begin
401 Result := FCanUndo;
402end;
403
404procedure TGame.Undo;
405begin
406 if CanUndo then begin
407 Board.Assign(FBoardUndo);
408 FCanUndo := False;
409 FRunning := CanMove;
410 DoChange;
411 end;
412end;
413
414function TGame.CanMoveDirection(Direction: TDirection): Boolean;
415var
416 StartPoint: TPoint;
417 AreaSize: TPoint;
418 Increment: TPoint;
419 P: TPoint;
420 PNew: TPoint;
421 PI: TPoint;
422begin
423 Result := False;
424 case Direction of
425 drLeft: begin
426 StartPoint := Point(1, 0);
427 AreaSize := Point(Board.Size.X - 2, Board.Size.Y - 1);
428 Increment := Point(1, 1);
429 end;
430 drUp: begin
431 StartPoint := Point(0, 1);
432 AreaSize := Point(Board.Size.X - 1, Board.Size.Y - 2);
433 Increment := Point(1, 1);
434 end;
435 drRight: begin
436 StartPoint := Point(Board.Size.X - 2, 0);
437 AreaSize := Point(Board.Size.X - 2, Board.Size.Y - 1);
438 Increment := Point(-1, 1);
439 end;
440 drDown: begin
441 StartPoint := Point(0, Board.Size.Y - 2);
442 AreaSize := Point(Board.Size.X - 1, Board.Size.Y - 2);
443 Increment := Point(1, -1);
444 end;
445 end;
446
447 PI.Y := 0;
448 while PI.Y <= AreaSize.Y do begin
449 PI.X := 0;
450 while PI.X <= AreaSize.X do begin
451 P := Point(StartPoint.X + PI.X * Increment.X, StartPoint.Y + PI.Y * Increment.Y);
452 PNew.X := P.X + DirectionDiff[Direction].X;
453 PNew.Y := P.Y + DirectionDiff[Direction].Y;
454 if IsValidPos(PNew) then begin
455 if (Board.Tiles[P.Y, P.X].Value <> 0) then begin
456 if (Board.Tiles[PNew.Y, PNew.X].Value = 0) or
457 (Board.Tiles[PNew.Y, PNew.X].Value = Board.Tiles[P.Y, P.X].Value) then begin
458 Result := True;
459 Break;
460 end;
461 end;
462 P.X := PNew.X;
463 P.Y := PNew.Y;
464 PNew.X := P.X + DirectionDiff[Direction].X;
465 PNew.Y := P.Y + DirectionDiff[Direction].Y;
466 end;
467 Inc(PI.X);
468 end;
469 if Result then Break;
470 Inc(PI.Y);
471 end;
472end;
473
474function TGame.MoveAll(Direction: TDirection): Integer;
475var
476 StartPoint: TPoint;
477 AreaSize: TPoint;
478 Increment: TPoint;
479 MoveDirection: TPoint;
480 P: TPoint;
481 PNew: TPoint;
482 PI: TPoint;
483 MovedCount: Integer;
484 X, Y: Integer;
485 I: Integer;
486 StartTime: TDateTime;
487 EndTime: TDateTime;
488 Time: TDateTime;
489 Part: Double;
490 HighestValue: Integer;
491begin
492 FMoving := True;
493 HighestValue := Board.GetHighestTileValue;
494 FBoardUndo.Assign(Board);
495 FCanUndo := True;
496 //Diff := DirectionDiff[Direction];
497 case Direction of
498 drLeft: begin
499 StartPoint := Point(1, 0);
500 AreaSize := Point(Board.Size.X - 2, Board.Size.Y - 1);
501 Increment := Point(1, 1);
502 MoveDirection := Point(-1, 0);
503 end;
504 drUp: begin
505 StartPoint := Point(0, 1);
506 AreaSize := Point(Board.Size.X - 1, Board.Size.Y - 2);
507 Increment := Point(1, 1);
508 MoveDirection := Point(0, -1);
509 end;
510 drRight: begin
511 StartPoint := Point(Board.Size.X - 2, 0);
512 AreaSize := Point(Board.Size.X - 2, Board.Size.Y - 1);
513 Increment := Point(-1, 1);
514 MoveDirection := Point(1, 0);
515 end;
516 drDown: begin
517 StartPoint := Point(0, Board.Size.Y - 2);
518 AreaSize := Point(Board.Size.X - 1, Board.Size.Y - 2);
519 Increment := Point(1, -1);
520 MoveDirection := Point(0, 1);
521 end;
522 end;
523 MovedCount := 0;
524 Board.ClearMerged;
525 for I := 0 to Max(Board.Size.X, Board.Size.Y) - 1 do begin
526 PI.Y := 0;
527 for Y := 0 to Board.Size.Y - 1 do
528 for X := 0 to Board.Size.X - 1 do begin
529 Board.Tiles[Y, X].NewValue := Board.Tiles[Y, X].Value;
530 Board.Tiles[Y, X].Moving := False;
531 end;
532
533 while PI.Y <= AreaSize.Y do begin
534 PI.X := 0;
535 while PI.X <= AreaSize.X do begin
536 P := Point(StartPoint.X + PI.X * Increment.X, StartPoint.Y + PI.Y * Increment.Y);
537 PNew.X := P.X + DirectionDiff[Direction].X;
538 PNew.Y := P.Y + DirectionDiff[Direction].Y;
539 if IsValidPos(PNew) then begin
540 if (Board.Tiles[P.Y, P.X].NewValue <> 0) then begin
541 if (Board.Tiles[PNew.Y, PNew.X].NewValue = 0) then begin
542 Board.Tiles[P.Y, P.X].Moving := True;
543 Board.Tiles[PNew.Y, PNew.X].NewValue := Board.Tiles[P.Y, P.X].NewValue;
544 Board.Tiles[PNew.Y, PNew.X].Merged := Board.Tiles[P.Y, P.X].Merged;
545 Board.Tiles[P.Y, P.X].NewValue := 0;
546 Board.Tiles[P.Y, P.X].Merged := False;
547 Inc(MovedCount);
548 end else
549 if (not Board.Tiles[P.Y, P.X].Merged) and (not Board.Tiles[PNew.Y, PNew.X].Merged) and
550 (Board.Tiles[PNew.Y, PNew.X].NewValue = Board.Tiles[P.Y, P.X].NewValue) then begin
551 Board.Tiles[P.Y, P.X].Moving := True;
552 Board.Tiles[PNew.Y, PNew.X].NewValue := Board.Tiles[PNew.Y, PNew.X].NewValue + Board.Tiles[P.Y, P.X].NewValue;
553 Board.Tiles[PNew.Y, PNew.X].Merged := True;
554 Board.Tiles[P.Y, P.X].NewValue := 0;
555 Board.Tiles[P.Y, P.X].Merged := False;
556 Inc(MovedCount);
557 Score := Score + Board.Tiles[PNew.Y, PNew.X].NewValue;
558 end;
559 end;
560 P.X := PNew.X;
561 P.Y := PNew.Y;
562 PNew.X := P.X + DirectionDiff[Direction].X;
563 PNew.Y := P.Y + DirectionDiff[Direction].Y;
564 end;
565 Inc(PI.X);
566 end;
567 Inc(PI.Y);
568 end;
569
570 // Animate tiles move
571 StartTime := Now;
572 EndTime := StartTime + AnimationDuration / 300 * OneSecond / Max(Board.Size.X, Board.Size.Y);
573 if AnimationDuration > 0 then
574 repeat
575 Time := Now;
576 Part := (Time - StartTime) / (EndTime - StartTime);
577 if Part > 1 then Part := 1;
578 for Y := 0 to Board.Size.Y - 1 do
579 for X := 0 to Board.Size.X - 1 do begin
580 if Board.Tiles[Y, X].Moving then
581 Board.Tiles[Y, X].Shift := Point(Trunc(Part * MoveDirection.X * 100),
582 Trunc(Part * MoveDirection.Y * 100));
583 end;
584 DoChange;
585 Application.ProcessMessages;
586 Sleep(1);
587 until Time > EndTime;
588
589 // Set final tiles values
590 for Y := 0 to Board.Size.Y - 1 do
591 for X := 0 to Board.Size.X - 1 do begin
592 Board.Tiles[Y, X].Shift := Point(0, 0);
593 Board.Tiles[Y, X].Moving := False;
594 Board.Tiles[Y, X].Value := Board.Tiles[Y, X].NewValue;
595 end;
596 DoChange;
597 end;
598 Result := MovedCount;
599
600 // Update state after move
601 if MovedCount > 0 then FillRandomTile;
602 if not CanMove and (Board.GetEmptyTilesCount = 0) then
603 GameOver;
604 if (HighestValue < WinScore) and
605 (Board.GetHighestTileValue >= WinScore) then Win;
606
607 FMoving := False;
608end;
609
610procedure TGame.MoveTile(SourceTile, TargetTile: TTile);
611begin
612 TargetTile.Value := SourceTile.Value;
613 SourceTile.Value := 0;
614 TargetTile.Merged := SourceTile.Merged;
615 SourceTile.Merged := False;
616end;
617
618function TGame.IsValidPos(Pos: TPoint): Boolean;
619begin
620 Result := (Pos.X >= 0) and (Pos.X < Board.Size.X) and
621 (Pos.Y >= 0) and (Pos.Y < Board.Size.Y);
622end;
623
624procedure TGame.SaveToRegistry(RegContext: TRegistryContext);
625begin
626 with TRegistryEx.Create do
627 try
628 CurrentContext := RegContext;
629
630 WriteInteger('TopScore', TopScore);
631 WriteInteger('AnimationDuration', AnimationDuration);
632 WriteInteger('Score', Score);
633 WriteBool('GameRunning', FRunning);
634 WriteBool('CanUndo', FCanUndo);
635 finally
636 Free;
637 end;
638 FBoardUndo.SaveToRegistry(TRegistryContext.Create(RegContext.RootKey, RegContext.Key + '\BoardUndo'));
639 Board.SaveToRegistry(TRegistryContext.Create(RegContext.RootKey, RegContext.Key + '\Board'));
640end;
641
642procedure TGame.LoadFromRegistry(RegContext: TRegistryContext);
643begin
644 with TRegistryEx.Create do
645 try
646 CurrentContext := RegContext;
647 AnimationDuration := ReadIntegerWithDefault('AnimationDuration', 30);
648 TopScore := ReadIntegerWithDefault('TopScore', 0);
649 Score := ReadIntegerWithDefault('Score', 0);
650 FRunning := ReadBoolWithDefault('GameRunning', False);
651 FCanUndo := ReadBoolWithDefault('CanUndo', False);
652 finally
653 Free;
654 end;
655 FBoardUndo.LoadFromRegistry(TRegistryContext.Create(RegContext.RootKey, RegContext.Key + '\BoardUndo'));
656 Board.LoadFromRegistry(TRegistryContext.Create(RegContext.RootKey, RegContext.Key + '\Board'));
657 DoChange;
658end;
659
660constructor TGame.Create;
661begin
662 AnimationDuration := 30;
663 WinScore := 2048;
664 Board := TBoard.Create;
665 FBoardUndo := TBoard.Create;
666end;
667
668destructor TGame.Destroy;
669begin
670 FreeAndNil(FBoardUndo);
671 FreeAndNil(Board);
672 inherited;
673end;
674
675function TGame.GetTileColor(Value: Integer): TColor;
676begin
677 case Value of
678 0: Result := $f2f6f9;
679 2: Result := $dae4ee;
680 4: Result := $c8e0ed;
681 8: Result := $79b1f2;
682 16: Result := $6395f5;
683 32: Result := $5f7cf6;
684 64: Result := $3b5ef6;
685 128: Result := $72cfed;
686 256: Result := $61cced;
687 512: Result := $50c8ed;
688 1024: Result := $3fc5ed;
689 2048: Result := $2ec2ed;
690 else Result := $323a3c;
691 end;
692end;
693
694procedure TGame.SetScore(AValue: Integer);
695begin
696 if FScore = AValue then Exit;
697 FScore := AValue;
698 if FScore > TopScore then TopScore := FScore;
699end;
700
701end.
702
Note: See TracBrowser for help on using the repository browser.