jp wrote: ↑Fri Apr 26, 2019 10:49 am
How is McCain related to SF? What are the main differences?
McCain was forked from Stockfish as a separate branch and is updated periodically with the SF patches.
https://github.com/MichaelB7/Stockfish/tree/McCain
Each and if every difference is documents in the code with "ifdef Maverick" in the source. Have also tried to attribute the source of the change as well. Most of the differences are in the search function An example of one of the difference is the the LMR function table in the "search:init" function.
This is McCain's
Code: Select all
#ifdef Maverick // MichaelB7
for (int imp = 0; imp <= 1; ++imp)
for (int d = 1; d < 32; ++d)
for (int mc = 1; mc < 80; ++mc) // record in a "real" game is 79 moves,
// in a search of one million games, found one posiiton with 78 possible moves.
// more weight on depth for LMR reductions than move count
// (from Crafty) MichaelB7
{
int red = int(log( d * 1.87 ) * log( mc * .95 )) / 2;
Reductions[imp][d][mc] = red;
// Increase reduction for non-PV nodes when eval is not improving
if (!imp && red > 1)
Reductions[imp][d][mc]++;
}
This is Stockfish
Code: Select all
#else
for (int i = 1; i < MAX_MOVES; ++i)
Reductions[i] = int(1024 * std::log(i) / std::sqrt(1.95));
#endif
As an example, I recently merged CorChess code by Ivan Ivec into McCain, such as the use of two delta's - delta1 and delta2.
The source is directly attributed to Ivan in the code:
Code: Select all
#ifdef Maverick
bestValue = delta1 = delta2 = alpha = -VALUE_INFINITE; //corchess by Ivan Ivec
#else
bestValue = delta = alpha = -VALUE_INFINITE;
#endif
It also includes Gunther Demetz's SF "zugzwang solver" patch from last fall. Although, it not pass the strict requirements o make it into regular SF, I felt the patch was certainly worthy of of inclusion in McCain. 1/4 of the "ifdef Maverick" statements in search.cpp are directly related to Demetz's "zugzwang solver" patch.
Below is the largest block code for the "zugzwang solver" patch from last fall written by Gunther.
Code: Select all
#ifdef Maverick //Gunther Demetz zugzwangSolver
if ( depth % 2 == 1 ){
thisThread->nmpColor = us;
Pawns::Entry* pe;
if ( !inCheck
&& thisThread->zugzwangMates < 1000000
&& (pe = Pawns::probe(pos)) != nullptr
&& popcount(pe->passedPawns[us])
&& popcount(pe->passedPawns[us]) <= 2
&& popcount(pos.pieces(us)) <= 7
&& popcount(pos.pieces()) <= 12
&& MoveList<LEGAL, KING>(pos).size() < 1)
{
bool oneOpponentPasser = popcount(pe->passedPawns[~us]) == 1 &&
!(pos.pieces() & forward_file_bb(~us, lsb(pe->passedPawns[~us])));
Bitboard passed = pe->passedPawns[us] & ~pos.blockers_for_king(us) & ~pos.blockers_for_king(~us);
while (passed)
{
Square s = pop_lsb(&passed);
Square promo = make_square(file_of(s), us == WHITE ? RANK_8 : RANK_1);
if ((pos.pieces() & between_bb(promo, s)) || promo == pos.square<KING>(us)) // king can't move
continue; // passer blocked
Move directPromotion = make_move(s, promo);
bool killPromo = (pos.pieces(~us) & promo) || !pos.see_ge(directPromotion); // opponent controls promotion-square
if (!killPromo && !oneOpponentPasser)
continue;
StateInfo s1,s2,s3;
Square p2, p3 = SQ_NONE;
if (oneOpponentPasser && !killPromo)
{
Rank r1 = relative_rank(~us, rank_of(lsb(pe->passedPawns[~us])));
Rank r2 = relative_rank( us, rank_of(s));
if (r2 > r1)
continue; // if our passed is more advanced we will promote earlier and probably defend with success
if (pawn_attack_span(us, s) & pos.pieces(~us, PAWN))
{ // pseudo passed pawn: will be passed after levers
p2 = lsb(pawn_attack_span(us, s) & pos.pieces(~us, PAWN));
Bitboard removeLevers = forward_file_bb(~us, p2) & pos.pieces( us, PAWN);
if (removeLevers)
{
p3 = lsb(removeLevers);
pos.removePawn(p2, s2);
pos.removePawn(p3, s3);
}
}
}
thisThread->nmpMinPly = MAX_PLY;
pos.removePawn(s, s1);
Move pv1[MAX_PLY+1];
(ss)->pv = pv1;
(ss)->pv[0] = MOVE_NONE;
Depth nd = (oneOpponentPasser && !killPromo) ? depth - R - 2 * ONE_PLY : depth - 4 * ONE_PLY;
Value v = search<PV>(pos, ss, mated_in(0), VALUE_MATED_IN_MAX_PLY, nd, false);
pos.undo_removePawn(s, us);
if (p3 != SQ_NONE) // reput the lever pawns
pos.undo_removePawn(p3, us), pos.undo_removePawn(p2, ~us);
if (v > mated_in(0) && v < VALUE_MATED_IN_MAX_PLY)
{
//sync_cout << pos << "info mate " << UCI::value(v) << " detected with depth " << nd << " ! at score " << thisThread->rootMoves[0].score << sync_endl;
thisThread->zugzwangMates++;
thisThread->nmpMinPly = 0;
// Early return here with a low value, this will spotlight this promising variation
return Value(thisThread->rootMoves[0].score * (thisThread->rootPos.side_to_move() != us ? 1 : -1) - 80);
}
} // end processing of passed pawns
}
}
#endif
In the search.cpp file, you one will find 47 "ifdef Maverick" statements. In addition , McCain has non functional differences such as "play by Elo" and the ability to use 3 opening books. One will find 24 "ifdef Add_Features" statements in the search.cpp .
In the Makefile this line decides whether it will a build McCain or Stockfish when you run make.
Code: Select all
### Uncomment the line below for McCain, comment in "###" for Stockfish functionality
VERSION=maverick
Leave it as is to build McCain, comment the line outwith puns signs to build a functionally equilavalent Stockfish engine ( but leaving in the bell and whistles, such as Play by Elo rating and using 3 opening books, etc , There are also few other items such as keyboard shortcuts when using McCain terminal mode.
Some shortcut commands:
Code: Select all
b = bench
g = go
i = infinite
p f = position fen
sd = search depth
sm = searchmoves
q = quit
? = stop ( to stop A search)
new option set or s = set, see example below
e.g.,
set threads xx = setoption name threads value xx
set hash xxx = setoption name hash value xx
g d 5 = go depth 5
g i = go infinite
g movetime 10000 sm g1f3 - searches only move g1f3 for 10 seconds
And then finally, in concert with working with Al Scally of DGT-Pi fame, we have developed about 20 weakened personalities that can be used with McCain and the DGT board.