Changeset 29 for trunk/UGame.pas


Ignore:
Timestamp:
Oct 6, 2019, 9:53:39 PM (5 years ago)
Author:
chronos
Message:
  • Added: Computer player accessible from Tools menu in Debug mode. It is not able to win game yet.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/UGame.pas

    r28 r29  
    3636    procedure Clear;
    3737    procedure ClearMerged;
     38    function GetValueSum: Integer;
    3839    function GetHighestTileValue: Integer;
    3940    function GetEmptyTilesCount: Integer;
     
    5354    FMoving: Boolean;
    5455    FOnChange: TNotifyEvent;
     56    FOnGameOver: TNotifyEvent;
     57    FOnWin: TNotifyEvent;
    5558    FRunning: Boolean;
    5659    FScore: Integer;
    5760    FCanUndo: Boolean;
    5861    FBoardUndo: TBoard;
    59     function CanMoveDirection(Direction: TDirection): Boolean;
    6062    function GetTileColor(Value: Integer): TColor;
    6163    procedure SetScore(AValue: Integer);
     
    7375    function CanUndo: Boolean;
    7476    procedure Undo;
     77    function CanMergeDirection(Direction: TDirection): Boolean;
     78    function CanMoveDirection(Direction: TDirection): Boolean;
    7579    function CanMove: Boolean;
    7680    procedure Assign(Source: TGame);
     
    7882    procedure Render(Canvas: TCanvas; CanvasSize: TPoint);
    7983    procedure MoveAll(Direction: TDirection);
     84    procedure MoveAllAndUpdate(Direction: TDirection);
    8085    procedure MoveTile(SourceTile, TargetTile: TTile);
    8186    function IsValidPos(Pos: TPoint): Boolean;
     
    8792    property Running: Boolean read FRunning write FRunning;
    8893    property OnChange: TNotifyEvent read FOnChange write FOnChange;
     94    property OnWin: TNotifyEvent read FOnWin write FOnWin;
     95    property OnGameOver: TNotifyEvent read FOnGameOver write FOnGameOver;
    8996    property Moving: Boolean read FMoving;
     97  end;
     98
     99  TGames = class(TFPGObjectList<TGame>)
    90100  end;
    91101
     
    94104    (X: -1; Y: 0), (X: 0; Y: -1), (X: 1; Y: 0), (X: 0; Y: 1)
    95105  );
     106  DirectionText: array[TDirection] of string = ('Left', 'Up', 'Right', 'Down');
    96107
    97108resourcestring
    98   SGameOverCaption = 'Lost';
    99   SGameOverMessage = 'Game over!';
    100   SWinCaption = 'Win';
    101   SWinMessage = 'You reached %d and won! You can continue to play to get higher score.';
    102109  SScore = 'Score';
    103110  STopScore = 'Top score';
     
    212219end;
    213220
     221function TBoard.GetValueSum: Integer;
     222var
     223  X, Y: Integer;
     224begin
     225  Result := 0;
     226  for Y := 0 to Size.Y - 1 do
     227    for X := 0 to Size.X - 1 do
     228      Inc(Result, Tiles[Y, X].Value);
     229end;
     230
    214231function TBoard.GetEmptyTilesCount: Integer;
    215232var
     
    260277procedure TGame.GameOver;
    261278begin
    262   if Running then MessageDlg(SGameOverCaption, SGameOverMessage, mtInformation, [mbOK], 0);
     279  if Running and Assigned(FOnGameOver) then FOnGameOver(Self);
    263280  Running := False;
    264281end;
     
    266283procedure TGame.Win;
    267284begin
    268   MessageDlg(SWinCaption, Format(SWinMessage, [WinScore]), mtInformation, [mbOk], 0);
     285  if Assigned(FOnWin) then FOnWin(Self);
    269286end;
    270287
     
    293310procedure TGame.Assign(Source: TGame);
    294311begin
    295   FScore := Source.FScore;
     312  Board.Assign(Source.Board);
     313  FBoardUndo.Assign(Source.FBoardUndo);
     314  FCanUndo := Source.FCanUndo;
    296315  TopScore := Source.TopScore;
    297316  AnimationDuration := Source.AnimationDuration;
    298   Board.Assign(Source.Board);
     317  WinScore := Source.WinScore;
     318  UndoEnabled := Source.UndoEnabled;
     319  FScore := Source.FScore;
     320  FRunning := Source.FRunning;
    299321end;
    300322
     
    412434    FRunning := CanMove;
    413435    DoChange;
     436  end;
     437end;
     438
     439function TGame.CanMergeDirection(Direction: TDirection): Boolean;
     440var
     441  StartPoint: TPoint;
     442  AreaSize: TPoint;
     443  Increment: TPoint;
     444  P: TPoint;
     445  PNew: TPoint;
     446  PI: TPoint;
     447  I: Integer;
     448begin
     449  Result := False;
     450  case Direction of
     451    drLeft: begin
     452      StartPoint := Point(1, 0);
     453      AreaSize := Point(Board.Size.X - 2, Board.Size.Y - 1);
     454      Increment := Point(1, 1);
     455    end;
     456    drUp: begin
     457      StartPoint := Point(0, 1);
     458      AreaSize := Point(Board.Size.X - 1, Board.Size.Y - 2);
     459      Increment := Point(1, 1);
     460    end;
     461    drRight: begin
     462      StartPoint := Point(Board.Size.X - 2, 0);
     463      AreaSize := Point(Board.Size.X - 2, Board.Size.Y - 1);
     464      Increment := Point(-1, 1);
     465    end;
     466    drDown: begin
     467      StartPoint := Point(0, Board.Size.Y - 2);
     468      AreaSize := Point(Board.Size.X - 1, Board.Size.Y - 2);
     469      Increment := Point(1, -1);
     470    end;
     471  end;
     472
     473  for I := 0 to Max(Board.Size.X, Board.Size.Y) - 1 do begin
     474    PI.Y := 0;
     475    while PI.Y <= AreaSize.Y do begin
     476      PI.X := 0;
     477      while PI.X <= AreaSize.X do begin
     478        P := Point(StartPoint.X + PI.X * Increment.X, StartPoint.Y + PI.Y * Increment.Y);
     479        PNew.X := P.X + DirectionDiff[Direction].X;
     480        PNew.Y := P.Y + DirectionDiff[Direction].Y;
     481        if IsValidPos(PNew) then begin
     482          if (Board.Tiles[PNew.Y, PNew.X].Value = 0) then begin
     483            Board.Tiles[PNew.Y, PNew.X].Value := Board.Tiles[P.Y, P.X].Value;
     484            Board.Tiles[P.Y, P.X].Value := 0;
     485          end else
     486          if (Board.Tiles[P.Y, P.X].Value <> 0) then begin
     487            if Board.Tiles[PNew.Y, PNew.X].Value = Board.Tiles[P.Y, P.X].Value then begin
     488              Result := True;
     489              Break;
     490            end;
     491          end;
     492          P.X := PNew.X;
     493          P.Y := PNew.Y;
     494          PNew.X := P.X + DirectionDiff[Direction].X;
     495          PNew.Y := P.Y + DirectionDiff[Direction].Y;
     496        end;
     497        Inc(PI.X);
     498      end;
     499      if Result then Break;
     500      Inc(PI.Y);
     501    end;
    414502  end;
    415503end;
     
    490578  Time: TDateTime;
    491579  Part: Double;
    492   HighestValue: Integer;
    493580begin
    494581  if not CanMoveDirection(Direction) then Exit;
    495582  FMoving := True;
    496   HighestValue := Board.GetHighestTileValue;
    497583  FBoardUndo.Assign(Board);
    498584  FCanUndo := True;
     
    596682    DoChange;
    597683  end;
    598 
    599   // Update state after move
     684  FMoving := False;
     685end;
     686
     687procedure TGame.MoveAllAndUpdate(Direction: TDirection);
     688var
     689  HighestValue: Integer;
     690begin
     691  HighestValue := Board.GetHighestTileValue;
     692  MoveAll(Direction);
    600693  FillRandomTile;
    601694  if not CanMove and (Board.GetEmptyTilesCount = 0) then
     
    603696  if (HighestValue < WinScore) and
    604697  (Board.GetHighestTileValue >= WinScore) then Win;
    605 
    606   FMoving := False;
    607698end;
    608699
Note: See TracChangeset for help on using the changeset viewer.