While implementing magic bitboards, I found the CarryRippler information on ChessProgramming Wiki to calculate all permuations. It's this function:
Code: Select all
void enumerateAllSubsets(U64 d) {
U64 n = 0;
do {
doSomeThingWithSubset(n);
n = (n - d) & d;
} while ( n );
}
Code: Select all
fn enumerate(d: u64) {
let mut n: u64 = 0;
let mut stop = false;
while !stop {
// doSomeThingWithSubset(n);
n = (n - d) & d;
stop = n == 0;
}
}
This line:
n = (n - d) & d;
It substracts d from n, but for any d greater than 0, the outcome of "n - d" will be negative, which is not possible when working with unsigned characters. Rust confirms:
"thread 'main' panicked at 'attempt to subtract with overflow'."
Still, stockfish and other engines use this technique almost verbatim from the wiki. Is there something C does that I don't know about, such as internally casting to an unsigned number, and then cast back again? Rust doesn't do things like that because it's possibly unsafe. Actually, it won't ever implicitly cast any type to another, not even from u8 to u64 for example.
Any thoughts on this?
(Also, I often see techniques in chess programming that actually take advantage of C/C++'s undefined behavior. An example is shifting more bits than are available in a number. Rust does not allow things like that.)