Changeset 31 for trunk/UGame.pas
- Timestamp:
- Oct 12, 2019, 10:47:02 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/UGame.pas
r30 r31 10 10 11 11 type 12 TGame = class; 13 TMoveDirection = (drNone, drLeft, drUp, drRight, drDown); 12 14 13 15 { TTile } 14 16 15 17 TTile = class 18 Index: TPoint; 16 19 Value: Integer; 17 20 NewValue: Integer; … … 32 35 function Create(P1, P2: TPoint): TArea; overload; 33 36 function Create(X1, Y1, X2, Y2: Integer): TArea; overload; 37 end; 38 39 { THistoryMove } 40 41 THistoryMove = class 42 Direction: TMoveDirection; 43 NewItemPos: TPoint; 44 NewItemValue: Integer; 45 procedure SaveToRegistry(RegContext: TRegistryContext); 46 procedure LoadFromRegistry(RegContext: TRegistryContext); 47 end; 48 49 { THistoryMoves } 50 51 THistoryMoves = class(TFPGObjectList<THistoryMove>) 52 procedure SaveToRegistry(RegContext: TRegistryContext); 53 procedure LoadFromRegistry(RegContext: TRegistryContext); 54 end; 55 56 { THistory } 57 58 THistory = class 59 Game: TGame; 60 Moves: THistoryMoves; 61 InitialTilesPos: array of TPoint; 62 procedure GetStep(GameStep: TGame; Step: Integer); 63 constructor Create; 64 destructor Destroy; override; 65 procedure SaveToRegistry(RegContext: TRegistryContext); 66 procedure LoadFromRegistry(RegContext: TRegistryContext); 34 67 end; 35 68 … … 55 88 end; 56 89 57 TDirection = (drLeft, drUp, drRight, drDown);58 59 90 { TGame } 60 91 … … 75 106 procedure GameOver; 76 107 procedure Win; 77 function FillRandomTile(Value4Change: Double = 0.1): Integer;78 function GetMoveArea(Direction: T Direction): TArea;108 function FillRandomTile(Value4Change: Double = 0.1): TTile; 109 function GetMoveArea(Direction: TMoveDirection): TArea; 79 110 public 80 111 Board: TBoard; … … 83 114 WinScore: Integer; 84 115 UndoEnabled: Boolean; 116 History: THistory; 85 117 function CanUndo: Boolean; 86 118 procedure Undo; 87 function CanMergeDirection(Direction: T Direction): Boolean;88 function CanMoveDirection(Direction: T Direction): Boolean;119 function CanMergeDirection(Direction: TMoveDirection): Boolean; 120 function CanMoveDirection(Direction: TMoveDirection): Boolean; 89 121 function CanMove: Boolean; 90 122 procedure Assign(Source: TGame); 91 123 procedure New; 92 124 procedure Render(Canvas: TCanvas; CanvasSize: TPoint); 93 procedure MoveAll(Direction: T Direction);94 procedure MoveAllAndUpdate(Direction: T Direction);125 procedure MoveAll(Direction: TMoveDirection); 126 procedure MoveAllAndUpdate(Direction: TMoveDirection); 95 127 procedure MoveTile(SourceTile, TargetTile: TTile); 96 128 function IsValidPos(Pos: TPoint): Boolean; … … 111 143 112 144 const 113 DirectionDiff: array[T Direction] of TPoint = (114 (X: -1; Y: 0), (X: 0; Y: -1), (X: 1; Y: 0), (X: 0; Y: 1)145 DirectionDiff: array[TMoveDirection] of TPoint = ( 146 (X: 0; Y: 0), (X: -1; Y: 0), (X: 0; Y: -1), (X: 1; Y: 0), (X: 0; Y: 1) 115 147 ); 116 DirectionText: array[T Direction] of string = ('Left', 'Up', 'Right', 'Down');148 DirectionText: array[TMoveDirection] of string = ('None', 'Left', 'Up', 'Right', 'Down'); 117 149 118 150 resourcestring … … 121 153 122 154 implementation 155 156 { THistoryMoves } 157 158 procedure THistoryMoves.SaveToRegistry(RegContext: TRegistryContext); 159 var 160 I: Integer; 161 begin 162 with TRegistryEx.Create do 163 try 164 CurrentContext := RegContext; 165 WriteInteger('Count', Count); 166 for I := 0 to Count - 1 do begin 167 Items[I].SaveToRegistry(TRegistryContext.Create(RegContext.RootKey, RegContext.Key + '/' + IntToStr(I))); 168 end; 169 finally 170 Free; 171 end; 172 end; 173 174 procedure THistoryMoves.LoadFromRegistry(RegContext: TRegistryContext); 175 var 176 I: Integer; 177 C: Integer; 178 HistoryMove: THistoryMove; 179 begin 180 with TRegistryEx.Create do 181 try 182 CurrentContext := RegContext; 183 C := ReadIntegerWithDefault('Count', 0); 184 for I := 0 to C - 1 do begin 185 HistoryMove := THistoryMove.Create; 186 Add(HistoryMove); 187 HistoryMove.LoadFromRegistry(TRegistryContext.Create(RegContext.RootKey, RegContext.Key + '/' + IntToStr(I))); 188 end; 189 finally 190 Free; 191 end; 192 end; 193 194 { THistoryMove } 195 196 procedure THistoryMove.SaveToRegistry(RegContext: TRegistryContext); 197 begin 198 with TRegistryEx.Create do 199 try 200 CurrentContext := RegContext; 201 WriteInteger('Direction', Integer(Direction)); 202 WriteInteger('NewItemPosX', NewItemPos.X); 203 WriteInteger('NewItemPosY', NewItemPos.Y); 204 WriteInteger('NewItemValue', NewItemValue); 205 finally 206 Free; 207 end; 208 end; 209 210 procedure THistoryMove.LoadFromRegistry(RegContext: TRegistryContext); 211 begin 212 with TRegistryEx.Create do 213 try 214 CurrentContext := RegContext; 215 Direction := TMoveDirection(ReadIntegerWithDefault('Direction', Integer(drNone))); 216 NewItemPos := Point(ReadIntegerWithDefault('NewItemPosX', 0), 217 ReadIntegerWithDefault('NewItemPosY', 0)); 218 NewItemValue := ReadIntegerWithDefault('NewItemValue', 0); 219 finally 220 Free; 221 end; 222 end; 223 224 { THistory } 225 226 procedure THistory.GetStep(GameStep: TGame; Step: Integer); 227 var 228 I: Integer; 229 begin 230 GameStep.Board.Size := Game.Board.Size; 231 GameStep.Board.Clear; 232 GameStep.Score := 0; 233 for I := 0 to Length(InitialTilesPos) - 1 do 234 GameStep.Board.Tiles[InitialTilesPos[I].Y, InitialTilesPos[I].X].Value := 2; 235 for I := 0 to Step - 1 do 236 with Moves[I] do begin 237 GameStep.MoveAll(Direction); 238 if GameStep.Board.Tiles[NewItemPos.Y, NewItemPos.X].Value = 0 then 239 GameStep.Board.Tiles[NewItemPos.Y, NewItemPos.X].Value := NewItemValue 240 else raise Exception.Create('Tile should be empty'); 241 end; 242 end; 243 244 constructor THistory.Create; 245 begin 246 Moves := THistoryMoves.Create; 247 end; 248 249 destructor THistory.Destroy; 250 begin 251 FreeAndNil(Moves); 252 inherited Destroy; 253 end; 254 255 procedure THistory.SaveToRegistry(RegContext: TRegistryContext); 256 var 257 I: Integer; 258 begin 259 with TRegistryEx.Create do 260 try 261 CurrentContext := TRegistryContext.Create(RegContext.RootKey, RegContext.Key + '\InitialTilesPos'); 262 WriteInteger('Count', Length(InitialTilesPos)); 263 for I := 0 to Length(InitialTilesPos) - 1 do begin 264 WriteInteger('X' + IntToStr(I), InitialTilesPos[I].X); 265 WriteInteger('Y' + IntToStr(I), InitialTilesPos[I].Y); 266 end; 267 finally 268 Free; 269 end; 270 Moves.SaveToRegistry(RegContext); 271 end; 272 273 procedure THistory.LoadFromRegistry(RegContext: TRegistryContext); 274 var 275 I: Integer; 276 begin 277 with TRegistryEx.Create do 278 try 279 CurrentContext := TRegistryContext.Create(RegContext.RootKey, RegContext.Key + '\InitialTilesPos'); 280 SetLength(InitialTilesPos, ReadIntegerWithDefault('Count', 0)); 281 for I := 0 to Length(InitialTilesPos) - 1 do begin 282 InitialTilesPos[I] := Point(ReadIntegerWithDefault('X' + IntToStr(I), 0), 283 ReadIntegerWithDefault('Y' + IntToStr(I), 0)); 284 end; 285 finally 286 Free; 287 end; 288 Moves.LoadFromRegistry(RegContext); 289 end; 123 290 124 291 { TArea } … … 154 321 SetLength(Tiles, FSize.Y, FSize.X); 155 322 for Y := 0 to FSize.Y - 1 do 156 for X := 0 to FSize.X - 1 do 323 for X := 0 to FSize.X - 1 do begin 157 324 Tiles[Y, X] := TTile.Create; 325 Tiles[Y, X].Index := Point(X, Y); 326 end; 158 327 end; 159 328 … … 228 397 end; 229 398 end; 399 Lines.Free; 400 Items.Free; 230 401 finally 231 402 Free; … … 315 486 end; 316 487 317 function TGame.FillRandomTile(Value4Change: Double = 0.1): Integer;488 function TGame.FillRandomTile(Value4Change: Double = 0.1): TTile; 318 489 var 319 490 EmptyTiles: TTiles; 320 491 NewValue: Integer; 321 492 begin 322 Result := 0;493 Result := nil; 323 494 EmptyTiles := TTiles.Create(False); 324 495 Board.GetEmptyTiles(EmptyTiles); 325 496 if EmptyTiles.Count > 0 then begin 326 497 if Random < Value4Change then NewValue := 4 else NewValue := 2; 327 EmptyTiles[Random(EmptyTiles.Count)].Value := NewValue;328 Result := 1;498 Result := EmptyTiles[Random(EmptyTiles.Count)]; 499 Result.Value := NewValue; 329 500 end; 330 501 EmptyTiles.Free; 331 502 end; 332 503 333 function TGame.GetMoveArea(Direction: T Direction): TArea;504 function TGame.GetMoveArea(Direction: TMoveDirection): TArea; 334 505 begin 335 506 case Direction of … … 371 542 var 372 543 I: Integer; 544 NewTile: TTile; 373 545 begin 374 546 FCanUndo := False; … … 376 548 Score := 0; 377 549 Running := True; 378 for I := 0 to 1 do FillRandomTile(0); 550 with History do begin 551 Moves.Clear; 552 553 SetLength(InitialTilesPos, 0); 554 for I := 0 to 1 do begin 555 NewTile := FillRandomTile(0); 556 SetLength(InitialTilesPos, Length(InitialTilesPos) + 1); 557 InitialTilesPos[Length(InitialTilesPos) - 1] := NewTile.Index; 558 end; 559 end; 379 560 DoChange; 380 561 end; … … 484 665 end; 485 666 486 function TGame.CanMergeDirection(Direction: T Direction): Boolean;667 function TGame.CanMergeDirection(Direction: TMoveDirection): Boolean; 487 668 var 488 669 P: TPoint; … … 495 676 for I := 0 to Max(Board.Size.X, Board.Size.Y) - 1 do begin 496 677 P := Area.P1; 497 while P.Y <> Area.P2.Y do begin678 while P.Y <> Area.P2.Y + Area.Increment.Y do begin 498 679 P.X := Area.P1.X; 499 while P.X <> Area.P2.X do begin680 while P.X <> Area.P2.X + Area.Increment.X do begin 500 681 PNew := P + DirectionDiff[Direction]; 501 682 if IsValidPos(PNew) then begin … … 519 700 end; 520 701 521 function TGame.CanMoveDirection(Direction: T Direction): Boolean;702 function TGame.CanMoveDirection(Direction: TMoveDirection): Boolean; 522 703 var 523 704 P: TPoint; … … 548 729 end; 549 730 550 procedure TGame.MoveAll(Direction: T Direction);731 procedure TGame.MoveAll(Direction: TMoveDirection); 551 732 var 552 733 P: TPoint; … … 560 741 Area: TArea; 561 742 begin 743 if Direction = drNone then Exit; 562 744 if not CanMoveDirection(Direction) then Exit; 563 745 FMoving := True; … … 634 816 end; 635 817 636 procedure TGame.MoveAllAndUpdate(Direction: T Direction);818 procedure TGame.MoveAllAndUpdate(Direction: TMoveDirection); 637 819 var 638 820 HighestValue: Integer; 821 HistoryMove: THistoryMove; 822 NewTile: TTile; 639 823 begin 640 824 HighestValue := Board.GetHighestTileValue; 641 825 MoveAll(Direction); 642 FillRandomTile; 826 827 NewTile := FillRandomTile; 828 HistoryMove := THistoryMove.Create; 829 HistoryMove.Direction := Direction; 830 HistoryMove.NewItemPos := NewTile.Index; 831 HistoryMove.NewItemValue := NewTile.Value; 832 History.Moves.Add(HistoryMove); 833 643 834 if not CanMove and (Board.GetEmptyTilesCount = 0) then 644 835 GameOver; … … 678 869 FBoardUndo.SaveToRegistry(TRegistryContext.Create(RegContext.RootKey, RegContext.Key + '\BoardUndo')); 679 870 Board.SaveToRegistry(TRegistryContext.Create(RegContext.RootKey, RegContext.Key + '\Board')); 871 History.SaveToRegistry(TRegistryContext.Create(RegContext.RootKey, RegContext.Key + '\History')); 680 872 end; 681 873 … … 696 888 FBoardUndo.LoadFromRegistry(TRegistryContext.Create(RegContext.RootKey, RegContext.Key + '\BoardUndo')); 697 889 Board.LoadFromRegistry(TRegistryContext.Create(RegContext.RootKey, RegContext.Key + '\Board')); 890 History.LoadFromRegistry(TRegistryContext.Create(RegContext.RootKey, RegContext.Key + '\History')); 698 891 DoChange; 699 892 end; … … 705 898 Board := TBoard.Create; 706 899 FBoardUndo := TBoard.Create; 900 History := THistory.Create; 901 History.Game := Self; 707 902 end; 708 903 709 904 destructor TGame.Destroy; 710 905 begin 906 FreeAndNil(History); 711 907 FreeAndNil(FBoardUndo); 712 908 FreeAndNil(Board);
Note:
See TracChangeset
for help on using the changeset viewer.