public void PartitionAndSortTest2() { var table = new ExtMove[] { new ExtMove(Move.Create(528), Value.Create(0)), new ExtMove(Move.Create(593), Value.Create(0)), new ExtMove(Move.Create(658), Value.Create(-32)), new ExtMove(Move.Create(723), Value.Create(0)), new ExtMove(Move.Create(788), Value.Create(0)), new ExtMove(Move.Create(853), Value.Create(-32)), new ExtMove(Move.Create(918), Value.Create(-32)), new ExtMove(Move.Create(983), Value.Create(-32)), new ExtMove(Move.Create(796), Value.Create(32)), new ExtMove(Move.Create(731), Value.Create(0)) }; var splitted = ExtMoveArrayWrapper.Partition(new ExtMoveArrayWrapper(table, 0), new ExtMoveArrayWrapper(table, 9)); Assert.AreEqual(1, splitted.current); Assert.AreEqual(796, splitted[0].Move); Assert.AreEqual(593, splitted[1].Move); Assert.AreEqual(528, splitted[8].Move); }
// Our insertion sort, which is guaranteed (and also needed) to be stable public static void insertion_sort(ExtMove begin, ExtMove end) { ExtMove tmp = new ExtMove(); //C++ TO C# CONVERTER TODO TASK: Pointer arithmetic is detected on this variable, so pointers on this variable are left unchanged: ExtMove *p = new ExtMove(); //C++ TO C# CONVERTER TODO TASK: Pointer arithmetic is detected on this variable, so pointers on this variable are left unchanged: ExtMove *q = new ExtMove(); for (p = begin + 1; p < end; ++p) { //C++ TO C# CONVERTER WARNING: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created if it does not yet exist: //ORIGINAL LINE: tmp = *p; tmp.CopyFrom(p); for (q = p; q != begin && *(q - 1) < tmp; --q) { *q = (q - 1); } *q = tmp; } }
// Add underpromotion captures to list of captures. internal static ExtMove add_underprom_caps(Position pos, ExtMove stack, ExtMove end) { //C++ TO C# CONVERTER TODO TASK: Pointer arithmetic is detected on this variable, so pointers on this variable are left unchanged: ExtMove *moves = new ExtMove(); //C++ TO C# CONVERTER TODO TASK: Pointer arithmetic is detected on this variable, so pointers on this variable are left unchanged: //C++ TO C# CONVERTER WARNING: The following line was determined to be a copy constructor call - this should be verified and a copy constructor should be created if it does not yet exist: //ORIGINAL LINE: ExtMove *extra = end; ExtMove *extra = new ExtMove(end); for (moves = stack; moves < end; moves++) { Move move = moves.move; if (GlobalMembersTypes.type_of(move) == MoveType.PROMOTION && !pos.empty(GlobalMembersTypes.to_sq(move))) { (*extra++).move = (Move)(move - (1 << 12)); (*extra++).move = (Move)(move - (2 << 12)); (*extra++).move = (Move)(move - (3 << 12)); } } return(extra); }
/// generate_next_stage() generates, scores and sorts the next bunch of moves, /// when there are no more moves to try for the current stage. private void generate_next_stage() { Debug.Assert(stage != Stages.STOP); cur.set(moves); switch (++stage) { case Stages.GOOD_CAPTURES: case Stages.QCAPTURES_1: case Stages.QCAPTURES_2: case Stages.PROBCUT_CAPTURES: case Stages.RECAPTURES: { endMoves = Movegen.generate(GenType.CAPTURES, pos, new ExtMoveArrayWrapper(moves)); score(GenType.CAPTURES); } break; case Stages.KILLERS: killers[0] = new ExtMove(ss[ss.current].killers0, killers[0].Value); killers[1] = new ExtMove(ss[ss.current].killers1, killers[1].Value); killers[2] = new ExtMove(countermove, killers[2].Value); cur.set(killers); endMoves = new ExtMoveArrayWrapper(cur.table, cur.current + 2 + ((countermove != killers[0] && countermove != killers[1]) ? 1 : 0)); break; case Stages.GOOD_QUIETS: { endQuiets = Movegen.generate(GenType.QUIETS, pos, new ExtMoveArrayWrapper(moves)); endMoves = endQuiets; score(GenType.QUIETS); endMoves = ExtMoveArrayWrapper.Partition(cur, endMoves); ExtMoveArrayWrapper.insertion_sort(cur, endMoves); } break; case Stages.BAD_QUIETS: cur = new ExtMoveArrayWrapper(endMoves); endMoves = endQuiets; if (depth >= 3*Depth.ONE_PLY_C) { ExtMoveArrayWrapper.insertion_sort(cur, endMoves); } break; case Stages.BAD_CAPTURES: // Just pick them in reverse order to get correct ordering cur = new ExtMoveArrayWrapper(moves) + (_.MAX_MOVES - 1); endMoves = endBadCaptures; break; case Stages.ALL_EVASIONS: { endMoves = Movegen.generate(GenType.EVASIONS, pos, new ExtMoveArrayWrapper(moves)); if (endMoves.current > 1) { score(GenType.EVASIONS); } } break; case Stages.CHECKS: { endMoves = Movegen.generate( GenType.QUIET_CHECKS, pos, new ExtMoveArrayWrapper(moves)); } break; case Stages.EVASION: case Stages.QSEARCH_WITH_CHECKS: case Stages.QSEARCH_WITHOUT_CHECKS: case Stages.PROBCUT: case Stages.RECAPTURE: case Stages.STOP: stage = Stages.STOP; break; default: Debug.Assert(false); break; } }
private void score_EVASIONS() { // Try winning and equal captures captures ordered by MVV/LVA, then non-captures // ordered by history value, then bad-captures and quiet moves with a negative // SEE ordered by SEE value. for (var i = 0; i < endMoves.current; i++) { var m = moves[i]; ValueT see; if ((see = pos.see_sign(m)) < Value.VALUE_ZERO) { moves[i] = new ExtMove(m, see - HistoryStats.Max); // At the bottom } else if (pos.capture(m)) { moves[i] = new ExtMove( m, Value.PieceValue[(int) Phase.MG][pos.piece_on(Move.to_sq(m))] - Value.Create(Piece.type_of(pos.moved_piece(m))) + HistoryStats.Max); } else { moves[i] = new ExtMove(m, history.value(pos.moved_piece(m), Move.to_sq(m))); } } }
private void score_QUIETS() { var prevSq = Move.to_sq(ss[ss.current - 1].currentMove); var cmh = counterMovesHistory.value(pos.piece_on(prevSq), prevSq); for (var i = 0; i < endMoves.current; i++) { var m = moves[i]; moves[i] = new ExtMove( m, history.value(pos.moved_piece(m), Move.to_sq(m)) + cmh.value(pos.moved_piece(m), Move.to_sq(m))); } }
/// score() assigns a numerical value to each move in a move list. The moves with /// highest values will be picked first. private void score_CAPTURES() { // Winning and equal captures in the main search are ordered by MVV, preferring // captures near our home rank. Suprisingly, this appears to perform slightly // better than SEE based move ordering: exchanging big pieces before capturing // a hanging piece probably helps to reduce the subtree size. // In main search we want to push captures with negative SEE values to the // badCaptures[] array, but instead of doing it now we delay until the move // has been picked up, saving some SEE calls in case we get a cutoff. for (var i = 0; i < endMoves.current; i++) { var m = moves[i]; moves[i] = new ExtMove( m, Value.PieceValue[(int) Phase.MG][pos.piece_on(Move.to_sq(m))] - Value.Create(200 * Rank.relative_rank_CtSt(pos.side_to_move(), Move.to_sq(m)))); } }
internal void setCurrentMove(MoveT m) { table[current] = new ExtMove(m, table[current].Value); }
internal void Add(MoveT m) { table[current] = new ExtMove(m, table[current].Value); current++; }
internal void set(ExtMove[] table) { this.table = table; current = 0; }
internal ExtMoveArrayWrapper(ExtMove[] table, int current) { this.table = table; this.current = current; }
internal ExtMoveArrayWrapper(ExtMove[] table) : this(table, 0) { }
// This routine treats a position with en passant captures as one without. internal static int probe_dtz_no_ep(Position pos, ref int success) { int wdl; int dtz; wdl = GlobalMembersTbprobe.probe_ab(pos, -2, 2, ref success); if (success == 0) { return(0); } if (wdl == 0) { return(0); } if (success == 2) { return(wdl == 2 ? 1 : 101); } ExtMove[] stack = Arrays.InitializeWithDefaultInstances <ExtMove>(192); //C++ TO C# CONVERTER TODO TASK: Pointer arithmetic is detected on this variable, so pointers on this variable are left unchanged: ExtMove * moves = new ExtMove(); ExtMove end = null; StateInfo st = new StateInfo(); CheckInfo ci = new CheckInfo(pos); if (wdl > 0) { // Generate at least all legal non-capturing pawn moves // including non-capturing promotions. if (pos.checkers() == 0) { //C++ TO C# CONVERTER WARNING: The following line was determined to be a copy constructor call - this should be verified and a copy constructor should be created if it does not yet exist: //ORIGINAL LINE: end = generate<NON_EVASIONS>(pos, stack); end = GlobalMembersMovegen.generate <GenType.NON_EVASIONS>(pos, new ExtMove(stack)); } else { //C++ TO C# CONVERTER WARNING: The following line was determined to be a copy constructor call - this should be verified and a copy constructor should be created if it does not yet exist: //ORIGINAL LINE: end = generate<EVASIONS>(pos, stack); end = GlobalMembersMovegen.generate <GenType.EVASIONS>(pos, new ExtMove(stack)); } for (moves = stack; moves < end; moves++) { Move move = moves.move; if (GlobalMembersTypes.type_of(pos.moved_piece(move)) != PieceType.PAWN || pos.capture(move) || !pos.legal(move, ci.pinned)) { continue; } pos.do_move(move, st, ci, pos.gives_check(move, ci)); int v = -GlobalMembersTbprobe.probe_ab(pos, -2, -wdl + 1, ref success); pos.undo_move(move); if (success == 0) { return(0); } if (v == wdl) { return(v == 2 ? 1 : 101); } } } dtz = 1 + GlobalMembersTbprobe.probe_dtz_table(pos, wdl, ref success); if (success >= 0) { if ((wdl & 1) != 0) { dtz += 100; } return(wdl >= 0 ? dtz : -dtz); } if (wdl > 0) { int best = 0xffff; for (moves = stack; moves < end; moves++) { Move move = moves.move; if (pos.capture(move) || GlobalMembersTypes.type_of(pos.moved_piece(move)) == PieceType.PAWN || !pos.legal(move, ci.pinned)) { continue; } pos.do_move(move, st, ci, pos.gives_check(move, ci)); int v = -GlobalMembersTbprobe.probe_dtz(pos, ref success); pos.undo_move(move); if (success == 0) { return(0); } if (v > 0 && v + 1 < best) { best = v + 1; } } return(best); } else { int best = -1; if (pos.checkers() == 0) { //C++ TO C# CONVERTER WARNING: The following line was determined to be a copy constructor call - this should be verified and a copy constructor should be created if it does not yet exist: //ORIGINAL LINE: end = generate<NON_EVASIONS>(pos, stack); end = GlobalMembersMovegen.generate <GenType.NON_EVASIONS>(pos, new ExtMove(stack)); } else { //C++ TO C# CONVERTER WARNING: The following line was determined to be a copy constructor call - this should be verified and a copy constructor should be created if it does not yet exist: //ORIGINAL LINE: end = generate<EVASIONS>(pos, stack); end = GlobalMembersMovegen.generate <GenType.EVASIONS>(pos, new ExtMove(stack)); } for (moves = stack; moves < end; moves++) { int v; Move move = moves.move; if (!pos.legal(move, ci.pinned)) { continue; } pos.do_move(move, st, ci, pos.gives_check(move, ci)); if (st.rule50 == 0) { if (wdl == -2) { v = -1; } else { v = GlobalMembersTbprobe.probe_ab(pos, 1, 2, ref success); v = (v == 2) ? 0 : -101; } } else { v = -GlobalMembersTbprobe.probe_dtz(pos, ref success) - 1; } pos.undo_move(move); if (success == 0) { return(0); } if (v < best) { best = v; } } return(best); } }
// Picks the best move in the range (begin, end) and moves it to the front. // It's faster than sorting all the moves in advance when there are few // moves e.g. possible captures. public static ExtMove pick_best(ExtMove begin, ExtMove end) { std.swap(begin, *std.max_element(begin, end)); return(begin); }
// Unary predicate used by std::partition to split positive values from remaining // ones so as to sort the two sets separately, with the second sort delayed. public static bool has_positive_value(ExtMove move) { return(move.value > Value.VALUE_ZERO); }
public void PartitionAndSortTest1() { var table = new ExtMove[] { new ExtMove(Move.Create(528), Value.Create(-1008)), new ExtMove(Move.Create(593), Value.Create(-1008)), new ExtMove(Move.Create(658), Value.Create(-1069)), new ExtMove(Move.Create(788), Value.Create(-413)), new ExtMove(Move.Create(853), Value.Create(-944)), new ExtMove(Move.Create(918), Value.Create(-944)), new ExtMove(Move.Create(983), Value.Create(-944)), new ExtMove(Move.Create(1243), Value.Create(-413)), new ExtMove(Move.Create(536), Value.Create(-444)), new ExtMove(Move.Create(601), Value.Create(-444)), new ExtMove(Move.Create(666), Value.Create(-444)), new ExtMove(Move.Create(796), Value.Create(475)), new ExtMove(Move.Create(861), Value.Create(-444)), new ExtMove(Move.Create(926), Value.Create(-444)), new ExtMove(Move.Create(991), Value.Create(-444)), new ExtMove(Move.Create(75), Value.Create(-32)), new ExtMove(Move.Create(88), Value.Create(-444)), new ExtMove(Move.Create(82), Value.Create(-444)), new ExtMove(Move.Create(405), Value.Create(-444)), new ExtMove(Move.Create(407), Value.Create(-444)), new ExtMove(Move.Create(139), Value.Create(32)), new ExtMove(Move.Create(148), Value.Create(0)), new ExtMove(Move.Create(157), Value.Create(0)), new ExtMove(Move.Create(166), Value.Create(0)), new ExtMove(Move.Create(175), Value.Create(0)), new ExtMove(Move.Create(203), Value.Create(0)), new ExtMove(Move.Create(267), Value.Create(0)), }; var splitted = ExtMoveArrayWrapper.Partition(new ExtMoveArrayWrapper(table, 0), new ExtMoveArrayWrapper(table, 26)); Assert.AreEqual(2, splitted.current); Assert.AreEqual(139, table[0].Move); Assert.AreEqual(796, table[1].Move); Assert.AreEqual(593, table[11].Move); ExtMoveArrayWrapper.insertion_sort(new ExtMoveArrayWrapper(table, 0), splitted); Assert.AreEqual(796, table[0].Move); Assert.AreEqual(139, table[1].Move); Assert.AreEqual(593, table[11].Move); }