Проще говоря, малые биты - это эффективный способ занять позицию и получить правовые движения для скользящей части.
Во-первых, вам нужно найти магические числа. Некоторые из кода, который вы пишете на , находите магические числа также будут повторно использоваться, когда вы используете магические числа.
Для начала вам необходимо написать 5 функций. Они не должны быть особенно быстрыми, потому что вы будете использовать их только при поиске магических чисел и один раз при запуске программы, прежде чем использовать свои магические числа. Вы можете использовать любую старую технику в этих функциях.
uint64_t blockermask_rook (int square);
uint64_t blockermask_bishop (int square);
uint64_t moveboard_rook (int square, uint64_t blockerboard);
uint64_t moveboard_bishop (int square, uint64_t blockerboard);
uint64_t blockerboard (int index, uint64_t blockermask);
Таким образом, вы можете спросить себя, да f% q - блокирующая маска, доска для перемещения и блокирующая панель? Ну, я только что сделал условие, но вот что я имею в виду под ними:
/* Example, Rook on e4:
*
* The blocker mask A blocker board The move board
* 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
* 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
* 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
* 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0
* 0 1 1 1 0 1 1 0 0 1 1 0 0 0 0 0 0 0 1 1 0 1 1 1
* 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
* 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0
* 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
*/
Маска блокирующей все квадратов, которые могут быть заняты и блокировать ваш кусок двигаться дальше. Крайние квадраты не обязательно должны быть частью этого, потому что ваш кусок не может двигаться дальше этого квадрата. Количество 1 в этой доске определяет, сколько больших поисковых таблиц вам нужно для этой части. & квадратная комбинация. В этом случае их 10, поэтому есть 2^10 (1024) возможных перестановок кусков, которые могут блокировать ладью e4.
Плата блокатора является одной из этих перестановок. В этом примере есть фрагменты на b4, c4, e2, e5 и e7. Это враги и дружественных частей. Плата блокатора всегда является подмножеством маски блокатора (ей не нужно отображать кусочки на других квадратах (например, blockers = occupancy & blockermask;
)).
Плата перехода является результирующими доступными ходами для вашей части для данной блокирующей доски. Это включает в себя возможность захвата вашей пьесы. Обратите внимание, что это также включает в себя захват ваших собственных произведений (но вы можете просто И это с НЕ из ваших мест кусочков, чтобы удалить их).
Итак, в основном вам нужно создать маску блокировщика на всех квадратах, как для ладьи, так и для слона. И вам также нужно создать все возможные блокираторы на каждом квадрате, как для ладьи, так и для слона. Когда вы создаете доски блокаторов, вы также должны генерировать результирующие платы перемещения. Храните все это в массивах для последующего использования.
Теперь, когда вы сделали это, для каждой комбинации квадратов/частей вы производите случайные 64-битные номера и видите, являются ли они волшебными. Вы узнаете, являются ли они волшебными, используя магическую формулу, return ((blockerboard*magic) >> (64-bits));
, которая создаст магический индекс из 0..2^бит (0..1024 в случае ладьи e4). Для определенного куска/квадрата, если две блокирующие доски когда-либо генерируют один и тот же магический индекс , но, эти две платы-доски имеют разные доски для перемещения, тогда это номер магглов, и вы должны попробовать новый.
Как только вы получите это, у вас будет 64 числа магии ладьи и 64 числа магических слонов. Чтобы использовать их, при запуске программы вы будете инициализировать все блокирующие маски, блокирующие доски и перемещать доски. И теперь ваша программа может эффективно искать доски для епископов и ладей на любом квадрате (и, следовательно, также королевы). Код для этого будет выглядеть примерно так:
/* Retrieves the move board for the given square and occupancy board. */
uint64_t magic_move_rook (int8_t square, uint64_t occupancy)
{
/* Remove occupants that aren't in the blocker mask for this square. */
occupancy &= Rook.blockmask[square];
/* Calculate the magic move index. */
int index = (occupancy*Rook.magic[square]) >> (64-Rook.bits[square]);
/* Return the pre-calculated move board. */
return Rook.moveboard[square][index];
}
Большое спасибо Zong Zheng Li, который отвечает на мой вопрос. Хотя на данный момент я использую более простой подход (http://chessprogramming.wikispaces.com/Classical+Approach), я вернусь к магическим советам, как только приступлю к общему процессу, включая поиск и оценку. – bytefire
@bytefire Да, в моем собственном движке я также использую классический подход, поскольку его было легко реализовать как временный компонент. Я обнаружил, что он достаточно быстр ('perft (6)' через 2 секунды), что выигрыш от перехода к магическому поколению в значительной степени незначителен, поэтому я просто сохранил его. – Zong
Это очень полезно, поскольку оно добавляет больше значения тому, что я сейчас реализую. На стороне примечания, когда я ударил дальнейшие блокпосты, я буду размещать вопросы на SO с тегом «шахматы». Ждем больше помощи :) – bytefire