hgm wrote: ↑Fri May 14, 2021 1:34 pm
You mean the u->searched++; and the nodeCnt++;? The latter is the (global) total node count for calculatin the nps. u->searched is local to the node, and is used at the end of the node to determine whether that node was a leaf or not. For the purpose of counting the number of leaf nodes.
int Search(UndoInfo *u) // pass all parameters in a struct
{
UndoInfo undo;
int pvMove;
int curMove, noncapts = 10000;
undo.pv = pvPtr;
undo.first = msp;
nodeCnt++;
......................
if(PATH) printf(" new=%08x existing=%08x worse=%08x\n undetected=%08x todo=%08x\n", u->newThreats, u->existingThreats, worseThreats, u->undetectedThreats, todo);
if(!todo && gap > 0) { // opponent has no non-futile move
u-> parentAlpha = -u->alpha; // fail-high score (-u->alpha is parent's beta)
attackers -= SZ; presence[stm] = u->oldPresence; // undo updates
u->searched++; nodeCnt++; qsCnt += (u->depth <= 0);
return 1; // and abort move ('overkill pruning')
............................
}
two increment in one node.
OK, I see. This is not twice, it either uses one or the other.
At some point I split the code in Search() over two routines, introcin a routine SearchCapture(), which also incorporated the tasks of MakeMove() and UnMake(). So Search() no longer calls itself recursively (for captures), but the calling graph is Search -> SearchCapture -> Search. The combination (SearchCapture, Search) thus does what in a more conventional design would be done by Search(), and this is what I count as a node. (To be able to compare with conventional desins.) But SearchCapture() doesn't always call Search(); when no (non-futile) captures can be generated it returns before the move sorting and the move loop (which are in Search()).
But I have to increment nodeCnt in Search() to also count the invocations through non-captures. So there needs to be a conditional increment in SearchCapture(), which only increments nodeCnt when it doesn't continue callin Search().
hgm wrote: ↑Fri May 14, 2021 1:34 pm
You mean the u->searched++; and the nodeCnt++;? The latter is the (global) total node count for calculatin the nps. u->searched is local to the node, and is used at the end of the node to determine whether that node was a leaf or not. For the purpose of counting the number of leaf nodes.
int Search(UndoInfo *u) // pass all parameters in a struct
{
UndoInfo undo;
int pvMove;
int curMove, noncapts = 10000;
undo.pv = pvPtr;
undo.first = msp;
nodeCnt++;
......................
if(PATH) printf(" new=%08x existing=%08x worse=%08x\n undetected=%08x todo=%08x\n", u->newThreats, u->existingThreats, worseThreats, u->undetectedThreats, todo);
if(!todo && gap > 0) { // opponent has no non-futile move
u-> parentAlpha = -u->alpha; // fail-high score (-u->alpha is parent's beta)
attackers -= SZ; presence[stm] = u->oldPresence; // undo updates
u->searched++; nodeCnt++; qsCnt += (u->depth <= 0);
return 1; // and abort move ('overkill pruning')
............................
}
two increment in one node.
OK, I see. This is not twice, it either uses one or the other.
At some point I split the code in Search() over two routines, introcin a routine SearchCapture(), which also incorporated the tasks of MakeMove() and UnMake(). So Search() no longer calls itself recursively (for captures), but the calling graph is Search -> SearchCapture -> Search. The combination (SearchCapture, Search) thus does what in a more conventional design would be done by Search(), and this is what I count as a node. (To be able to compare with conventional desins.) But SearchCapture() doesn't always call Search(); when no (non-futile) captures can be generated it returns before the move sorting and the move loop (which are in Search()).
But I have to increment nodeCnt in Search() to also count the invocations through non-captures. So there needs to be a conditional increment in SearchCapture(), which only increments nodeCnt when it doesn't continue callin Search().
Hi Martin — welcome back (it's tough to truly kick this addiction ). I'm looking forward to the new version of Colossus, or maybe "White Knight"? I can still remember playing White Knight on a BBC computer while still at school.
Thanks Steve
It is indeed an addiction! I remember talking to Jonathan Schaeffer back in the Chinook days and likening it to a disease that goes into remission before flaring up again... I called it "engine fever"!
I'd better not have another eleven years off though as I might not have that many years left!
hgm wrote: ↑Fri May 14, 2021 1:34 pm
I am not sure where the 5.9Mnps was achieved. The latest state was 8.0Mnps, on a 2.2GHz i3 CPU. Also not sure if I uploaded the exact source of that version; I do not consider this final, but I had to take a break from the project to tend to other matters.
r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1
depth 12
So mailbox was 1.66 times faster (10.2 Mnps vs 6.1Mnps)?
How can you have such a large number of nodes at 1 ply? You have more than 100 times as many as the reference search!
I don't quite understand your question about SEE. There is no SEE in the reference search. Just MVV/LVA ordering. The node starts by generating captures, and determining the MVV-wise best. If that doesn't stand any chance to get above alpha, it is done. This happens in SearchCapture(). If there is a capture to search, it goes on to call Search().
Sure, that makes it difficult to compare different programs. It could also depend on how exactly you count nodes, how you handle futility pruning, perhaps even which margins you use, etc. This is why I made a reference search, with a clearly specified task.