unit genunit;
interface
CONST
  XCount         = 30; {Размер поля}
  YCount         = 20;
  FieldSize	 = XCount * YCount div 8; {Объем информации, требуемой для ее хранения}
  LifeTimeAdd    : array [0..9] of longint = (50,30,20,10,10,10,10,5,5,5);


type
              {Самый примитивный, всего одна хромосома - Х}
  EChromos = (CR_X); {Переч. хромосом}
CONST
  CFirstChromo : EChromos = CR_X;
   CLastChromo : EChromos = CR_X;
TYPE
	     {Пол (0-м), 2 бита цвета, ост 2 бита цвета,размер,Сила,Ум,
	      Возраст,-//-2}
  EGenesX = (GEN_X_GENDER,GEN_X_COL_RG,GEN_X_COL_BA, {Перечень генов в X-хромосоме}
	   GEN_X_SIZE,GEN_X_STRENGTH,GEN_X_MIND,GEN_X_AGE1,GEN_X_AGE2);
CONST
  CFirstGeneX : EGenesX = GEN_X_GENDER;
   CLastGeneX : EGenesX = GEN_X_AGE2;
TYPE
  EColors  = (COL_Black,COL_Blue,COL_Green,COL_Cyan,COL_Red,COL_Magenta,
	      COL_Brown,COL_LightGray,COL_DarkGray,COL_LightBlue,
	      COL_LightGreen,COL_LightCyan,COL_LightRed,COL_LightMagenta,
	      COL_Yellow,COL_White);


  EAStages = (AGE_CHILD,AGE_YOUTH,AGE_NORMAL,AGE_OLDMAN,AGE_DEAD);
  	   {Стадии возраста клеток}

  TChromo  = array [EGenesX] of byte; {Хромосома, как набор генов}

  TChromos = array [EChromos] of TChromo;
    {Одиночный хромосомный набор (гаплоидный)}
  Tvec	= record x,y:real; end;
  PCreature = ^Creature;
{CReature}
  Creature  = object
    private
      Genos                  : array [1..2] of TChromos;
					 {Генотип (диплоидный набор)}
      Age                    : longint;  {Возраст}
      AgeStage               : EAStages; {Стадии возраста}
      MaxAge                 : longint;	 {Возраст смерти}
      Children		     : longint;
      CrMom, CrDad           : pcreature;{Родители}
    Public
      Gender                 : char;	 {Пол (W/M)}
      Color                  : EColors;	 {Цвет}
      Size                   : byte;	 {Размер}
      Pos                    : Tvec;	 {Положение на поле}
      Constructor Init(apos : tvec; aC1,aC2 : TChromos;aMom,aDad : pcreature);
      Procedure   SetGamete(var aG : TChromos);
      Procedure   AddChild;
      Function    GetRandomGene(aJ : EGenesX):Byte;
  end;
{/CReature}

  PCList = ^TCList;
  TCList = record	{Список существ}
    Cr   : pcreature;
    Next,Prev : PCList;
  end;

  TCreatureEnumProc = procedure(pC : PCreature);

{CWorld}
  CWorld = object	{Объект - мир}
    Field 	   : array [1..FieldSize] of byte; {Битовое поле существ}
    Creatures      : PCList;			   {Сами существа}
    CreatureCount  : longint;			   {Их кол-во}
    Constructor Init;
    Function  CreateChild(aPos:TVec; aMom,aDad : PCreature):PCreature;
    procedure SetFieldPos(x,y : word);		   {Установка бита в поле}
    Function  GetFieldPos(x,y:word) : boolean;     {..}
    Procedure ForEachCreature(aProc : TCreatureEnumProc);
    procedure UnSetFieldPos(x,y : word);	   {Снятие бита поля}
    Function  AddNewCreature(aPos : tvec; aC1,aC2 : TChromos;aMom,aDad : pcreature):pCreature;
					   {Добавление существа в мир}
    Destructor Done;
  end;
{CWorld}

Implementation

Constructor Creature.Init;
begin
  Randomize;
  Children := 0;
  pos := aPos;
  Age := 0;
  AgeStage := AGE_CHILD;
  move(aC1,Genos[1],Sizeof(aC1));
  move(aC2,Genos[2],Sizeof(aC2));
  if Genos[1][CR_X][GEN_X_GENDER] = Genos[2][CR_X][GEN_X_GENDER] then Gender := 'W'
  else Gender := 'M';
  MaxAge := random(LifeTimeAdd[random(10)]);
  MaxAge := Integer(random(2)*2-1)*MaxAge;
  MaxAge := MaxAge + Genos[1][CR_X][GEN_X_AGE1] + Genos[2][CR_X][GEN_X_AGE1]+
	    Genos[1][CR_X][GEN_X_AGE2] + Genos[2][CR_X][GEN_X_AGE2]+LongInt(51);

  Color := EColors(Genos[1][CR_X][GEN_X_COL_RG] and 1 +
		   Genos[2][CR_X][GEN_X_COL_RG] and 2 +
		   Genos[1][CR_X][GEN_X_COL_BA] and 4 +
		   Genos[2][CR_X][GEN_X_COL_BA] and 8
		   );
  if (Genos[1][CR_X][GEN_X_SIZE] <> 0) or (Genos[2][CR_X][GEN_X_SIZE] <> 0) then
    Size := 10
  else
    Size := 5;

  CrMom := aMom;
  CrDad := aDad;
end;{Creature.Init}
{------------------------------}
Function Creature.GetRandomGene(aJ : EGenesX):Byte;
begin
  GetRandomGene := Genos[random(2)+1][CR_X][aJ]
end;{Creature.GetRandomGene}
{------------------------------}
Procedure Creature.SetGamete;
var
  j : EGenesX;
begin
  randomize;
  for j := CFirstGeneX to CLastGeneX do aG[CR_X][j] := GetRandomGene(j);
end;{Creature.SetGamete}
{------------------------------}
Procedure Creature.AddChild;
begin
  inc(Children);
end;{Creature.AddChild}
{/Creature}


{/////////////////////////////////////////////////////////}


{CWorld}
Constructor CWorld.Init;
begin
  Creatures := nil;
  CreatureCount :=0;
  FillChar(Field,FieldSize,0);
end;{CWorld.Init}
{----------------------------------------------}
Function CWorld.AddNewCreature;
var
  NNN : PCList;
  NC  : PCreature;
begin
  New(NC);
  NC^.Init(aPos,aC1,aC2,aMom,aDad);
  SetFieldPos(Round(aPos.X),Round(aPos.Y));
  Inc(CreatureCount);
  NNN := New(PClist);
  NNN^.Cr   := NC;
  NNN^.Prev := Creatures;
  NNN^.Next := nil;
  if Creatures <> nil then Creatures^.Next := NNN;
  Creatures := NNN;
  AddNewCreature := NC;
End;{CWorld.AddNewCreature}
{-----------------------------------------------}
Function CWorld.CreateChild;
var
 cr1,cr2 : TChromos;
begin
  aMom^.SetGamete(cr1);
  aDad^.SetGamete(cr2);
  aMom^.AddChild;
  aDad^.AddChild;
  CreateChild:=AddNewCreature(aPos,cr1,cr2,aMom,aDad);
end;{CWorld.CreateChild}
{-----------------------------------------------}
procedure CWorld.SetFieldPos(x,y : word);
var
  Cbyte : longint;
  Cbit  : byte;
  Mask  : byte;
begin
  CByte := (y*YCount + X) div 8;
  CBit  := (y*YCount + X) mod 8;
  Mask := 1 shl (7-CBit);
  Field[Cbyte] := Field[Cbyte] or Mask;
end;{CWorld.SetFieldPos}
{--------------------------}
procedure CWorld.UnSetFieldPos(x,y : word);
var
  Cbyte : longint;
  Cbit  : byte;
  Mask  : byte;
begin
  CByte := (y*YCount + X) div 8;
  CBit  := (y*YCount + X) mod 8;
  Mask  := 255 xor (1 shl (7-CBit));
  Field[Cbyte] := Field[Cbyte] and Mask;
end;{CWorld.UnSetFieldPos}
{------------------------------------------}
Function  CWorld.GetFieldPos(x,y:word) : boolean;
var
  Cbyte : longint;
  Cbit  : byte;
  Mask  : byte;
begin
  CByte := (y*YCount + X) div 8;
  CBit  := (y*YCount + X) mod 8;
  Mask  := Field[Cbyte] shr (7-Cbit);
  if Mask and 1 = 1 then GetFieldPos := true
  else GetFieldPos := false;
end; {CWorld.GetFieldPos}
{-----------------------------------------------}
Procedure CWorld.ForEachCreature;
var
 C : PCList;
begin
  C := Creatures;
  while C <> nil do begin aProc(C^.Cr); c:=c^.prev; end;
end;{CWorld.ForEachCreature}
{-----------------------------------------------}
Destructor CWorld.Done;
var
 C : PCList;
begin
  while Creatures <> nil do
   begin
     C:=Creatures;
     Creatures:=Creatures^.Prev;
     Dispose(C);
   end;
end;{CWorld.Done}
{/CWorld}
{////////////////////////////////////////////////////}
end.
