private static bool Read(ref BookEntry e, BinaryReader br) { if (br.BaseStream.Length == br.BaseStream.Position) { return(false); } byte[] t = br.ReadBytes((int)SIZE_OF_BOOKENTRY); e.key = (((UInt64)t[0]) << 56) | (((UInt64)t[1]) << 48) | (((UInt64)t[2]) << 40) | (((UInt64)t[3]) << 32) | (((UInt64)t[4]) << 24) | (((UInt64)t[5]) << 16) | (((UInt64)t[6]) << 8) | (((UInt64)t[7]) << 0); e.move = (UInt16)( (((UInt64)t[8]) << 8) | (((UInt64)t[9]) << 0)); e.count = (UInt16)( (((UInt64)t[10]) << 8) | (((UInt64)t[11]) << 0)); e.learn = (UInt32)( (((UInt64)t[12]) << 24) | (((UInt64)t[13]) << 16) | (((UInt64)t[14]) << 8) | (((UInt64)t[15]) << 0)); return(true); }
/// Book::binary_search() takes a book key as input, and does a binary search /// through the book file for the given key. File stream current position is set /// to the leftmost book entry with the same key as the input. private static void binary_search(UInt64 key, UInt64 size, BinaryReader br) { UInt64 low, high, mid; BookEntry e = new BookEntry(); low = 0; high = (ulong)(size - 1); Debug.Assert(low <= high); while (low < high) { mid = (low + high) / 2; Debug.Assert(mid >= low && mid < high); br.BaseStream.Seek((long)(mid * SIZE_OF_BOOKENTRY), SeekOrigin.Begin); Read(ref e, br); if (key <= e.key) { high = mid; } else { low = mid + 1; } } Debug.Assert(low == high); br.BaseStream.Seek((long)(low * SIZE_OF_BOOKENTRY), SeekOrigin.Begin); }
/// 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 WINDOWS_RT #region DLL book (local) 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); using (Stream fs = typeof(Engine).GetTypeInfo().Assembly.GetManifestResourceStream("SethRocks.book.bin")) { if (fs == null) { bookNotExists = true; return(MoveC.MOVE_NONE); } 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; } } } } #endregion #elif 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("SethRocksBook"); using (Stream fs = bookAssembly.GetManifestResourceStream("SethRocksBook.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); }