There we have easy pseudocode for AB:
Code: Select all
int AlphaBeta(int tiefe, int alpha, int beta)
{
if (tiefe == 0)
return Bewerten();
BOOL PVgefunden = FALSE;
best = -unendlich;
Zugliste = GeneriereMoeglicheZuege();
for each (Zug in Zugliste)
{
FuehreZugAus(Zug);
if (PVgefunden)
{
wert = -AlphaBeta(tiefe-1, -alpha-1, -alpha);
if (wert > alpha && wert < beta)
wert = -AlphaBeta(tiefe-1, -beta, -wert);
} else
wert = -AlphaBeta(tiefe-1, -beta, -alpha);
MacheZugRueckgaengig(Zug);
if (wert > best)
{
if (wert >= beta)
return wert;
best = wert;
if (wert > alpha)
{
alpha = wert;
PVgefunden = TRUE;
}
}
}
return best;
}
Now we switch reference frames. GeneriereMoeglicheZuege becomes generate all possible AB Threads. Where each thread doesnt doesnt deepen by only the first move (according to sorting) but 1,2,3,4 depending on threadid and skips the other ones. That is AB on top of AB. This will find the optimal threadid which in turn has the optimal move. Repeated searches would have to be stopped so we still need a TT.
Seems to me that parallelsisation is possible after all.
The main reason why this works is that move sorting is not (and cannot be) perfect. If move ordering were perfect you wouldnt need a search.
So branching into moves[0] first and having a concurrent thread that branches into moves[1] at the same time is a very smart thing. All you need is a config parameter that contains the bitmask of what to skip and what to branch into.
The way you skip the expensive synchronisation is having not each thread talk to each other 32*32 but you have the context of an AB tree on top of that. So communication is 32*1.
I see that maybe the smartest move may be (offset in the moves going down the stack) 3,1,0,1,2,1
With perfect move ordering it would be 0,0,0,0,0 -> but this is literally impossible to sort. And thats why parallelisation is not only possible - but overall the faster solution.
Cool Idea!