{$APPTYPE CONSOLE}
{$RANGECHECKS ON}
program RandD(output);

uses SysUtils;

const
  MaxBranch = 4; MaxNode = 15; NumSVariables = 14;
  SPEED = 1; TURBINE = 2; CLEAR = 3; CEV1 = 4; CEV2 = 5;
  CEV3 = 6; CEV = 7; COST = 8; CV = 9; TEV = 10;
  FV = 11; MV = 12; LFV = 13; SHP = 14;
  CHANCE = 1; DECISION = 2; ENDPOINT = 3; AUXILIARY = 4;
  INFINITY = 1.0e30;
  

type
  real = double;
  State = array[1 .. NumSVariables] of real;

var
  i, k  : integer;
  b, t, v  : array[1 .. MaxNode] of integer;
  s  : State;

function u(x : real) : real; begin
  u := x
end;

function FCEV1(j:integer; var s : State): real; begin
  case j of
    1 : case round(s[CLEAR]) of
         1 : FCEV1 := -0.5; 2 : FCEV1 :=  2.0; 3 : FCEV1 :=  0.0;
        end;
    2 : case round(s[CLEAR]) of
         1 : FCEV1 :=  0.0; 2 : FCEV1 :=  3.2; 3 : FCEV1 :=  3.5;
        end;
    3 : case round(s[CLEAR]) of
         1 : FCEV1 :=  0.5; 2 : FCEV1 :=  4.0; 3 : FCEV1 :=  4.0;
        end;
  end
end;


function FCEV (var s : State): real; 
  var
    IntCLEAR : integer;
  begin
    IntCLEAR := round(s[CLEAR]);
    if ((IntCLEAR = 1) or (IntCLEAR = 2)) then FCEV := s[CEV1]
    else if ((IntCLEAR = 3) and (s[CEV1] >= 3.5)) 
          then FCEV := s[CEV1]
    else if ((IntCLEAR = 3) and (s[CEV1] < 3.5) 
             and (s[CEV2] >= 4.0)) then FCEV := s[CEV2]
    else FCEV := s[CEV3]
  end;

function c1(var s : State) : real; begin
  case round(s[SPEED]) of
    1 : c1 := 100000; 
    2 : c1 := 125000;
  end;
end;

function c2(var s : State) : real; begin
  case round(s[TURBINE]) of
    1 : c2 := 100000; 
    2 : c2 := 300000; 
    3 : c2 := 400000; 
    4 : c2 := 800000;
  end;
end;

function c3(var s : State) : real; 
  var
    IntCLEAR : real;
  begin
    IntCLEAR := round(s[CLEAR]);
    if(IntCLEAR = 1) then c3 := 0.0
    else if (IntCLEAR = 2) then c3 := 50000
    else if ((IntCLEAR = 3) and (s[CEV1] >= 3.5)) then c3 := 100000
    else if ((IntCLEAR = 3) and (s[CEV1] < 3.5) and (s[CEV2] >= 4.0)) 
       then c3 := 200000
    else c3 := 300000;
end;

function FCV(j:integer; var s : State): real; begin
  case j of
    1 : case round(s[CLEAR]) of
         1, 2 : FCV := -0.1;
         3    : FCV := -0.5;
        end;
    2 : case round(s[CLEAR]) of
         1, 2 : FCV :=  0.0;
         3    : FCV := -0.1;
        end;
    3 : case round(s[CLEAR]) of
         1, 2 : FCV :=  0.1;
         3    : FCV :=  0.3;
         end;
  end;
end;

function FTEV(j:integer; var s : State): real; begin
  case j of
    1 : case round(s[SPEED]) of
         1: case round(s[TURBINE]) of
             1 : FTEV := -0.25; 
             2 : FTEV :=  0.00;
             3 : FTEV :=  0.30; 
             4 : FTEV :=  0.50;
             end;
         2: case round(s[TURBINE]) of
             1 : FTEV := -0.75; 
             2 : FTEV := -0.50;
             3 : FTEV := -0.20; 
             4 : FTEV := -0.10;
             end;
        end;
    2 : case round(s[SPEED]) of
         1: case round(s[TURBINE]) of
             1 : FTEV := 0.50; 
             2 : FTEV := 0.75;
             3 : FTEV := 0.875; 
             4 : FTEV := 1.00;
             end;
         2: case round(s[TURBINE]) of
             1 : FTEV := 0.25; 
             2 : FTEV := 0.50;
             3 : FTEV := 0.625; 
             4 : FTEV := 0.75;
             end;
        end;
    3 : case round(s[SPEED]) of
         1: case round(s[TURBINE]) of
             1 : FTEV := 1.25; 
             2 : FTEV := 1.25;
             3 : FTEV := 1.375; 
             4 : FTEV := 1.50;
             end;
         2: case round(s[TURBINE]) of
             1 : FTEV := 1.25; 
             2 : FTEV := 1.25;
             3 : FTEV := 1.375; 
             4 : FTEV := 1.50;
             end;
        end;
  end;
end;

function vs(var s : State) : real ; begin
  vs := (1-exp(-(s[SHP]+2)/8.312))/0.763946
end;

function vc(var s : State) : real ; begin
  vc := (1200000-s[COST])/1000000
end;

function f(i, j : integer; var s : State) : real; begin
  case i of
    1 : case j of
         1 : f := 1; 
         2 : f := 2;
        end;
    2 : case j of
         1 : f := 1; 
         2 : f := 2; 
         3 : f := 3; 
         4 : f := 4;
        end;
    3 : case j of
         1 : f := 1; 
         2 : f := 2; 
         3 : f := 3;
        end;
    4 : f := FCEV1(j, s);
    5,6 : case j of
         1 : f := 1.5; 
         2 : f := 4.0; 
         3 : f := 5.5;
        end;
      7 : f := FCEV(s);
      8 : f := c1(s) + c2(s) + c3(s);
      9 : f := FCV(j, s);
     10 : f := FTEV(j, s);
    11  : case j of
         1 : f := -0.01; 
         2 : f :=  0.00; 
         3 : f :=  0.01;
        end;
    12  : case j of
         1 : f := -0.5; 
         2 : f :=  0.0; 
         3 : f :=  0.5;
        end;
    13  : case j of
         1 : f := -0.4; 
         2 : f :=  0.0; 
         3 : f :=  0.4;
        end;
    14 : f :=  0.167*s[CEV] + s[CV] + 10.47*s[TEV] 
                 + 27.4*s[FV] + s[MV] + s[LFV];
    15 : f := 0.3*vs(s) + 0.7*vc(s);
  end;
end;

function n(i, j : integer; var s : State) : integer;
var
  FindCLEAR : integer;
begin
  case i of
    1 .. 3, 6 .. 14 : n := i + 1;
    4               : begin
                        FindCLEAR := round(s[CLEAR]);
                        if (FindCLEAR in [1, 2]) then n := 7
                        else if ((FindCLEAR = 3) and (j in [2,3]))
                          then n := 7
                        else n := 5;
                      end;
    5               : case j of
                       1 : n := 6;
                       2,3 : n := 7;
                      end;
  end;
end;

function p(i, j : integer; var s : State) : real; begin
  case i of
    4 .. 6, 9 .. 13 : case j of
         1, 3 : p := 0.3;
         2 :    p := 0.4;
    end;
  end;
end;

function EU(i : integer; var s : State) : real;
  var
    j : integer;
    NewEU, TryEU : real;
  begin
    case t[i] of
      CHANCE : begin
                 NewEU := 0.0;
                 for j := 1 to b[i] do begin
                   s[v[i]] := f(i, j, s);
                   NewEU := NewEU + p(i, j, s) * EU(n(i, j, s), s)
                 end;
                 EU := NewEU
               end;
      DECISION : begin
                   NewEU := -INFINITY;
                   for j := 1 to b[i] do begin
                     s[v[i]] := f(i, j, s);
                     TryEU := EU(n(i, j, s), s);
                     if TryEU > NewEU then NewEU := TryEU
                   end;
                   EU := NewEU
                 end;
      ENDPOINT : EU := u(f(i, 1, s));
      AUXILIARY : begin
                    s[v[i]] := f(i, 1, s);
                    EU := EU(n(i, 1, s), s)
                  end
    end
end;

procedure EvalDecNode(i : integer; var s : State);
  var
    j : integer;
    MaxEU : real;
    HoldEU : array[1 .. MaxBranch] of real;
  begin
    MaxEU := -INFINITY;
    for j := 1 to b[i] do begin
      s[v[i]] := f(i, j, s);
      HoldEU[j]  := EU(n(i, j, s), s);
      if HoldEU[j] > MaxEU then MaxEU := HoldEU[j]
    end;
    writeln('Exp. Utility = ', MaxEU:12:3);
    writeln('Branch  Exp. Utility');
    for j := 1 to b[i] do begin
      write(j:4, HoldEU[j]:16:3);
      if HoldEU[j] = MaxEU then writeln(' <--') else writeln
    end
end;

begin {main program}
  for i := 1 to 3 do t[i] := DECISION; 
  for i := 4 to 13 do t[i] := CHANCE; 
  t[7] := AUXILIARY; t[8] := AUXILIARY;
  t[14] := AUXILIARY; t[15] := ENDPOINT;
  
  b[1] := 2; b[2] := 4; b[3] := 3; b[4] := 3; b[5] := 3; b[6] := 3;
  b[9] := 3; b[10] := 3; b[11] := 3; b[12] := 3; b[13] := 3;

  v[1] := SPEED; v[2] := TURBINE; v[3] := CLEAR; v[4] := CEV1;
  v[5] := CEV2; v[6] := CEV3; v[7] := CEV; v[8] := COST;
  v[9] := CV; v[10] := TEV; v[11] := FV; v[12] := MV;
  v[13] := LFV; v[14] := SHP;

  writeln('Start time: ', TimeToStr(Time));
  EvalDecNode(1, s);
  writeln('Middle time: ', TimeToStr(Time));

  for i := 1 to b[1] do begin
    s[v[1]] := f(1,i,s);
    for k := 1 to b[2] do begin
      writeln;
      s[v[n(1,i,s)]] := f(n(1,i,s),k,s);
      EvalDecNode(n(n(1,i,s), k, s), s)
    end
  end;
  writeln('End time: ', TimeToStr(Time));
end.

        
        