program TestAB;
{
 This program is a crude implementation of the AlphaBeta
 algorithm found in Kreutzer & MacKenzie p. 233.
}
  const
    MaxNum = 2;  {node degree}
    NumPly = 4;  {search ply}
    Root = 1;    {start search at this location}
 
  type
    Index = 1..50;
    Tree = array[Index] of Real;     {simulated game tree}
    State = Index;
    Ply = Integer;
    ListIndex = 1..MaxNum;
    List = array[ListIndex] of Real; {state siblings}
 
  var
    T : Tree;
 
  procedure Init(var T : Tree);
  {
   Build dummy game tree.
  }
  var
    I : Index;
 
  begin {Init}
    for I := 16 to 31 do       {blank out 4-ply leaf nodes}
      T[I] := 0;
  end; {Init}
 
  function Eval (S : State) : Real;
  {
   Compute value of state S.
  }
  begin {Eval}
    Eval := Random(101);
  end; {Eval}
 
  function Terminal(S : State) : Boolean;
  {
   Stub function to check S for succesor states.
  }
  begin {Terminal}
    Terminal := False;
  end; {Terminal}
 
  function Max(X, Y : Real) : Real;
  {
   Returns maximum of X and Y.
  }
  begin {Max}
    if X > Y then
      Max := X
    else
      Max := Y
  end; {Max}
 
  function Min(X, Y : Real) : Real;
  {
   Returns minimum of X and Y.
  }
  begin {Min}
    if X < Y then
      Min := X
    else
      Min := Y
  end; {Min}
 
  function Child(S : State; I : ListIndex) : State;
  {
   Compute I-th successor of state S.
  }
  begin {Child}
    Child := MaxNum * S + I - 1;
  end; {Child}
 
  function MachineMove(N : Ply) : Boolean;
  {
   Checks to see if it is computer's move in this ply.
  }
  begin {MachineMove}
    MachineMove := { not } Odd(N)
  end; {MachineMove}
 
  function AlphaBeta(S : State; N : Ply; Alpha, Beta : Real) : Real;
  {
   Recusively score state S using evaluation function Eval
   and an N - Ply state space graph.
  }
    var
      Next      : State;
      I         : ListIndex;
      V, Value,
      BestScore : Real;
      L         : List; {successors of S at this level}
 
  begin {AlphaBeta}
    if (N = 0) or Terminal(S) then
      begin
        Value := Eval(S);
 
        T[S] := Value;  {record values only to confirm cut offs}
 
        if Value > 100 then         {machine win}
          AlphaBeta := MaxInt
        else if Value < -100  then  {machine loss}
          AlphaBeta := -MaxInt
        else if Value = 0 then      {draw}
          AlphaBeta := 0
        else
          AlphaBeta := Value
      end
    else
      begin
        if MachineMove(N) then            {program's move}
          BestScore := Alpha
        else
          BestScore := Beta;
 
        I := 1;
        while I <= MaxNum do
          begin
            Next := Child(S, I);
            V := AlphaBeta(Next, N - 1, Alpha, Beta);
 
            if MachineMove(N) then        {program's move}
              begin
                BestScore := Max(V, BestScore);
                Alpha := BestScore;
                if Alpha >= Beta then
                  begin
                    BestScore := Beta;
                    I := MaxNum;        {prune remaining S successors}
                  end
              end
            else
              begin
                BestScore := Min(V, BestScore);
                Beta := BestScore;
                if Alpha >= Beta then
                  begin
                    BestScore := Alpha;
                    I := MaxNum;        {prune remaining S successors}
                  end
              end;
            I := I + 1;
          end;
        AlphaBeta := BestScore;
      end
  end; {AlphaBeta}
 
begin {TestAB}
  Randomize;
  Init(T);
  WriteLn('Value = ', AlphaBeta(Child(Root, 1), NumPly - 1, -MaxInt, MaxInt));
  WriteLn('Value = ', AlphaBeta(Child(Root, 2), NumPly - 1, -MaxInt, MaxInt));
end. {TestAB}
