Шахматы: высокий коэффициент ветвления

Я пытаюсь разработать простой шахматный движок, но я борюсь с его исполнением. Я реализовал Negamax с альфа-бета-обрезкой и итеративным углублением (без каких-либо дополнительных эвристик), но я не могу получить разумное время поиска за пределами 3-4-го слоя. Вот выдержка из журнала моей программы с самого начала игры:

2013-05-11 18:22:06,835 [9] INFO  CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Searching at depth 1
2013-05-11 18:22:06,835 [9] DEBUG CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Leaves searched: 28
2013-05-11 18:22:06,835 [9] DEBUG CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Nodes searched: 28
2013-05-11 18:22:06,835 [9] DEBUG CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Found PV: A4->A6 
2013-05-11 18:22:06,835 [9] INFO  CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Searching at depth 2
2013-05-11 18:22:06,897 [9] DEBUG CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Leaves searched: 90
2013-05-11 18:22:06,897 [9] DEBUG CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Nodes searched: 118
2013-05-11 18:22:06,897 [9] DEBUG CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Found PV: A2->A3 B7->B6 
2013-05-11 18:22:06,897 [9] INFO  CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Searching at depth 3
2013-05-11 18:22:08,005 [9] DEBUG CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Leaves searched: 6027
2013-05-11 18:22:08,005 [9] DEBUG CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Nodes searched: 6414
2013-05-11 18:22:08,005 [9] DEBUG CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Found PV: A2->A3 A6->B8 A4->A7 
2013-05-11 18:22:08,005 [9] INFO  CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Searching at depth 4
2013-05-11 18:22:10,485 [9] DEBUG CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Leaves searched: 5629
2013-05-11 18:22:10,485 [9] DEBUG CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Nodes searched: 6880
2013-05-11 18:22:10,485 [9] DEBUG CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Found PV: D2->D4 A6->B8 C4->C5 A7->A6 
2013-05-11 18:22:10,485 [9] INFO  CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Searching at depth 5
2013-05-11 18:22:34,353 [9] DEBUG CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Leaves searched: 120758
2013-05-11 18:22:34,353 [9] DEBUG CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Nodes searched: 129538
2013-05-11 18:22:34,353 [9] DEBUG CoevolutionaryChess.Engine.MoveSearchers.NegamaxMoveSearcher [(null)] - Found PV: D2->D4 A6->B8 C4->C5 A7->A6 A4->A6 

Это показывает, что коэффициент ветвления составляет около 10. Я прочитал, что при правильном заказе движения я должен получить что-то около 6, поэтому я подозреваю, что мой приказ неверен. В настоящее время он работает следующим образом:

  1. узел игрового дерева имеет связанный список своих детей; первоначально захваты и акции размещаются перед тихими ходами
  2. во время поиска ребенок, который увеличивает Альфа или вызывает отсечение, помещается в начале списка
  3. на следующей итерации углубления PV следует искать сначала

это правильный способ упорядочить движения и коэффициент ветвления, который я получаю, должен быть ожидаемые? В настоящее время я использую простую статическую функцию оценки, которая учитывает только материальную разницу позиции - может ли это быть причиной низкой скорости отсечения (Если также учитывать мобильность фигур, я получаю аналогичные результаты)? Помогут ли такие методы, как уменьшение нулевого хода или эвристика убийцы (не на 10-15%, а на порядок)? Я не ожидаю, что мой двигатель будет сильным, но я хотел бы получить коэффициент ветвления около 6.

2 ответов


Я также разработал шахматный движок на C#, и он имеет коэффициент ветвления около 2,5. Определенно возможно улучшить ваш двигатель много порядков величин. В настоящее время общая стратегия заключается в использовании очень агрессивной обрезки хода на основе хорошего порядка движения. Вы жертвуете некоторой корректностью, чтобы увидеть некоторые глубокие тактические линии.

вот обзор методов, которые я нашел наиболее эффективными. Обратите внимание, что некоторые компоненты являются дополнениями, а другие заменители, поэтому даю общие рекомендации. Большие достижения в конце списка невозможны, если у вас нет прочной основы.

  1. просто negamax С альфа-бета обрезка: глубина 4 в течение 3 секунд.

  2. добавить итеративным углублением и нулевая эвристика перемещения: глубина 5. Итеративное углубление на данный момент не очень помогает, Но легко осуществлять. Значение null move состоит из пропуска вашей очереди и посмотреть, если вы все еще можете получить бета-отсечение с неглубоким поиском. Если вы можете, то это, вероятно, безопасно обрезать дерево, так как это почти всегда выгодно двигаться.

  3. убийца эвристический: глубина 6. Это включает в себя хранение ходов, которые потому что beta cutoffs и пытается их сначала, если они легальны в следующий раз вы находитесь на той же глубине. Кажется, ты делаешь что-то похожее. уже.

  4. заказ MVV/LVA: глубина 8. В принципе, вы хотите поместить захваты, которые имейте много потенциального материального чистого выигрыша в верхней части движения список. Поэтому, если пешка захватывает ферзя, вы должны сначала обыскать ее.

  5. представление Bitboard: глубина 10. Это не улучшает ветвление фактор, но это то, что я сделал, когда достиг этой точки. Канава массивы, используйте UInt64s вместо этого и используйте make / unmake вместо copy-make. Вам не нужно использовать волшебные битборды, если вам это сложно; есть более простые методы, которые все еще очень быстры. Bitboards значительно улучшают производительность и сделать его легким написать компоненты оценки. Я ушел от perft (6) от минут до 3 секунд. (Кстати, написание функции perft-отличный способ обеспечить правильность генерации перемещения)

  6. транспозиция таблице: глубина 13. Это предлагает большие выгоды, но также очень трудно понять. Быть абсолютно уверены, что ваша позиция хеширования правильно перед реализацией таблицы. Большая часть прибыли приходит от удивительный ход, который дает заказ стола. Всегда храните лучшее переместитесь в таблицу и всякий раз, когда вы получаете соответствующую позицию, попробуйте первый.

  7. сокращение позднего хода: глубина 16. Это значительно раздувает вашу глубину поиска, но усиление силы больше искусственно, чем с другими методами. В основном ваш переместить порядок так хорошо сейчас, что вам нужно только полностью искать первые несколько перемещается в узле, и вы можете просто проверить другие с неглубокими поисками.

  8. бесперспективность обрезке: глубина 17. Листовые узлы обрезаются пропуском ходов которые имеют низкую вероятность улучшения значения узла при взгляде на потенциал материальная выгода. Если чистый потенциальный выигрыш от move + статической оценки позиции ниже текущего значения позиции, пропустите этот оценка для переезда.

существуют различные другие компоненты,которые также помогают, но большинство из них незначительны, а некоторые являются собственностью. :D однако речь идет не только о высоких глубинах поиска и низких факторах ветвления. Такие вещи, как короткошерстные поиск ухудшает глубину поиска, но в значительной степени является необходимостью для любого двигателя. Без него ваш двигатель будет страдать от больших тактических ошибок. Вы также можете рассмотреть проверяем расширения и расширения одного ответа. Я бы также рекомендовал по крайней мере ввести piece-квадратные таблицы функции оценки. Это очень простой способ значительно улучшить позиционные знания вашей программы; вы, вероятно, увидите, что ваш движок играет более общие отверстия. Шахматное Программирование-забавное хобби, и я надеюсь, что объем информации не обескуражит вас!


существует несколько эвристик, которые можно использовать для уменьшения коэффициента ветвления.

во-первых, вы должны использовать таблица транспозиции (TT) для хранения результатов позиций, глубины и лучшего хода. Прежде чем искать перемещение, сначала проверьте, было ли оно уже выполнено на глубине >= на глубину, которую вы планируете искать. Если это так, вы можете просто использовать результат из таблицы. Если это не так, вы все равно можете использовать ход в таблице в качестве первого хода поиск.

Если нет совпадения в TT для позиции (внутри поиска), вы можете использовать итеративное углубление (ID). Вместо того, чтобы делать поиск на глубину N, вы сначала выполните поиск на глубину N-2. Это будет очень быстро и даст вам возможность сначала искать на глубине N.

появилась Null Перемещение Обрезки. В сочетании с Альфа-Бета (Negamax является вариацией на Альфа-Бета) в значительно уменьшит ваш фактор ветвления. Идея заключается в том, что перед поиском позиции вы пробуете нулевой ход (не играя) и выполняете поиск сокращения (N-2 или N-3). Сократить поиск будет очень быстрым. Если результат поиска нулевого перемещения по-прежнему выше бета-версии, это означает, что позиция настолько плоха, что вам больше не нужно искать ее (не всегда верно, но в большинстве случаев).

конечно, есть несколько других эвристических вы можете использовать, чтобы улучшить свой переместить заказ который все улучшит ваш фактор ветвления.