-- computerman is multiway user tools.
-- Computerman is Copyright (C) 2024 Manuel De Girardi ; 
--
--   This program is free software; you can redistribute it and/or modify
--   it under the terms of the GNU General Public License as published by
--   the Free Software Foundation; either version 2 of the License, or
--   (at your option) any later version.
--
--   This program is distributed in the hope that it will be useful,
--   but WITHOUT ANY WARRANTY; without even the implied warranty of
--   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--   GNU General Public License for more details.
--
--   You should have received a copy of the GNU General Public License
--   along with this program; if not, write to the Free Software
--   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
--
-- Date := "2024-05-11 15:51:39"
-- Version := "0.0.2a"
package body Computer.Frame is
   
      function Digit_Random(Digit_Random_Generator : in Digit_Random_Generator_Type) return Digit_Type is
      New_Digit : Digit_Type;
   begin
      New_Digit.Class_Id := Random_Class_Id.Random(Digit_Random_Generator.Class_Id_Gen);
      New_Digit.Value_Id := Random_Value_Id.Random(Digit_Random_Generator.Value_Id_Gen);
      New_Digit.Data_Id := Random_Data_Id.Random(Digit_Random_Generator.Data_Id_Gen);
      return New_Digit;
   end Digit_Random;
   
   -- Use case : "to succed"
   function To_Succed (Old_Position : in Position_Type;
		       Successor    : in Digit_Type) return Position_Type is
      New_Position : Position_Type := Old_Position;
   begin
      new_position.Digit := New_Position.Temp;
      new_position.Temp := Successor;
      return New_Position;
   end To_Succed;     
   
   
   package body Frame_Rand is
      
      procedure Reset is
      begin
	 Random_Class_Id.Reset(Digit_Generator.Class_Id_Gen, 7);
	 Random_Value_Id.Reset(Digit_Generator.Value_Id_Gen, 3);
	 Random_Data_Id.Reset(Digit_Generator.Data_Id_Gen, 1);
      end Reset;
      
      procedure Random (B_Inf           : in Natural;
			B_Sup           : in Natural;
			Digit_Generator : in Digit_Random_Generator_Type;
			Frame           :    out Frame_Type) is
	 
	 New_Frame : Frame_Type := ((others => ((Digit_Default, Digit_Default), Digit_Default)), B_Inf, B_Sup);
	 
      begin	 
	 for Series_Index in B_Inf..B_Sup loop
	    New_Frame.Digital_Series(Series_Index) := (Position => (Digit_Random(Digit_Generator), 
								    Digit_Random(Digit_Generator)), 
						       Successor => Digit_Random(Digit_Generator));
	 end loop;
	 Frame := New_Frame;
      end Random;
      
      function Frame_Random return Frame_Type is
	 
	 New_Frame : Frame_Type;
      begin	 
	 Random(Max_B_Inf, Frame_Range_Rand.Random(Frame_Range_Gen), Digit_Generator, New_Frame);
	 return New_Frame;
      end Frame_Random;
   end Frame_Rand;
   
   
   type Digit_Counter_Type is
      record
	 Digit : Digit_Type;
	 Count : Positive := 1;
      end record;
   
   type Digit_Counter_Table_Type is array (Natural range Max_B_Inf..Max_B_Sup) of Digit_Counter_Type;
      
   
   function Frame_Fitness (Frame : in Frame_Type) return Float is
      
      Fitness : Float := 0.0;
      
      
      Digit_Counter_Table : Digit_Counter_Table_Type;
      
      Current_Digit : Digit_Type;
      
      Bester : Boolean := False;
      
   begin
      for Series_Index in Frame.B_Inf..Frame.B_Sup loop
	 Digit_Counter_Table(Series_Index).Digit := Frame.Digital_Series(Series_Index).Position.Digit;
      end loop;
      
      for Digit_Index in Digit_Counter_Table'Range loop
	 Current_Digit := Digit_Counter_Table(Digit_Index).Digit;
	 for Counter_Index in Digit_Index+1..Digit_Counter_Table'Last loop
	    if Digit_Counter_Table(Counter_Index).Digit = Current_Digit then
	       Digit_Counter_Table(Counter_Index).Count := Digit_Counter_Table(Counter_Index).Count + 1;
	    end if;
	 end loop;
      end loop;
      
      for Digit_Index in Digit_Counter_Table'Range loop	 
	 if Digit_Counter_Table(Digit_Index).Count = 1 then
	    Fitness := Fitness + 1.0;
	 elsif Digit_Counter_Table(Digit_Index).Count > 2 then
	    Fitness := Fitness - 1.0;
	 end if;
      end loop;
      for Counter_Index in Digit_Counter_Table'Range loop
	 if Digit_Counter_Table(Counter_Index).Count = 2 then
	    if Bester then
	       Bester := False;
	       exit;
	    else
	       Bester := True;
	    end if;
	 end if;
      end loop;
      if Bester then
	 Fitness := Fitness * 2.0;
      end if;
      return Fitness;
   end Frame_Fitness;
   
   
   function Frame_Mate (Left_Frame : in Frame_Type;
			Right_Frame : in Frame_Type) return Frame_Type is
      
     New_Frame : Frame_Type := Left_Frame;
   begin
      
      for Series_Index in New_Frame.B_Inf..New_Frame.B_Sup loop
	 
	 New_Frame.Digital_Series(Series_Index).Position := 
	   To_Succed(New_Frame.Digital_Series(Series_Index).Position,
		     Right_Frame.Digital_Series(Series_Index).Successor);
      end loop;
	
      return New_Frame;
   end Frame_Mate;
   
   procedure Frame_Mutate (Old_Frame : in out Frame_Type) is
      
      New_Frame : Frame_Type := Old_Frame;
   begin
      
      for Series_Index in New_Frame.B_Inf..New_Frame.B_Sup loop
	 
	 New_Frame.Digital_Series(Series_Index).Position := 
	   To_Succed(New_Frame.Digital_Series(Series_Index).Position,
		     New_Frame.Digital_Series(Series_Index).Successor);
      end loop;
      
      Old_Frame := New_Frame;
   end Frame_Mutate;

   
   
end Computer.Frame ;