unit Board;

interface

uses
  Classes, SysUtils, Tile, RegistryEx;

type
  TMoveDirection = (drNone, drLeft, drUp, drRight, drDown);

  { TBoard }

  TBoard = class
  private
    FSize: TPoint;
    procedure SetSize(AValue: TPoint);
  public
    Tiles: array of array of TTile;
    procedure Assign(Source: TBoard);
    procedure Clear;
    procedure ClearMerged;
    function GetBiggestTile: Integer;
    function GetValueSum: Integer;
    function GetHighestTileValue: Integer;
    function GetEmptyTilesCount: Integer;
    procedure GetEmptyTiles(EmptyTiles: TTiles);
    procedure SaveToRegistry(Reg: TRegistryEx; RegContext: TRegistryContext);
    procedure LoadFromRegistry(Reg: TRegistryEx; RegContext: TRegistryContext);
    destructor Destroy; override;
    property Size: TPoint read FSize write SetSize;
  end;


implementation

{ TBoard }

procedure TBoard.SetSize(AValue: TPoint);
var
  X, Y: Integer;
begin
  if FSize = AValue then Exit;
  for Y := 0 to FSize.Y - 1 do
    for X := 0 to FSize.X - 1 do
      Tiles[Y, X].Free;
  FSize := AValue;
  SetLength(Tiles, FSize.Y, FSize.X);
  for Y := 0 to FSize.Y - 1 do
    for X := 0 to FSize.X - 1 do begin
      Tiles[Y, X] := TTile.Create;
      Tiles[Y, X].Index := Point(X, Y);
    end;
end;

procedure TBoard.Assign(Source: TBoard);
var
  X, Y: Integer;
begin
  Size := Source.Size;
  for Y := 0 to Size.Y - 1 do
    for X := 0 to Size.X - 1 do
      Tiles[Y, X].Assign(Source.Tiles[Y, X]);
end;

procedure TBoard.GetEmptyTiles(EmptyTiles: TTiles);
var
  X, Y: Integer;
begin
  EmptyTiles.Clear;
  for Y := 0 to Size.Y - 1 do
    for X := 0 to Size.X - 1 do
      if (Tiles[Y, X].Value = 0) and not Tiles[Y, X].Disabled then
        EmptyTiles.Add(Tiles[Y, X]);
end;

procedure TBoard.SaveToRegistry(Reg: TRegistryEx; RegContext: TRegistryContext);
var
  X, Y: Integer;
begin
  with Reg do begin
    CurrentContext := RegContext;

    WriteInteger('SizeX', Size.X);
    WriteInteger('SizeY', Size.Y);
    for Y := 0 to Size.Y - 1 do begin
      for X := 0 to Size.X - 1 do begin
        Tiles[Y, X].SaveToRegistry(Reg, TRegistryContext.Create(RegContext.RootKey, RegContext.Key + '\Tile' + IntToStr(X) + 'x' + IntToStr(Y)));
      end;
    end;
  end;
end;

procedure TBoard.LoadFromRegistry(Reg: TRegistryEx; RegContext: TRegistryContext);
var
  X, Y: Integer;
begin
  with Reg do begin
    CurrentContext := RegContext;

    Size := Point(ReadIntegerWithDefault('SizeX', 4),
      ReadIntegerWithDefault('SizeY', 4));
    for Y := 0 to Size.Y - 1 do begin
      for X := 0 to Size.X - 1 do begin
        Tiles[Y, X].LoadFromRegistry(Reg, TRegistryContext.Create(RegContext.RootKey, RegContext.Key + '\Tile' + IntToStr(X) + 'x' + IntToStr(Y)));
      end;
    end;
  end;
end;

destructor TBoard.Destroy;
begin
  Size := Point(0, 0);
  inherited;
end;

procedure TBoard.ClearMerged;
var
  X, Y: Integer;
begin
  for Y := 0 to Size.Y - 1 do
    for X := 0 to Size.X - 1 do
      Tiles[Y, X].Merged := False;
end;

function TBoard.GetBiggestTile: Integer;
var
  X, Y: Integer;
begin
  Result := 0;
  for Y := 0 to Size.Y - 1 do
    for X := 0 to Size.X - 1 do
      if not Tiles[Y, X].Disabled and
      not Tiles[Y, X].Unmergeable and
      (Tiles[Y, X].Value > Result) then Result := Tiles[Y, X].Value;
end;

function TBoard.GetValueSum: Integer;
var
  X, Y: Integer;
begin
  Result := 0;
  for Y := 0 to Size.Y - 1 do
    for X := 0 to Size.X - 1 do
      Inc(Result, Tiles[Y, X].Value);
end;

function TBoard.GetEmptyTilesCount: Integer;
var
  X, Y: Integer;
begin
  Result := 0;
  for Y := 0 to Size.Y - 1 do
    for X := 0 to Size.X - 1 do
      if (Tiles[Y, X].Value = 0) and not Tiles[Y, X].Disabled then
        Inc(Result);
end;

function TBoard.GetHighestTileValue: Integer;
var
  X, Y: Integer;
begin
  Result := 0;
  for Y := 0 to Size.Y - 1 do
    for X := 0 to Size.X - 1 do
      if Result < Tiles[Y, X].Value then Result := Tiles[Y, X].Value;
end;

procedure TBoard.Clear;
var
  X, Y: Integer;
begin
  for Y := 0 to Size.Y - 1 do
    for X := 0 to Size.X - 1 do
      Tiles[Y, X].Clear;
end;

end.

