unit ucursormapeocf;

{$mode delphi}

interface

uses
  Classes, SysUtils, xmatdefs, uestados, ufechas, uparseadorsupersimple, usalasdejuego;

type

{ TCursorMapeoCF }

TCursorMapeoCF = class
  CFX, CFY: TAdminEstados;
  mapeo_str: String;
  aScript: TExprLst;
  sala: TSalaDeJuego;
  Evaluador: TEvaluadorExpresionesSimples;
  aVar: TVar;

  // Desaparecida significa que Está En CFAux y no en Self.
  cnt_desaparecidas_continuas, cnt_desaparecidas_discretas: integer;
  k_desaparecidas_continuas, k_desaparecidas_discretas: TDAOfNInt;

  cnt_y: integer;
  xrs, xds, yrs, yds: array of TVar;
  iyrs, iyds: TDAOfNInt;

  cnt_: integer;
  contadores_continuas, contadores_discretas: TDAOfNInt;

  hay_desaparecidas: boolean;

  constructor Create(sala: TSalaDeJuego);

  function Val(dt:TDateTime): NReal;

  destructor destroy; override;
end;



implementation

{ TCursorMapeoCF }

constructor TCursorMapeoCF.Create(sala: TSalaDeJuego);

var
  i, k: integer;
  rval: double;
  s: string;

begin
  CFX:= sala.globs.CF;   // De este solo apunto, pues la sala ya lo parasitó
  CFY:= sala.globs.CF_Enganche.CreateParasito;   // este lo parsito


  self.sala:= sala;

  self.mapeo_str:= MemoToStr( sala.enganche_mapeo );

  //kpr es la cantidad de pasos desde el inicio de CF hasta "dt"
  //con el paso de tiempo de aux



  sala.Sim_Cronica_Inicio;
  Evaluador := TEvaluadorExpresionesSimples.Create;

  sala.PosicionarseEnEstrellita;
  sala.AgregarDefinicionesEvaluador(Evaluador);

  //inicializamos variables "X" en entorno de cálculo
  for i := 0 to CFX.nVarsContinuas - 1 do
  begin
    s:= '$X_' + CFX.xr_Def[i].nombre + ':= 0.0';
    if not evaluador.Ejecutar( rval, s ) then
      raise Exception.Create('TCursorMapeoCF.Create. Imposible evaluar: '+s );
  end;

  for i := 0 to sala.globs.CF.nVarsDiscretas - 1 do
  begin
    s:= '$X_' + CFX.xd_Def[i].nombre + ':= 0';
    if not evaluador.Ejecutar( rval, s ) then
      raise Exception.Create('TCursorMapeoCF.Create. Imposible evaluar: '+s );
  end;

  aScript := evaluador.GetExprLst( mapeo_str );
  setlength( xrs, CFX.nVarsContinuas );
  setlength( xds, CFX.nVarsDiscretas );


  //Cargamos variables "X" según estado actual solo para que quede algo definido
  for i := 0 to sala.globs.CF.nVarsContinuas - 1 do
  begin
    aVar := evaluador.FindVar('$X_' + CFX.xr_Def[i].nombre);
    aVar.val.Val_F := CFX.xr[i];
    xrs[i] := aVar;
  end;

  for i := 0 to CFX.nVarsDiscretas - 1 do
  begin
    aVar := evaluador.FindVar('$X_' + CFX.xd_Def[i].nombre);
    aVar.val.Val_I := CFX.xd[i];
    xds[i] := aVar;
  end;

  aScript.evaluar; // evaluamos para que quede algo definido en las Y

  setlength(k_desaparecidas_continuas, length( CFY.xr_def));
  cnt_desaparecidas_continuas := 0;
  cnt_y := 0;
  //leo los valores "Y" resultantes. Si no encuentro alguna variable la marco como
  // desaparecida.
  setlength(yrs, CFY.nVarsContinuas);
  setlength(iyrs, CFY.nVarsContinuas);
  for i := 0 to CFY.nVarsContinuas - 1 do
  begin
    aVar := evaluador.FindVar('$Y_' + CFY.xr_Def[i].nombre);
    if aVar <> nil then
    begin
      yrs[cnt_y] := aVar;
      iyrs[cnt_y] := i;
      Inc(cnt_y);
    end
    else
    begin
      k_desaparecidas_continuas[cnt_desaparecidas_continuas] := i;
      Inc(cnt_desaparecidas_continuas);
    end;
  end;

  setlength(yrs, cnt_y);
  setlength(iyrs, cnt_y);
  setlength(k_desaparecidas_continuas, cnt_desaparecidas_continuas);

  setlength(k_desaparecidas_discretas, length(CFY.xd_def));
  cnt_y := 0;
  cnt_desaparecidas_discretas := 0;

  setlength(yds, CFY.nVarsDiscretas);
  setlength(iyds, CFY.nVarsDiscretas);
  for i := 0 to CFY.nVarsDiscretas - 1 do
  begin
    aVar := evaluador.FindVar('$Y_' + CFY.xd_Def[i].nombre);
    if aVar <> nil then
    begin
      yds[cnt_y] := aVar;
      iyds[cnt_y] := i;
      Inc(cnt_y);
    end
    else
    begin
      k_desaparecidas_discretas[cnt_desaparecidas_discretas] := i;
      Inc(cnt_desaparecidas_discretas);
    end;
  end;

  setlength(yds, cnt_y);
  setlength(iyds, cnt_y);
  setlength(k_desaparecidas_discretas, cnt_desaparecidas_discretas);

  hay_desaparecidas := (cnt_desaparecidas_continuas + cnt_desaparecidas_discretas) > 0;

  if hay_desaparecidas then
  begin
    // si se va a precisar iterar en los estados perdidos de CFAux ponemos
    // los contadores de las discretizaciones para poder iterar.
    setlength(contadores_continuas, cnt_desaparecidas_continuas);
    setlength(contadores_discretas, cnt_desaparecidas_discretas);
    for k := 0 to high(contadores_continuas) do
      contadores_continuas[k] := CFY.xr_def[k_desaparecidas_continuas[k]].NPuntos;
    for k := 0 to high(contadores_discretas) do
      contadores_continuas[k] := CFY.xd_def[k_desaparecidas_discretas[k]].NPuntos;
  end;

end;


function TCursorMapeoCF.Val(dt: TDateTime): NReal;

var
  costoAux: NReal;
  i: integer;
  recorriendo_desaparecidas: boolean;
  kpr: NReal;
  alfa, beta: NReal;
  kp1, kp2: integer;


begin

   { self.dt:= dt;


   kpr := ( dt - CFY.fechaIni.dt) * 24.0 / CFY.horasDelPaso + 1;
     alfa := frac(kpr);
     beta := 1 - alfa;
     kp1 := trunc(kpr);
     kp2 := kp1 + 1;

     if (kp1 < CFY.Primer_kPuntoT ) or (kp2 > CFY.Ultimo_kPuntoT ) then
         raise Exception.Create(
           'TAdminEstados.InicializarFrameFinal: se desea enganchar el ' +
           DateTimeToIsoStr( dt ) + ' y el archivo de costo futuro con que desea enganchar va desde el '
           + CFY.fechaIni.AsStr + ' hasta el ' + CFY.fechaFin.AsStr +
           '.'#10'La fecha de enganche debe estar contenida dentro del período de optimización del archivo CF.bin');




     }
  //Cargamos variables "X" según estado actual
    for i := 0 to CFX.nVarsContinuas - 1 do
      xrs[i].val.Val_F := CFX.xr[i];
    for i := 0 to CFX.nVarsDiscretas - 1 do
      xds[i].val.Val_I := CFX.xd[i];

    // cargo y ejecuto las funciones Y=f(X)
    //    evaluador.Ejecutar(s);
    aScript.evaluar;

    // leemos los resultados
    for i := 0 to high(yrs) do
    begin
//   writeln( iyrs[i], ': ', yrs[i].ValAsFloat );
      CFY.xr[iyrs[i]] := yrs[i].ValAsFloat;
    end;

    for i := 0 to high(yds) do
      CFY.xd[iyds[i]] := yds[i].ValAsInt;

    if (hay_desaparecidas) then
    begin
      costoAux := 0;
      cnt_ := 0;
      recorriendo_desaparecidas := True;
      CFY.SetEstrellaCERO_indexada(contadores_continuas, contadores_discretas);
      while recorriendo_desaparecidas do
      begin
        // fijamos los valores de las indexaddas
        for i := 0 to high(k_desaparecidas_continuas) do
          CFY.xr[k_desaparecidas_continuas[i]] := contadores_continuas[i];

        for i := 0 to high(k_desaparecidas_discretas) do
          CFY.xd[k_desaparecidas_discretas[i]] := contadores_discretas[i];

        if abs(alfa) > AsumaCero then
          costoAux := costoAux + CFY.costoContinuo(kp1) * beta +
            CFY.costoContinuo(kp2) * alfa
        else
          costoAux := costoAux + CFY.costoContinuo(kp1);
        Inc(cnt_);

        recorriendo_desaparecidas :=
          CFY.IncEstrella_indexada(contadores_continuas,
          contadores_discretas, k_desaparecidas_continuas,
          k_desaparecidas_discretas);

      end;
      costoAux := costoAux / cnt_;
    end
    else
    begin
      if abs(alfa) > AsumaCero then
        costoAux := CFX.costoContinuo(kp1) * beta +
          CFX.costoContinuo(kp2) * alfa
      else
        costoAux := CFX.costoContinuo(kp1);
    end;

  result:= CostoAux;

end;

destructor TCursorMapeoCF.destroy;
begin
  setlength(yrs, 0);
  setlength(iyrs, 0);
  setlength(k_desaparecidas_continuas, 0);
  setlength(yds, 0);
  setlength(iyds, 0);
  setlength(k_desaparecidas_discretas, 0);
  setlength(contadores_continuas, 0);
  setlength(contadores_discretas, 0);

  evaluador.Free;
  CFX:= nil;
  CFY.Free;

  inherited destroy;
end;

end.

