// ThreadsManager::start_searching() wakes up the main thread sleeping in // main_loop() so to start a new search, then returns immediately. internal static void start_searching(Position pos, LimitsType limits, List <Move> searchMoves) { wait_for_search_finished(); Search.SearchTime.Reset(); Search.SearchTime.Start(); // As early as possible Search.SignalsStopOnPonderhit = Search.SignalsFirstRootMove = false; Search.SignalsStop = Search.SignalsFailedLowAtRoot = false; Search.RootPosition.copy(pos); Search.Limits = limits; Search.RootMoves.Clear(); MList mlist = MListBroker.GetObject(); mlist.pos = 0; Movegen.generate_legal(pos, mlist.moves, ref mlist.pos); for (int i = 0; i < mlist.pos; i++) { Move move = mlist.moves[i].move; if ((searchMoves.Count == 0) || Utils.existSearchMove(searchMoves, move)) { Search.RootMoves.Add(new RootMove(move)); } } MListBroker.Free(); main_thread().do_sleep = false; main_thread().wake_up(); }
/// Mate with KX vs K. This function is used to evaluate positions with /// King and plenty of material vs a lone king. It simply gives the /// attacking side a bonus for driving the defending king towards the edge /// of the board, and for keeping the distance between the two kings small. /// KXK internal static Value Endgame_KXK(Color strongerSide, Position pos) { Color weakerSide = strongerSide ^ 1; Debug.Assert(pos.non_pawn_material(weakerSide) == ValueC.VALUE_ZERO); Debug.Assert(pos.piece_count(weakerSide, PieceTypeC.PAWN) == ValueC.VALUE_ZERO); // Stalemate detection with lone king MList mlist = MListBroker.GetObject(); mlist.pos = 0; Movegen.generate_legal(pos, mlist.moves, ref mlist.pos); bool any = mlist.pos > 0; MListBroker.Free(); if (pos.sideToMove == weakerSide && !pos.in_check() && !any) { return ValueC.VALUE_DRAW; } Square winnerKSq = pos.king_square(strongerSide); Square loserKSq = pos.king_square(weakerSide); Value result = pos.non_pawn_material(strongerSide) + pos.piece_count(strongerSide, PieceTypeC.PAWN) * Constants.PawnValueEndgame + MateTable[loserKSq] + DistanceBonus[Utils.square_distance(winnerKSq, loserKSq)]; if (pos.piece_count(strongerSide, PieceTypeC.QUEEN)!=0 || pos.piece_count(strongerSide, PieceTypeC.ROOK)!=0 || pos.bishop_pair(strongerSide)) { result += ValueC.VALUE_KNOWN_WIN; } return strongerSide == pos.sideToMove ? result : -result; }
/// Book::probe() tries to find a book move for the given position. If no move /// is found returns MOVE_NONE. If pickBest is true returns always the highest /// rated move, otherwise randomly chooses one, based on the move score. internal static Move probe(Position pos, string filename, bool pickBest) { #if PORTABLE #region DLL book if (bookNotExists) { return(MoveC.MOVE_NONE); } BookEntry e = new BookEntry(); UInt16 best = 0; uint sum = 0; Move move = MoveC.MOVE_NONE; UInt64 key = book_key(pos); try { System.Reflection.Assembly bookAssembly = System.Reflection.Assembly.Load("PortfishBook"); using (Stream fs = bookAssembly.GetManifestResourceStream("PortfishBook.book.bin")) { UInt64 size = (UInt64)(fs.Length / SIZE_OF_BOOKENTRY); using (BinaryReader br = new BinaryReader(fs)) { binary_search(key, size, br); while (Read(ref e, br) && (e.key == key)) { best = Math.Max(best, e.count); sum += e.count; // Choose book move according to its score. If a move has a very // high score it has higher probability to be choosen than a move // with lower score. Note that first entry is always chosen. if ((RKiss.rand() % sum < e.count) || (pickBest && e.count == best)) { move = e.move; } } } } } catch (System.IO.FileNotFoundException) { bookNotExists = true; return(MoveC.MOVE_NONE); } #endregion #else #region File system read if (!System.IO.File.Exists(filename)) { return(MoveC.MOVE_NONE); } BookEntry e = new BookEntry(); UInt16 best = 0; uint sum = 0; Move move = MoveC.MOVE_NONE; UInt64 key = book_key(pos); using (FileStream fs = new FileStream(filename, FileMode.Open)) { UInt64 size = (UInt64)(fs.Length / SIZE_OF_BOOKENTRY); using (BinaryReader br = new BinaryReader(fs)) { binary_search(key, size, br); while (Read(ref e, br) && (e.key == key)) { best = Math.Max(best, e.count); sum += e.count; // Choose book move according to its score. If a move has a very // high score it has higher probability to be choosen than a move // with lower score. Note that first entry is always chosen. if (((sum != 0) && (RKiss.rand() % sum < e.count)) || (pickBest && e.count == best)) { move = e.move; } } br.Close(); } fs.Close(); } #endregion #endif if (move != 0) { // A PolyGlot book move is encoded as follows: // // bit 0- 5: destination square (from 0 to 63) // bit 6-11: origin square (from 0 to 63) // bit 12-14: promotion piece (from KNIGHT == 1 to QUEEN == 4) // // Castling moves follow "king captures rook" representation. So in case book // move is a promotion we have to convert to our representation, in all the // other cases we can directly compare with a Move after having masked out // the special Move's flags (bit 14-15) that are not supported by PolyGlot. int pt = (move >> 12) & 7; if (pt != 0) { move = Utils.make_promotion(Utils.from_sq(move), Utils.to_sq(move), (pt + 1)); } // Add 'special move' flags and verify it is legal MList mlist = MListBroker.GetObject(); mlist.pos = 0; Movegen.generate_legal(pos, mlist.moves, ref mlist.pos); for (int i = 0; i < mlist.pos; i++) { if (move == (mlist.moves[i].move & 0x3FFF)) { Move retval = mlist.moves[i].move; MListBroker.Free(); return(retval); } } MListBroker.Free(); } return(MoveC.MOVE_NONE); }
/// MovePicker::generate_next() generates, scores and sorts the next bunch of moves, /// when there are no more moves to try for the current phase. private void generate_next() { curMovePos = 0; switch (++phase) { case SequencerC.CAPTURES_S1: case SequencerC.CAPTURES_S3: case SequencerC.CAPTURES_S4: case SequencerC.CAPTURES_S5: case SequencerC.CAPTURES_S6: mpos = 0; Movegen.generate_capture(pos, ms, ref mpos); lastMovePos = mpos; score_captures(); return; case SequencerC.KILLERS_S1: curMovePos = Constants.MAX_MOVES; //killers[0]; lastMovePos = curMovePos + 2; return; case SequencerC.QUIETS_1_S1: mpos = 0; Movegen.generate_quiet(pos, ms, ref mpos); lastQuietPos = lastMovePos = mpos; score_noncaptures(); lastMovePos = partition(curMovePos, lastMovePos); sort(); return; case SequencerC.QUIETS_2_S1: curMovePos = lastMovePos; lastMovePos = lastQuietPos; if (depth >= 3 * DepthC.ONE_PLY) { sort(); } return; case SequencerC.BAD_CAPTURES_S1: // Just pick them in reverse order to get MVV/LVA ordering curMovePos = Constants.MAX_MOVES - 1; lastMovePos = lastBadCapturePos; return; case SequencerC.EVASIONS_S2: mpos = 0; Movegen.generate_evasion(pos, ms, ref mpos); lastMovePos = mpos; score_evasions(); return; case SequencerC.QUIET_CHECKS_S3: mpos = 0; Movegen.generate_quiet_check(pos, ms, ref mpos); lastMovePos = mpos; return; case SequencerC.EVASION: case SequencerC.QSEARCH_0: case SequencerC.QSEARCH_1: case SequencerC.PROBCUT: case SequencerC.RECAPTURE: phase = SequencerC.STOP; lastMovePos = curMovePos + 1; // Avoid another next_phase() call break; case SequencerC.STOP: lastMovePos = curMovePos + 1; // Avoid another next_phase() call return; default: Debug.Assert(false); break; } }