In BozoChess, a chess move is not packed into a single scalar type but instead is a structure of unpacked data. This works well as there is no packing/unpacking overhead and there is little need to actually move the move data from place to place.
A move can live inside a move node structure which is simply an element of a two-way linked list. Each node is initially allocated by a library call, but thereafter the node can be moved from list to list just by changing a few pointers. The dynamic storage is releases via library calls only when the list is destroyed.
A variation structure is composed of two move lists. The first is the used lust which contains the moves of interest. The second is the free node list which contains free nodes which are used for appending new moves to the used list as needed. When a move node is released form the used list, it is appended to the free list for later use. The big idea here is to not call an slow library memory management routine each time a variation needs adjustment.
Using the variation data structure greatly simplifies handling predicted variations at all ply. It's also good for handling the current variation (i.e., path from the root) for tracing and debugging.
Code: Select all
{ Chess move: a single move with a score value }
movetype =
record
frsq: sqtype; { From square }
tosq: sqtype; { To square }
frman: mantype; { From man }
toman: mantype; { To man }
msc: msctype; { Special case }
mfs: mfstype; { Move flag set }
sv: svtype { Score value }
end;
{ Move nodes }
mnptrtype = ^mntype; { A pointer to a move node }
mntype =
record
move: movetype; { The move }
prev: mnptrtype; { Link to previous move node }
next: mnptrtype { Link to next move node }
end;
{ List of move nodes }
mnlisttype =
record
ecount: ecounttype; { Element count }
head: mnptrtype; { Head of move node list }
tail: mnptrtype { Tail of move node list }
end;
{ Variation }
variationtype =
record
freelist: mnlisttype; { Free move nodes }
usedlist: mnlisttype { Move nodes in played order }
end;
{ ***** Variation routines ***** }
procedure VariationReset(var variation: variationtype);
begin
with variation do
begin
MnListReset(freelist);
MnListReset(usedlist)
end
end; { VariationReset }
procedure VariationRecycleTail(var variation: variationtype);
begin
with variation do
MnListAppendTail(freelist, MnListDetachTail(usedlist))
end; { VariationRecycleTail }
procedure VariationRecycle(var variation: variationtype);
begin
with variation do
while usedlist.tail <> nil do
VariationRecycleTail(variation)
end; { VariationRecycle }
procedure VariationAppendMove(var variation: variationtype; var move: movetype);
var
mnptr: mnptrtype;
begin
with variation do
begin
if freelist.tail = nil then
begin
New(mnptr);
MnListAppendTail(freelist, mnptr)
end;
mnptr := MnListDetachTail(freelist);
mnptr^.move := move;
MnListAppendTail(usedlist, mnptr)
end
end; { VariationAppendMove }
procedure VariationAppend(var variation, subvariation: variationtype);
var
mnptr: mnptrtype;
begin
with variation do
begin
mnptr := subvariation.usedlist.head;
while mnptr <> nil do
begin
VariationAppendMove(variation, mnptr^.move);
mnptr := mnptr^.next
end
end
end; { VariationAppend }
procedure VariationAssign(var variation, altvariation: variationtype);
begin
VariationRecycle(variation);
VariationAppend(variation, altvariation)
end; { VariationAssign }
procedure VariationBuild(
var variation: variationtype;
var move: movetype; var subvariation: variationtype);
begin
VariationRecycle(variation);
VariationAppendMove(variation, move);
VariationAppend(variation, subvariation)
end; { VariationBuild }
procedure VariationNotate(var variation: variationtype; var pos: postype);
var
mnptr: mnptrtype;
count: ecounttype;
begin
with variation do
begin
count := 0;
mnptr := usedlist.head;
while mnptr <> nil do
begin
PosMoveNotate(pos, mnptr^.move);
PosExecute(pos, mnptr^.move);
Inc(count);
mnptr := mnptr^.next
end;
while count > 0 do
begin
PosRetract(pos);
Dec(count)
end
end
end; { VariationNotate }
function VariationPosEncode(var variation: variationtype; var pos: postype): String;
var
myresult: String;
mnptr: mnptrtype;
mc: mctype;
begin
with variation do
begin
myresult := '';
VariationNotate(variation, pos);
PosLoadToMc(pos, mc);
mnptr := usedlist.head;
while mnptr <> nil do
begin
if (mc.good = colorw) or (mnptr = usedlist.head) then
myresult := myresult + McEncode(mc) + ' ';
myresult := myresult + MoveEncode(mnptr^.move);
McIncrement(mc);
mnptr := mnptr^.next;
if mnptr <> nil then
myresult := myresult + ' '
end
end;
VariationPosEncode := myresult
end; { VariationPosEncode }
procedure VariationInit(var variation: variationtype);
begin
with variation do
begin
MnListInit(freelist);
MnListInit(usedlist)
end
end; { VariationInit }
procedure VariationTerm(var variation: variationtype);
begin
with variation do
begin
MnListTerm(freelist);
MnListTerm(usedlist)
end
end; { VariationTerm }