# Alpha-beta pruning algorithm with Delphi

I'm trying to get round to writing more often and to do my own research with some interesting and complicated algorithms. Given to my great passion for different types of algorithms, in AI , I have found one very interesting and here you can get it build with Delphi 2010. With this solution, you'll be able to add values to the leaves and run the algorithm to find the nodes that will be evaluated and others that will be pruned. I've used my little framework to build the structure (using a GDI render) and then only focus on the algorithm that was the important part. Alpha-beta pruning is a search algorithm which seeks to reduce the number of nodes that are evaluated in the search tree by the minimax algorithm. It is a search with adversary algorithm used commonly for machine playing of two-player games (Tic-tac-toe, Chess, Go, etc.). It stops completely evaluating a move when at least one possibility has been found that proves the move to be worse than a previously examined move. Such moves need not be evaluated further. Alpha-beta pruning is a sound optimization in that it does not change the result of the algorithm it optimizes (Algorithmist.com).

The pseudo-code is quite simple, and it looks like this:
The structure of the application is very simple and the most difficult part is the simulation process where you need to draw every step of the algorithm.
You can download the application from here (Thundax Alpha-beta pruning) and play with it to understand how the algorithm works.
This video shows the execution of the program:
The code of the algorithm is explained as follows:

Alpha-beta algorithm:
```function TViewMinimax.alphabeta(Node: TNode; alpha: integer; beta: integer): integer;
var
i: integer;
ret: integer;
begin
if Node.isLeaf then
ret := Node.Value
else
begin
for i := 0 to Node.children.Count - 1 do
begin
alpha := max(alpha, -alphabeta(Node.children.Items[i], -beta, -alpha));
case Node.player of
tMAX:
begin
Node.Value := alpha;
SetAlpha(Node, alpha);
Node.visited := true;
end;
tMIN:
begin
Node.Value := -alpha;
SetBeta(Node, alpha);
Node.visited := true;
end;
end;
if beta <= alpha then
Break;
end;
ret := alpha;
end;
result := ret;
end;
```

Drawing the nodes by using a pre-order method for iterating the binary tree:
```procedure TViewMinimax.Draw;
begin
preorder(Self.FMinimax.root);
end;

procedure TViewMinimax.preorder(root: TNode);
begin
if Assigned(root) then
begin
if root.children.Count > 0 then
begin
DrawLine(root, root.children.Items[0]);
DrawLine(root, root.children.Items[1]);
preorder(root.children.Items[0]);
preorder(root.children.Items[1]);
end;
DrawRectangle(root);
end;
end;

procedure TViewMinimax.DrawRectangle(Node: TNode);
begin
Fcanvas.Font.Name := 'Arial';
Fcanvas.Brush.Style := bsSolid;
if Node.visited then
Fcanvas.Brush.Color := clRed
else
Fcanvas.Brush.Color := clWhite;
if Node.selected then
Fcanvas.Brush.Color := clGreen;
Fcanvas.Pen.Width := 2;
Fcanvas.Pen.Color := clBlack;
Fcanvas.Rectangle(Node.position.x - gap, Node.position.y - gap, Node.position.x + gap, Node.position.y + gap);
Fcanvas.TextOut(Node.position.x - 5, Node.position.y - 5, Inttostr(Node.Value));
Fcanvas.Brush.Color := clWhite;
if (Node.isLeaf) and (Node.Order <> 0) then
Fcanvas.TextOut(Node.position.x - 5, Node.position.y + 15, Inttostr(Node.Order));
if not Node.isLeaf then
begin
case Node.player of
tMAX:
begin
if Node.alpha <> 0 then
Fcanvas.TextOut(Node.position.x - 65, Node.position.y - 10, Inttostr(Node.Order) + ': a=' + Inttostr(Node.alpha));
if Node.newAlpha <> 0 then
Fcanvas.TextOut(Node.position.x - 65, Node.position.y + 5, Inttostr(Node.NewOrder) + ': a=' + Inttostr(Node.newAlpha));
end;
tMIN:
begin
if Node.beta <> 0 then
Fcanvas.TextOut(Node.position.x - 65, Node.position.y - 10, Inttostr(Node.Order) + ': ß=' + Inttostr(Node.beta));
if Node.Newbeta <> 0 then
Fcanvas.TextOut(Node.position.x - 65, Node.position.y + 5, Inttostr(Node.NewOrder) + ': ß=' + Inttostr(Node.Newbeta));
end;
end;
if Node.text <> '' then
begin
Fcanvas.Brush.Color := clyellow;
if (Node.newAlpha = 0) and (Node.Newbeta = 0) then
Fcanvas.TextOut(Node.position.x - 53, Node.position.y + 5, Node.text)
else
Fcanvas.TextOut(Node.position.x - 53, Node.position.y + 20, Node.text)
end;
end;
end;
```

Setting up the Minimax Algorithm:
```procedure TForm1.Start1Click(Sender: TObject);
var
vminimax: TViewMinimax;
minimax: TMinimax;
words: TStringList;
alpha, beta: integer;
begin
minimax := TMinimax.Create;
if Edit1.Text <> '' then
begin
words := TStringList.Create;
SplitTextIntoWords(Edit1.Text, words);
end;
minimax.CreateTree;
Memo1.Lines.Clear;

Image1.Canvas.Brush.color := clwhite;
Image1.Canvas.Rectangle(0, 0, Image1.Width, Image1.Height);

vminimax := TViewMinimax.Create(Self.Image1.Canvas, minimax, Memo1);
if CheckBox1.Checked then
vminimax.time := 1000
else
vminimax.time := 0;
alpha := alphavalue;
beta := betavalue;

vminimax.Draw;
Self.Image1.Canvas.TextOut(951, 25 - 5, 'MAX');
Self.Image1.Canvas.TextOut(951, 127 - 5, 'MIN');
Self.Image1.Canvas.TextOut(951, 228 - 5, 'MAX');
Self.Image1.Canvas.TextOut(951, 328 - 5, 'MIN');

Start1.Enabled := false;
CheckBox1.Enabled := false;
vminimax.alphabeta(minimax.root, alpha, beta);
vminimax.Draw;
Start1.Enabled := true;
CheckBox1.Enabled := true;

FreeAndNil(words);
FreeAndNil(minimax);
FreeAndNil(vminimax);
end;
```

Splitting the text into numbers (comma separated values):
```procedure SplitTextIntoWords(const S: string; words: TstringList);
var
startpos, endpos: Integer;
begin
Assert(Assigned(words));
words.Clear;
startpos := 1;
while startpos <= Length(S) do
begin
while (startpos <= Length(S)) and (S[startpos] = ',') do
Inc(startpos);
if startpos <= Length(S) then
begin
endpos := startpos + 1;
while (endpos <= Length(S)) and not (S[endpos] = ',') do
Inc(endpos);