// Given a position, produce a 64-bit material signature key. // If the engine supports such a key, it should equal the engine's key. internal static ulong calc_key(Position pos, int mirror) { Color color; PieceType pt; int i; ulong key = 0; color = mirror == 0 ? Color.WHITE : Color.BLACK; for (pt = PieceType.PAWN; pt <= PieceType.KING; ++pt) { for (i = GlobalMembersTbprobe.popcount <Max15>(pos.pieces(color, pt)); i > 0; i--) { key ^= Zobrist.psq[(int)Color.WHITE][(int)pt][i - 1]; } } color = ~color; for (pt = PieceType.PAWN; pt <= PieceType.KING; ++pt) { for (i = GlobalMembersTbprobe.popcount <Max15>(pos.pieces(color, pt)); i > 0; i--) { key ^= Zobrist.psq[(int)Color.BLACK][(int)pt][i - 1]; } } return(key); }
// Given a position with 6 or fewer pieces, produce a text string // of the form KQPvKRP, where "KQP" represents the white pieces if // mirror == 0 and the black pieces if mirror == 1. //C++ TO C# CONVERTER TODO TASK: Pointer arithmetic is detected on the parameter 'str', so pointers on this parameter are left unchanged: internal static void prt_str(Position pos, sbyte *str, int mirror) { Color color; PieceType pt; int i; color = mirror == 0 ? Color.WHITE : Color.BLACK; for (pt = PieceType.KING; pt >= PieceType.PAWN; --pt) { for (i = GlobalMembersTbprobe.popcount <Max15>(pos.pieces(color, pt)); i > 0; i--) { *str++ = GlobalMembersTbcore.pchr[6 - pt]; } } *str++ = 'v'; color = ~color; for (pt = PieceType.KING; pt >= PieceType.PAWN; --pt) { for (i = GlobalMembersTbprobe.popcount <Max15>(pos.pieces(color, pt)); i > 0; i--) { *str++ = GlobalMembersTbcore.pchr[6 - pt]; } } *str++ = 0; }
internal static void init_tb(ref string str) { FD fd = new FD(); TBEntry entry; int i; int j; int[] pcs = new int[16]; ulong key; ulong key2; int color; //C++ TO C# CONVERTER TODO TASK: Pointer arithmetic is detected on this variable, so pointers on this variable are left unchanged: sbyte *s; fd = GlobalMembersTbcore.open_tb(str, DefineConstants.WDLSUFFIX); if (fd == DefineConstants.FD_ERR) { return; } GlobalMembersTbcore.close_tb(fd); for (i = 0; i < 16; i++) { pcs[i] = 0; } color = 0; for (s = str; *s; s++) { switch (*s) { case 'P': pcs[DefineConstants.TB_PAWN | color]++; break; case 'N': pcs[DefineConstants.TB_KNIGHT | color]++; break; case 'B': pcs[DefineConstants.TB_BISHOP | color]++; break; case 'R': pcs[DefineConstants.TB_ROOK | color]++; break; case 'Q': pcs[DefineConstants.TB_QUEEN | color]++; break; case 'K': pcs[DefineConstants.TB_KING | color]++; break; case 'v': color = 0x08; break; } } for (i = 0; i < 8; i++) { if (pcs[i] != pcs[i + 8]) { break; } } key = GlobalMembersTbprobe.calc_key_from_pcs(pcs, 0); key2 = GlobalMembersTbprobe.calc_key_from_pcs(pcs, 1); if (pcs[DefineConstants.TB_PAWN] + pcs[DefineConstants.TB_PAWN | 8] == 0) { if (TBnum_piece == DefineConstants.TBMAX_PIECE) { Console.Write("TBMAX_PIECE limit too low!\n"); Environment.Exit(1); } entry = (TBEntry)TB_piece[TBnum_piece++]; } else { if (TBnum_pawn == DefineConstants.TBMAX_PAWN) { Console.Write("TBMAX_PAWN limit too low!\n"); Environment.Exit(1); } entry = (TBEntry)TB_pawn[TBnum_pawn++]; } entry.key = key; entry.ready = 0; entry.num = 0; for (i = 0; i < 16; i++) { entry.num += (byte)pcs[i]; } entry.symmetric = (key == key2); entry.has_pawns = (pcs[DefineConstants.TB_PAWN] + pcs[DefineConstants.TB_PAWN | 8] > 0); if (entry.num > GlobalMembersTbprobe.MaxCardinality) { GlobalMembersTbprobe.MaxCardinality = entry.num; } if (entry.has_pawns != 0) { TBEntry_pawn ptr = (TBEntry_pawn)entry; ptr.pawns[0] = (byte)pcs[DefineConstants.TB_PAWN]; ptr.pawns[1] = (byte)pcs[DefineConstants.TB_PAWN | 8]; if (pcs[DefineConstants.TB_PAWN | 8] > 0 && (pcs[DefineConstants.TB_PAWN] == 0 || pcs[DefineConstants.TB_PAWN | 8] < pcs[DefineConstants.TB_PAWN])) { ptr.pawns[0] = (byte)pcs[DefineConstants.TB_PAWN | 8]; ptr.pawns[1] = (byte)pcs[DefineConstants.TB_PAWN]; } } else { TBEntry_piece ptr = (TBEntry_piece)entry; for (i = 0, j = 0; i < 16; i++) { if (pcs[i] == 1) { j++; } } if (j >= 3) { ptr.enc_type = 0; } else if (j == 2) { ptr.enc_type = 2; } else // only for suicide { j = 16; for (i = 0; i < 16; i++) { if (pcs[i] < j && pcs[i] > 1) { j = pcs[i]; } ptr.enc_type = (byte)(1 + j); } } } GlobalMembersTbcore.add_to_hash(entry, key); if (key2 != key) { GlobalMembersTbcore.add_to_hash(entry, key2); } }
// 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); } }
internal static int probe_ab(Position pos, int alpha, int beta, ref int success) { int v; ExtMove[] stack = Arrays.InitializeWithDefaultInstances <ExtMove>(64); ExtMove moves; ExtMove end; StateInfo st = new StateInfo(); // Generate (at least) all legal non-ep captures including (under)promotions. // It is OK to generate more, as long as they are filtered out below. 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<CAPTURES>(pos, stack); end = GlobalMembersMovegen.generate <GenType.CAPTURES>(pos, new ExtMove(stack)); // Since underpromotion captures are not included, we need to add them. //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 = add_underprom_caps(pos, stack, end); end = GlobalMembersTbprobe.add_underprom_caps(pos, new ExtMove(stack), end); } 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)); } CheckInfo ci = new CheckInfo(pos); for (moves = stack; moves < end; moves++) { Move capture = moves.move; if (!pos.capture(capture) || GlobalMembersTypes.type_of(capture) == MoveType.ENPASSANT || !pos.legal(capture, ci.pinned)) { continue; } pos.do_move(capture, st, ci, pos.gives_check(capture, ci)); v = -GlobalMembersTbprobe.probe_ab(pos, -beta, -alpha, ref success); pos.undo_move(capture); if (success == 0) { return(0); } if (v > alpha) { if (v >= beta) { success = 2; return(v); } alpha = v; } } v = GlobalMembersTbprobe.probe_wdl_table(pos, ref success); if (success == 0) { return(0); } if (alpha >= v) { success = 1 + (alpha > 0); return(alpha); } else { success = 1; return(v); } }
internal static int probe_dtz_table(Position pos, int wdl, ref int success) { TBEntry ptr; ulong idx; int i; int res; int[] p = new int[DefineConstants.TBPIECES]; // Obtain the position's material signature key. ulong key = pos.material_key(); if (GlobalMembersTbcore.DTZ_table[0].key1 != key && GlobalMembersTbcore.DTZ_table[0].key2 != key) { for (i = 1; i < DefineConstants.DTZ_ENTRIES; i++) { if (GlobalMembersTbcore.DTZ_table[i].key1 == key) { break; } } if (i < DefineConstants.DTZ_ENTRIES) { DTZTableEntry table_entry = GlobalMembersTbcore.DTZ_table[i]; for (; i > 0; i--) { GlobalMembersTbcore.DTZ_table[i] = GlobalMembersTbcore.DTZ_table[i - 1]; } GlobalMembersTbcore.DTZ_table[0] = table_entry; } else { TBHashEntry[] ptr2 = GlobalMembersTbcore.TB_hash[key >> (64 - DefineConstants.TBHASHBITS)]; for (i = 0; i < DefineConstants.HSHMAX; i++) { if (ptr2[i].key == key) { break; } } if (i == DefineConstants.HSHMAX) { success = 0; return(0); } ptr = ptr2[i].ptr; string str = new string(new char[16]); int mirror = (ptr.key != key); GlobalMembersTbprobe.prt_str(pos, str, mirror); if (GlobalMembersTbcore.DTZ_table[DefineConstants.DTZ_ENTRIES - 1].entry != null) { GlobalMembersTbcore.free_dtz_entry(GlobalMembersTbcore.DTZ_table[DefineConstants.DTZ_ENTRIES - 1].entry); } for (i = DefineConstants.DTZ_ENTRIES - 1; i > 0; i--) { GlobalMembersTbcore.DTZ_table[i] = GlobalMembersTbcore.DTZ_table[i - 1]; } GlobalMembersTbcore.load_dtz_table(ref str, GlobalMembersTbprobe.calc_key(pos, mirror), GlobalMembersTbprobe.calc_key(pos, mirror == 0)); } } ptr = GlobalMembersTbcore.DTZ_table[0].entry; if (ptr == null) { success = 0; return(0); } int bside; int mirror; int cmirror; if (ptr.symmetric == 0) { if (key != ptr.key) { cmirror = 8; mirror = 0x38; bside = (pos.side_to_move() == Color.WHITE); } else { cmirror = mirror = 0; bside = !(pos.side_to_move() == Color.WHITE); } } else { cmirror = (int)pos.side_to_move() == ((int)Color.WHITE) != 0 ? 0 : 8; mirror = (int)pos.side_to_move() == ((int)Color.WHITE) != 0 ? 0 : 0x38; bside = 0; } if (ptr.has_pawns == 0) { DTZEntry_piece entry = (DTZEntry_piece)ptr; if ((entry.flags & 1) != bside && entry.symmetric == 0) { success = -1; return(0); } byte[] pc = entry.pieces; for (i = 0; i < entry.num;) { uint GlobalMembersBitboard.long bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3), (PieceType)(pc[i] & 0x07)); do { p[i++] = (int)GlobalMembersBitboard.pop_lsb(ref bb); } while (bb); } idx = GlobalMembersTbcore.encode_piece((TBEntry_piece)entry, entry.norm, p, entry.factor); res = GlobalMembersTbcore.decompress_pairs(entry.precomp, idx); if ((entry.flags & 2) != 0) { res = entry.map[entry.map_idx[GlobalMembersTbcore.wdl_to_map[wdl + 2]] + res]; } if (!(entry.flags & GlobalMembersTbcore.pa_flags[wdl + 2]) || (wdl & 1)) { res *= 2; } } else { DTZEntry_pawn entry = (DTZEntry_pawn)ptr; int k = entry.file[0].pieces[0] ^ cmirror; uint GlobalMembersBitboard.long bb = pos.pieces((Color)(k >> 3), (PieceType)(k & 0x07)); i = 0; do { p[i++] = (int)GlobalMembersBitboard.pop_lsb(ref bb) ^ mirror; } while (bb); int f = GlobalMembersTbcore.pawn_file((TBEntry_pawn)entry, p); if ((entry.flags[f] & 1) != bside) { success = -1; return(0); } byte[] pc = entry.file[f].pieces; for (; i < entry.num;) { bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3), (PieceType)(pc[i] & 0x07)); do { p[i++] = (int)GlobalMembersBitboard.pop_lsb(ref bb) ^ mirror; } while (bb); } idx = GlobalMembersTbcore.encode_pawn((TBEntry_pawn)entry, entry.file[f].norm, p, entry.file[f].factor); res = GlobalMembersTbcore.decompress_pairs(entry.file[f].precomp, idx); if ((entry.flags[f] & 2) != 0) { res = entry.map[entry.map_idx[f, GlobalMembersTbcore.wdl_to_map[wdl + 2]] + res]; } if (!(entry.flags[f] & GlobalMembersTbcore.pa_flags[wdl + 2]) || (wdl & 1)) { res *= 2; } } return(res); }
// probe_wdl_table and probe_dtz_table require similar adaptations. internal static int probe_wdl_table(Position pos, ref int success) { TBEntry ptr; TBHashEntry[] ptr2; ulong idx; ulong key; int i; byte res; int[] p = new int[DefineConstants.TBPIECES]; // Obtain the position's material signature key. key = pos.material_key(); // Test for KvK. if (key == (Zobrist.psq[(int)Color.WHITE][(int)PieceType.KING][0] ^ Zobrist.psq[(int)Color.BLACK][(int)PieceType.KING][0])) { return(0); } ptr2 = GlobalMembersTbcore.TB_hash[key >> (64 - DefineConstants.TBHASHBITS)]; for (i = 0; i < DefineConstants.HSHMAX; i++) { if (ptr2[i].key == key) { break; } } if (i == DefineConstants.HSHMAX) { success = 0; return(0); } ptr = ptr2[i].ptr; if (ptr.ready == 0) { LOCK(GlobalMembersTbcore.TB_mutex); if (ptr.ready == 0) { string str = new string(new char[16]); GlobalMembersTbprobe.prt_str(pos, str, ptr.key != key); if (GlobalMembersTbcore.init_table_wdl(ptr, ref str) == 0) { ptr2[i].key = 0UL; success = 0; UNLOCK(GlobalMembersTbcore.TB_mutex); return(0); } // Memory barrier to ensure ptr->ready = 1 is not reordered. #if _MSC_VER _ReadWriteBarrier(); #else __asm__ __volatile__ = new __asm__("" global::: "memory"); #endif ptr.ready = 1; } UNLOCK(GlobalMembersTbcore.TB_mutex); } int bside; int mirror; int cmirror; if (ptr.symmetric == 0) { if (key != ptr.key) { cmirror = 8; mirror = 0x38; bside = (pos.side_to_move() == Color.WHITE); } else { cmirror = mirror = 0; bside = !(pos.side_to_move() == Color.WHITE); } } else { cmirror = (int)pos.side_to_move() == ((int)Color.WHITE) != 0 ? 0 : 8; mirror = (int)pos.side_to_move() == ((int)Color.WHITE) != 0 ? 0 : 0x38; bside = 0; } // p[i] is to contain the square 0-63 (A1-H8) for a piece of type // pc[i] ^ cmirror, where 1 = white pawn, ..., 14 = black king. // Pieces of the same type are guaranteed to be consecutive. if (ptr.has_pawns == 0) { TBEntry_piece entry = (TBEntry_piece)ptr; byte[] pc = entry.pieces[bside]; for (i = 0; i < entry.num;) { uint GlobalMembersBitboard.long bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3), (PieceType)(pc[i] & 0x07)); do { p[i++] = (int)GlobalMembersBitboard.pop_lsb(ref bb); } while (bb); } idx = GlobalMembersTbcore.encode_piece(entry, entry.norm[bside], p, entry.factor[bside]); res = GlobalMembersTbcore.decompress_pairs(entry.precomp[bside], idx); } else { TBEntry_pawn entry = (TBEntry_pawn)ptr; int k = entry.file[0].pieces[0, 0] ^ cmirror; uint GlobalMembersBitboard.long bb = pos.pieces((Color)(k >> 3), (PieceType)(k & 0x07)); i = 0; do { p[i++] = (int)GlobalMembersBitboard.pop_lsb(ref bb) ^ mirror; } while (bb); int f = GlobalMembersTbcore.pawn_file(entry, p); byte[] pc = entry.file[f].pieces[bside]; for (; i < entry.num;) { bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3), (PieceType)(pc[i] & 0x07)); do { p[i++] = (int)GlobalMembersBitboard.pop_lsb(ref bb) ^ mirror; } while (bb); } idx = GlobalMembersTbcore.encode_pawn(entry, entry.file[f].norm[bside], p, entry.file[f].factor[bside]); res = GlobalMembersTbcore.decompress_pairs(entry.file[f].precomp[bside], idx); } return(((int)res) - 2); }
internal static byte decompress_pairs(PairsData d, ulong idx) { bool isLittleEndian = GlobalMembersTbprobe.is_little_endian(); return(isLittleEndian ? GlobalMembersTbcore.decompress_pairs <true>(d, idx) : GlobalMembersTbcore.decompress_pairs <false>(d, idx)); }