protected Int32 sortMoves(List <Move> moves, List <GoodMove> goodMoves, Depth wDepth) { //[Test]goodMoves.Sort(); var nMoves = moves.Count; var mLateStart = Eval.MaxValue; var nEarly = 0; //[Init] foreach (var move in moves) { var nIndex = goodMoves.FindIndex(gm => equalMoves(gm.Move, move)); if (nIndex >= 0) { nEarly++; State.IncEarlyMoveCount(SearchPly); // Update EarlyMove Histogram var good = goodMoves[nIndex]; var mGoodValue = good.Value; if (EvalUndefined < mGoodValue && mGoodValue < mLateStart) { mLateStart = mGoodValue; } } } var bWTM = WTM(); State.AddEarlyTotal(bWTM, nEarly); var mLateNext = mLateStart; var nGenerated = 0; foreach (var move in moves) { var nIndex = goodMoves.FindIndex(gm => equalMoves(gm.Move, move)); #if TestGoodValue var mValue = EvalUndefined; if (nIndex < 0) { mValue = --mLateNext; } else { var good = goodMoves[nIndex]; var mGoodValue = good.Value; //mValue = EvalUndefined < mGoodValue ? mGoodValue : (Eval)(mLateStart - nIndex); if (EvalUndefined < mGoodValue) { mValue = mGoodValue; } else { mValue = (Eval)(mLateStart - nIndex); } } #else var mValue = nIndex < 0 ? EvalUndefined : (Eval)(Eval.MaxValue - nIndex); #endif // // nGenerated index is included in SortMove so a Stable // Sort can be implemented on its IComparable interface // SortMoves[nGenerated++] = new SortMove(move, nGenerated, mValue, wDepth); } #if LazyMoveSort PriorityMove.Truncate(); // Truncate Heap, preparing to rebuild. PriorityMove.IsAscending = true; // // Convert SortMoves[] into a Heap: // PriorityMove.Build(nGenerated); #else Array.Sort <SortMove>(SortMoves, 0, nGenerated); #endif #if DebugMoveOrder if (IsTrace()) { DisplayCurrent("sortMoves()"); var sb = new StringBuilder(); #if LazyMoveSort var nMoveIndex = 0; foreach (var sm in PriorityMove) { #else for (var nMoveIndex = 0; nMoveIndex < nGenerated; nMoveIndex++) { var sm = SortMoves[nMoveIndex]; #endif sb.Clear(); sb.AppendAN(sm.Move, State.Rule.IsChess960); LogLine($"{nMoveIndex}) {sb}: Depth = {sm.Depth}, Value = {sm.Value}, Index = {sm.Index}"); #if LazyMoveSort nMoveIndex++; #endif } #if LazyMoveSort Trace.Assert(!PriorityMove.IsAscending, "Heap Ascending after enumeration"); if (!PriorityMove.IsAscending) { PriorityMove.Reverse(); } #endif } #endif // DebugMoveOrder if (nGenerated != nMoves) { Debug.Assert(nGenerated == nMoves, "nGenerated != nMoves"); } //[Commented]Scale(bWTM, wPly, 0.75f); return(nEarly); }
protected Int32 sortMoves(List <Move> moves, List <GoodMove> goodMoves, Depth wDepth) { var nStart = SiftedMoves.Count; Trace.Assert(nStart == 0, "nStart != 0"); var nEarlyCapacity = goodMoves.Count; var earlyMoves = new List <Move>(nEarlyCapacity); // // goodMoves.Count is not subtracted from moves.Count because there // is no guarantee that any of the goodMoves will be found in moves: // var nMoves = moves.Count; var lateMoves = new List <Move>(nMoves); // //[Note]The following operations are O(M*N) where N is the number of goodMoves // // Sift up the elements of "moves" found in goodMoves: // foreach (var move in moves) { if (goodMoves.Exists(gm => equalMoves(gm.Move, move))) { earlyMoves.Add(move); State.IncEarlyMoveCount(SearchPly); // Update EarlyMove Histogram } else { lateMoves.Add(move); } } var bWTM = WTM(); foreach (var gm in goodMoves) // Maintain goodMove priority for earlyMoves { #if DebugMove unpackMove1(gm.Move, out sq sqFrom, out sq sqTo, out Piece piece, out Piece promotion, out Boolean bCapture); //unpackMove2(gm.Move, out sq sqFrom, out sq sqTo, out Piece piece, out Piece promotion, out Piece capture, out Boolean bCastles, out Boolean bCapture); #endif #if DebugMoveColor && BottleBothSides var bWhiteMove = (gm.Move & Move.WTM) != 0; if (bWTM != bWhiteMove) { Debug.Assert(bWTM == bWhiteMove, "WTM != WhiteMove [sortMoves]"); DisplayCurrent("sortMoves()"); } #endif //SiftedMoves was cleared in generate() via clearPseudoMoveLists() var nIndex = earlyMoves.FindIndex(em => equalMoves(em, gm.Move)); if (nIndex >= 0) { var em = earlyMoves[nIndex]; //[Note]goodMoves may contain dupilicates if (!SiftedMoves.Exists(sm => equalMoves(sm, em))) { #if TestGoodCapture var good = gm.Move & Move.NormalMask; if (good != em) { var goodCaptive = captured(good); var emCaptive = captured(em); if (emCaptive != Piece.Capture) { var sb = new StringBuilder(); sb.AppendAN(good, false); if (goodCaptive != Piece.None) { sb.Append(goodCaptive); } sb.Append(" != "); sb.AppendAN(em, false); if (emCaptive != Piece.None) { sb.Append(emCaptive); } sb.FlushLine(); } else if (goodCaptive != Piece.Capture) { good &= ~Move.CaptiveMask; good |= (Move)((Byte)Piece.Capture << nCaptiveBit); } } #endif // //[Warning]It is necessary to Add(em) rather than gm here. // // An em capture will specify either Piece.Capture or Piece.EP; but a Killer gm // can specify a capture from some other position and still match an em capture. // SiftedMoves.Add(em); } } } var nEarly = SiftedMoves.Count; State.AddEarlyTotal(bWTM, nEarly); SiftedMoves.AddRange(lateMoves); var nGenerated = SiftedMoves.Count; if (nGenerated != nMoves) { Debug.Assert(nGenerated == nMoves, "nGenerated != nMoves"); } return(nEarly); }