chrisw wrote:bob wrote:chrisw wrote:bob wrote:Uri Blass wrote:Guetti wrote:chrisw wrote:Bob argued that the existence in the Rybka code of setjmp() was "interesting" because this also existed in Fruit and nowhere else.
Uri pointed out that Tom Kerrigan's public program TSCP also used setjmp() and that some other programs were likely/possibly developed, legally, off TSCP as basis.
I'm an engine programmer and always had user interface programmers working in support, so I got very lazy and understand very little about DOS, windows, C support functions and so on. setjmp() knowledge is no way a speciality of mine.
However, casting my mind back many years, I'm fairly sure that the Ren Wu Chess program which was also worked on by Ren at Oxford Softworks used setjmp() to unwind the search on a timeout. CSTal, by contrast, did a proper search unwind.
There are two ways to exit Search() on a timeout or user intervention. The 'correct' way, I suppose, is to unwind the Search back to the start using unmove simultaneously unstacking the variables.
The brutal and simple way is simply to jump straight out, reseting the stack pointer. I guess this is setjmp().
I'l be very surprised if numbers of programs, especially those designed years ago without SMP in mind, didn't use the brutal setjmp() technique to break the search.
Bottom line: setjmp() is not unique and its use doesn't imply anything, certainly it cannot imply copied code.
Leaving the setjmp() relevant or not argument aside for a moment, come on, you state that you believe that an engine used setjmp()? Isn't that a bit vague? You demand always hard facts and source and pretty aligned code from Zach and Christoph, so were are the facts of Ren Wu chess?
Would you believe Zach if he would write he believes that the eval of Rybka is identical to Fruit without further comment?
You always want to see facts, so please before you do a conclusion, gives us some facts.
When I look at the (far from complete) list of chess engines released in recent years at
http://wbec-ridderkerk.nl/html/enginesindex.htm, I wonder how many of these engines use setjmp()? 10 of 200? More?
I think it is still a good indication, not a prove.
I do not know but movei used setjmp() at the beginning like tscp
and I simply learned from the code of tscp.
I got rid of setjmp later because I read people said it is not good
so it is not clear how many engines use setjmp.
old movei use it
new movei does not use it and you can download both old movei and new movei from wbec site.
Uri
So, you copied TSCP, which uses setjmp(). And then discovered it is a bad programming solution and removed it. Good. But notice where you got it from. That is the point of this minor side-issue. It is just another indication that perhaps something was copied, because good programmers do not use it for _many_ reasons. Perhaps Fruit started life as TSCP as well, who knows? But if programs that are suspected of being connected by common source, share a particular feature that is known to be bad programming, it is just another hint that things might have been copied...
I never claimed it to be the ultimate proof. I simply said it was another suspicious detail because it is such a lousy way of writing a program.
Ahem. Copied? I would prefer "used the idea". And if it's one line of code, there's not much else he can do, is there?
It is not "one line of code" it is an approach to unwind the search that requires actions in other parts of the program in order for it to work properly. Also he said "I don't understand how it works" so how can one copy an idea they don't understand?
What if someone reads Crafty use of null move? The call is one line
value = -Search(ply-2); basically
Basically? here's real code:
Code: Select all
pieces = (wtm) ? TotalPieces(white, occupied) : TotalPieces(black, occupied);
if (do_null && !tree->inchk[ply] && pieces && (pieces > 9 || depth < 7 * PLY)) {
register BITBOARD save_hash_key;
int null_depth;
tree->curmv[ply] = 0;
tree->phase[ply] = NULL_MOVE;
#if defined(TRACE)
if (ply <= trace_level)
Trace(tree, ply, depth, wtm, beta - 1, beta, "Search1", 0);
#endif
null_depth = (depth > 6 * PLY && pieces > 9) ? null_max : null_min;
tree->position[ply + 1] = tree->position[ply];
Rule50Moves(ply + 1) = 0;
save_hash_key = HashKey;
if (EnPassant(ply)) {
HashEP(EnPassant(ply + 1), HashKey);
EnPassant(ply + 1) = 0;
}
if (depth - null_depth >= PLY)
value =
-Search(tree, -beta, 1 - beta, Flip(wtm), depth - null_depth, ply + 1,
NO_NULL);
else
value = -QuiesceChecks(tree, -beta, 1 - beta, Flip(wtm), ply + 1);
HashKey = save_hash_key;
if (abort_search || tree->stop)
return (0);
if (value >= beta) {
HashStore(tree, ply, depth, wtm, LOWER, value, mate_threat);
return (value);
}
if (value == -MATE + ply + 2)
mate_threat = 1;
}
If your code matches that, you copied it. There are hundreds of ways to express the above idea using different implementation details... Again, we are not talking single lines, but single blocks.
how are we going to get a suitable value back from Search() without telling it to take 2 of the search depth?
not all of us take 2 off. And in fact, most take 3 which is 2 plies less deep than a normal search which uses depth-1. So many details makes duplicate code _highly_ improbable.
Some things just are as they are.
yes. now if we can just agree on what they are, and are not. And simple is what they are not.
Most of the code is housekeeping. The key bit is:
if (depth - null_depth >= PLY)
value =
-Search(tree, -beta, 1 - beta, Flip(wtm), depth - null_depth, ply + 1,
NO_NULL);
else
value = -QuiesceChecks(tree, -beta, 1 - beta, Flip(wtm), ply + 1);
There's not many ways to encode
"If we're not at the leaf nodes, do a null move search else quiesce"
I'ld do something like this
if (depth - nulldepth >= PLY)
{
value = -Search(ply-2, blah blah other parameters);
}
else
{
value = -Quiesce(blah blah parameters);
}
It looks suspiciciously like your code, but what choice do I have?
I guess if I wanted to hide things badly, I could fiddle with the if expression, swap the braced stuff round by negation and so on. But, basically, that's how it gets done.[/quote]
You are slowly realizing what I have been saying from the get-go. Individual lines mean _nothing_. Blocks of code mean _everything_. In a call to search, about the only flexibility would be (a) recursive or not, some use iterative search some use recursive; (b) order of arguments; (c) name of search function; (d) negamax or minmax?
But in a simple thing like null-move, you see what mine looks like, and nobody elses is going to look like that. Some "make/unmake" the null move. Some don't have a separate place where it is done (cray blitz did that) they just generate a null first and search it first. Etc. So individual lines don't mean much unless they are somehow unique (setjmp() is rare enough to fit this). But blocks of individually identical lines say a lot.