// start_thinking() wakes up the main thread sleeping in MainThread::idle_loop() // so to start a new search, then returns immediately. public void start_thinking(Position pos, LimitsType limits, StateStackPtr states) { wait_for_think_finished(); Search.SearchTime = Time.now(); // As early as possible Search.Signals.stopOnPonderhit = Search.Signals.firstRootMove = false; Search.Signals.stop = Search.Signals.failedLowAtRoot = false; Search.RootMoves.Clear(); Search.RootPos = pos; Search.Limits = limits; if (states.Count > 0) // If we don't set a new position, preserve current state { Search.SetupStates = states; // Ownership transfer here //Debug.Assert(states==null); } for (MoveList it = new MoveList(pos, GenTypeS.LEGAL); it.move()!= 0; ++it) if (limits.searchmoves.Count == 0 || Misc.existSearchMove(limits.searchmoves, it.move())) Search.RootMoves.Add(new RootMove(it.move())); main().thinking = true; main().notify_one(); // Starts main thread }
public MoveList(Position pos, GenType T) { cur = 0; mlist = new ExtMove[Types.MAX_MOVES]; last = MoveList.generate(pos, mlist, 0, T); mlist[last].move = MoveS.MOVE_NONE; }
/// move_from_uci() takes a position and a string representing a move in /// simple coordinate notation and returns an equivalent legal Move if any. public static Move move_from_uci(Position pos, string str) { if (str.Length == 5) { // Junior could send promotion piece in uppercase char[] strChar = str.ToCharArray(); strChar[4] = char.ToLower(strChar[4]); str = new String(strChar); } for (MoveList it = new MoveList(pos, GenTypeS.LEGAL); it.mlist[it.cur].move != MoveS.MOVE_NONE; ++it) { if (str == move_to_uci(it.move(), pos.is_chess960() != 0)) { return(it.move()); } } return(MoveS.MOVE_NONE); }
/// 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. public Move probe(Position pos, string fName, bool pickBest) { if (fName == null || (fileName != fName && !open(fName))) { return(MoveS.MOVE_NONE); } PolyglotBook.Entry e = new PolyglotBook.Entry(); UInt16 best = 0; uint sum = 0; Move move = MoveS.MOVE_NONE; Key key = polyglot_key(pos); stream.Seek(find_first(key) * SIZE_OF_BOOKENTRY, SeekOrigin.Begin); while (read(ref e) && 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 && ((((uint)RKiss.rand64()) % sum) < e.count)) || (pickBest && e.count == best)) { move = (e.move); } } if (move == 0) { return(MoveS.MOVE_NONE); } // 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 = Types.make(Types.from_sq(move), Types.to_sq(move), MoveTypeS.PROMOTION, (pt + 1)); } // Add 'special move' flags and verify it is legal for (MoveList ml = new MoveList(pos, GenTypeS.LEGAL); ml.mlist[ml.cur].move != MoveS.MOVE_NONE; ++ml) { if (move == (ml.move() ^ Types.type_of_move(ml.move()))) { return(ml.move()); } } return(MoveS.MOVE_NONE); }
/// generate_next_stage() generates, scores and sorts the next bunch of moves, /// when there are no more moves to try for the current stage. public void generate_next_stage() { cur = 0; switch (++stage) { case StagesS.CAPTURES_S1: case StagesS.CAPTURES_S3: case StagesS.CAPTURES_S4: case StagesS.CAPTURES_S5: case StagesS.CAPTURES_S6: end = MoveList.generate(pos, moves, 0, GenTypeS.CAPTURES); score_captures(); return; case StagesS.KILLERS_S1: cur = Types.MAX_MOVES; end = cur + 2; moves[Types.MAX_MOVES].move = ss.killers0; moves[Types.MAX_MOVES + 1].move = ss.killers1; moves[Types.MAX_MOVES + 2].move = moves[Types.MAX_MOVES + 3].move = MoveS.MOVE_NONE; moves[Types.MAX_MOVES + 4].move = moves[Types.MAX_MOVES + 5].move = MoveS.MOVE_NONE; // Please note that following code is racy and could yield to rare (less // than 1 out of a million) duplicated entries in SMP case. This is harmless. // Be sure countermoves are different from killers for (int i = 0; i < 2; ++i) { if (countermoves[i] != moves[cur].move && countermoves[i] != moves[cur + 1].move) { moves[end++].move = countermoves[i]; } } // Be sure followupmoves are different from killers and countermoves for (int i = 0; i < 2; ++i) { if (followupmoves[i] != moves[cur].move && followupmoves[i] != moves[cur + 1].move && followupmoves[i] != moves[cur + 2].move && followupmoves[i] != moves[cur + 3].move) { moves[end++].move = followupmoves[i]; } } return; case StagesS.QUIETS_1_S1: endQuiets = end = MoveList.generate(pos, moves, 0, GenTypeS.QUIETS); score_quiets(); end = partition(moves, cur, end); insertion_sort(moves, cur, end); return; case StagesS.QUIETS_2_S1: cur = end; end = endQuiets; if (depth >= 3 * DepthS.ONE_PLY) { insertion_sort(moves, cur, end); } return; case StagesS.BAD_CAPTURES_S1: // Just pick them in reverse order to get MVV/LVA ordering cur = Types.MAX_MOVES - 1; end = endBadCaptures; return; case StagesS.EVASIONS_S2: end = MoveList.generate(pos, moves, 0, GenTypeS.EVASIONS); if (end > 1) { score_evasions(); } return; case StagesS.QUIET_CHECKS_S3: end = MoveList.generate(pos, moves, 0, GenTypeS.QUIET_CHECKS); return; case StagesS.EVASION: case StagesS.QSEARCH_0: case StagesS.QSEARCH_1: case StagesS.PROBCUT: case StagesS.RECAPTURE: stage = StagesS.STOP; end = cur + 1; break; case StagesS.STOP: end = cur + 1; // Avoid another next_phase() call return; default: Debug.Assert(false); break; } }