Tuesday, October 5, 2010

Out of memory, the fallen and the rise of a programmer

As an average developer would do, I started creating classes and interfaces like hell for the chess project, as long as my search depth levels kept low, there was no problem at all, but as some optimizations and bugs fixing were deployed the memory was increasing rapidly, now in some positions the program can easily go to depth15, 20, etc (it depends in the amount of time and position, of course), so I had to do something that dramatically reduce the amount of memory and the code changes at a minimal level:

Before (simplistic version)


TMove = class
public
 function ToString: string; override;

 property FromIdx: integer read FFrom;
 property ToIdx: integer read FTo;
 property PieceType: TPieceType read FPieceType;
 property Action: TAction read FAction;
end;
Currently


TMove = integer;
 
  TMoveHelper = class
  { TODO : promotion type }
  {
  upper 16 bits  |lower 16 bits
  upper 8|lower 8|upper 6|middle 6|lower 4
  from   |to     |piece  |action  |promotion
  }
  public
    class function Pack(aPiece: TPieceType; aFrom, aTo: integer; aAction: TAction; aPromotion: TPromotion = pQueen): TMove; inline;
    class procedure Unpack(aMove: TMove; out aPiece: TPieceType; out aFrom, aTo: integer; out aAction: TAction);
    class function GetPiece(aMove: TMove): TPieceType; inline;
    class function GetFrom(aMove: TMove): integer; inline;
    class function GetTo(aMove: TMove): integer; inline;
    class function GetAction(aMove: TMove): TAction; inline;
    class function ToString(aMove: TMove): string; reintroduce;
  end;
The trick is packing all the class information into a single 32 bits integer and create a helper class that easily pack and unpack all the necessary information.
board[move.FromIdx] := move.PieceType ;
becomes 
board[TMoveHelper.GetFrom(move)] := TMoveHelper.GetPiece(move);
With the online options the code generated is quite fast, for the changes, a few replaces was enough.
Albeit the code now is a bit "obscure"

{ TMoveHelper }

class function TMoveHelper.GetAction(aMove: TMove): TAction;
begin
  Exit(TAction(aMove and $3f0 shr 4));
end;

class function TMoveHelper.GetFrom(aMove: TMove): integer;
begin
  Exit(aMove shr 24);
end;

class function TMoveHelper.GetPiece(aMove: TMove): TPieceType;
begin
  Exit(TPieceType(aMove and $ffff shr 10))
end;

class function TMoveHelper.GetTo(aMove: TMove): integer;
begin
  Exit(aMove and $ff0000 shr 16);
end;

class function TMoveHelper.Pack(aPiece: TPieceType; aFrom, aTo: integer; aAction: TAction; aPromotion: TPromotion = pQueen): TMove;
begin
  Exit((aFrom shl 24) + (aTo shl 16) + (integer(aPiece) shl 10) + (integer(aAction) shl 4) + integer(aPromotion));
end;

class function TMoveHelper.ToString(aMove: TMove): string;
var
  piece: TPieceType;
  action: TAction;
  FromIdx, ToIdx: integer;

begin
  Unpack(aMove, piece, FromIdx, ToIdx, action);
  Exit('xxx');  //+
end;

class procedure TMoveHelper.Unpack(aMove: TMove; out aPiece: TPieceType; out aFrom, aTo: integer; out aAction: TAction);
begin
  aPiece := TPieceType(aMove and $ffff shr 10);
  aAction := TAction(aMove and f0 shr 4);
  aFrom := aMove shr 24;
  aTo := aMove and $ff0000 shr 16;
  //+ aPromote := aMove and $f;
end;
Have fun

No comments:

Post a Comment