Головоломка програміста: кодування стану шахової дошки протягом гри


95

Не суворо питання, більше загадка ...

Протягом багатьох років я брав участь у кількох технічних співбесідах нових співробітників. Окрім стандартних питань "чи знаєш ти технологію X", я також намагався зрозуміти, як вони підходять до проблем. Як правило, я надсилав їм запитання електронною поштою за день до співбесіди і очікував, що вони прийдуть рішення до наступного дня.

Часто результати були б досить цікавими - неправильними, але цікавими - і людина все одно отримала б мою рекомендацію, якби могла пояснити, чому застосувала той чи інший підхід.

Тож я подумав кинути одне зі своїх запитань для аудиторії Stack Overflow.

Запитання: Який найефективніший у космосі спосіб ви можете придумати для кодування стану шахової партії (або її підгрупи)? Тобто, враховуючи шахову дошку з фігурами, розташованими законно, кодують і цей початковий стан, і всі наступні легальні ходи, зроблені гравцями в грі.

Для відповіді не потрібен код, лише опис алгоритму, який ви використовуєте.

EDIT: Як зазначав один із плакатів, я не враховував часовий інтервал між ходами. Не соромтеся враховувати це теж як необов’язкову додаткову послугу :)

EDIT2: Лише для додаткових роз’яснень ... Пам’ятайте, кодер / декодер відповідає правилам. Єдине, що дійсно потрібно зберегти, - це вибір гравця - все інше можна вважати відомим кодером / декодером.

EDIT3: Тут буде важко вибрати переможця :) Багато чудових відповідей!


4
Хіба початковий стан гри в шахи чітко не визначений? Чому він повинен бути закодований? Я думаю, цього повинно бути достатньо для кодування різниць між кожним оборотом (= переміщення).
Танацій

1
Він припускає, що партія може розпочатися з будь-якої початкової легальної установки (як і в головоломках із шахів, які ви можете знайти в газетах).
Аарон Дігулла

6
щоб бути строгим, вам також доведеться закодувати всі минулі позиції, тому що якщо одна і та ж позиція з’являється тричі, це нічия en.wikipedia.org/wiki/Threefold_repetition
flybywire

4
Пропозиція: зробіть це справжнім конкурсом, де люди подаватимуть свої роботи як програми. Програма взяла б за основу шахову гру (ви можете визначити для цього якийсь базовий, зручний для читання, неоптимізований формат) і видала б стиснуту гру. Потім, з параметром, він буде приймати стиснуту гру і регенерувати вихідний вхід, який повинен збігатися.
Вількс

2
Точніше, це продемонструвало б, що ви не можете слідувати інструкціям ... Навіть найбільш уберкодерам потрібно в якийсь момент дотримуватися інструкцій. Я стикався з ситуаціями, коли мені казали реалізовувати щось певним чином, хоча я вважав (і говорив), що це дурна реалізація, але я залишився з яйцем на обличчі, коли виявилося, що була дуже вагома причина (яку я не знав і не розумів), щоб її реалізувати таким чином.
Ендрю Роллінгс,

Відповіді:


132

Оновлення: ця тема мені так сподобалася, я писав загадки для програмування, шахові позиції та кодування Хаффмана . Якщо ви прочитаєте це, я визначив, що єдиним способом збереження повного стану гри є збереження повного списку ходів. Читайте далі, чому. Тому я використовую дещо спрощену версію задачі для компонування.

Проблема

Це зображення ілюструє початкову шахову позицію. Шахи відбуваються на дошці 8х8, кожен гравець починає з однакового набору з 16 фігур, що складається з 8 пішаків, 2 граків, 2 лицарів, 2 єпископів, 1 королеви та 1 короля, як показано тут:

вихідна шахова позиція

Позиції, як правило, реєструються як буква для стовпця, за якою слідує номер для рядка, тому дама білих знаходиться на d1. Переміщення найчастіше зберігаються в алгебраїчних позначеннях , що є однозначним і, як правило, визначає лише мінімальну необхідну інформацію. Розгляньте це відкриття:

  1. e4 e5
  2. Nf3 Nc6

що перекладається як:

  1. Білий переміщує пішака короля з e2 на e4 (це єдина фігура, яка може дістатися до e4, отже, “e4”);
  2. Чорний переміщує пішака короля з e7 на e5;
  3. Білий переміщує лицаря (N) до f3;
  4. Чорний переводить лицаря на c6.

Дошка виглядає так:

раннє відкриття

Важливою здатністю будь-якого програміста є вміння правильно і однозначно вказати проблему .

То що бракує чи неоднозначно? Як виявляється, багато.

Держава дошки проти держави гри

Перше, що вам потрібно визначити, це те, чи зберігаєте ви стан гри чи положення фігур на дошці. Кодування просто позицій частин - це одне, але проблема говорить "всі наступні юридичні дії". Проблема також нічого не говорить про знання кроків до цього моменту. Це власне проблема, як я поясню.

Рокінг

Гра тривала наступним чином:

  1. e4 e5
  2. Nf3 Nc6
  3. Bb5 a6
  4. Ba4 Bc5

Дошка виглядає так:

пізніше відкриття

Білий має можливість закидати . Частина вимог для цього полягає в тому, що король і відповідна ладья ніколи не могли рухатися, тому, чи рухався король або кожна грач з кожної сторони, потрібно буде зберігати. Очевидно, що якщо вони не перебувають на вихідних позиціях, вони рухаються, інакше це потрібно вказати.

Існує кілька стратегій, які можна використовувати для вирішення цієї проблеми.

По-перше, ми могли б зберегти додаткові 6 біт інформації (по 1 на кожну ладью та короля), щоб вказати, чи рухалася ця фігура. Ми могли б впорядкувати це, лише зберігаючи трохи для одного з цих шести квадратів, якщо в ньому випадково опиниться потрібний фрагмент. В якості альтернативи ми могли б розглядати кожну непорушену фігуру як інший тип фігури, тож замість 6 типів фігур на кожній стороні (пішак, ладья, лицар, єпископ, королева та король) їх є 8 (додаючи непорушну ладью та незворушного короля).

En Passant

Ще одне своєрідне і часто нехтуване правило в шахах - En Passant .

en passant

Гра прогресувала.

  1. e4 e5
  2. Nf3 Nc6
  3. Bb5 a6
  4. Ba4 Bc5
  5. OO b5
  6. Bb3 b4
  7. c4

Пішак Чорного на b4 тепер має можливість перемістити пішака на b4 на c3, приймаючи Білу пішака на c4. Це трапляється лише при першій можливості, тобто якщо Чорний передає опцію зараз, він не може зробити наступний хід. Тож нам потрібно це зберігати.

Якщо ми знаємо попередній крок, ми точно можемо відповісти, чи можливий En Passant. Крім того, ми можемо зберегти, чи кожна пішак свого 4-го рангу щойно переїжджала туди, подвійним рухом вперед. Або ми можемо розглянути кожну можливу позицію En Passant на дошці та мати прапорець, який вказує, чи можливо це чи ні.

Акція

просування пішака

Це крок Білого. Якщо білий перемістить пішака на h7 на h8, його можна підвищити до будь-якої іншої фігури (але не до короля). У 99% випадків він підвищується до Королеви, але іноді це не так, як правило, тому що це може призвести до патової ситуації, коли інакше ви переможете. Це написано так:

  1. h8 = Q

Це важливо в нашій проблемі, оскільки це означає, що ми не можемо розраховувати на наявність фіксованої кількості штук на кожній стороні. Цілком можливо (але неймовірно малоймовірно), щоб одна сторона отримала 9 ферзів, 10 граків, 10 єпископів або 10 лицарів, якщо всі 8 пішаків отримають підвищення.

Патова ситуація

Коли ти в позиції, з якої ти не можеш виграти, твоя найкраща тактика - це спробувати глухий кут . Найімовірнішим варіантом є те, що ви не можете зробити законний крок (зазвичай тому, що будь-який крок, коли ви ставите свого короля під контроль). У цьому випадку ви можете вимагати нічию. Це легко задовольнити.

Другий варіант - триразове повторення . Якщо одна і та ж позиція дошки трапляється тричі в грі (або траплятиметься втретє при наступному ході), може бути заявлена ​​нічия. Позиції не повинні відбуватися в якомусь певному порядку (це означає, що він не повинен повторювати однакову послідовність ходів тричі). Це значно ускладнює проблему, тому що ви повинні пам'ятати кожну попередню позицію дошки. Якщо це є вимогою проблеми, єдино можливим рішенням проблеми є збереження кожного попереднього ходу.

Нарешті, існує правило п’ятдесяти ходів . Гравець може претендувати на нічию, якщо жодна пішак не переїхала і жодна фігура не була взята за попередні п'ятдесят послідовних ходів, тому нам потрібно буде зберегти, скільки ходів було переміщено пішаком або взята фігура (остання з двох. Для цього потрібно 6 біт (0-63).

Чия черга?

Звичайно, нам також потрібно знати, на кого черга, і це єдиний біт інформації.

Дві проблеми

Через безвихідний випадок єдиним можливим або розумним способом збереження ігрового стану є збереження всіх ходів, що призвели до цієї позиції. Я вирішу цю проблему. Проблема стану дошки буде спрощена до наступного: зберігати поточне положення всіх фігур на дошці, ігноруючи закидання, пасивні ситуації, тупикові умови та чия черга .

Компонування шматка можна в широкому обсязі виконати одним із двох способів: зберігаючи вміст кожного квадрата або зберігаючи позицію кожного шматка.

Простий зміст

Існує шість типів штук (пішак, грак, лицар, єпископ, королева та король). Кожна фігура може бути білою або чорною, тому квадрат може містити одну з 12 можливих фігур або може бути порожньою, тому існує 13 можливостей. 13 можна зберігати в 4 бітах (0-15) Отже, найпростішим рішенням є зберігання 4 бітів для кожного квадрата, помноженого на 64 квадрата або 256 біт інформації.

Перевага цього методу полягає в тому, що маніпуляції неймовірно легкі та швидкі. Це можна навіть розширити, додавши ще 3 можливості, не збільшуючи вимог до зберігання: пішак, який перемістив 2 місця на останній черзі, король, який не рухався, і грач, який не рухався, що задовольнить багато чого раніше згаданих питань.

Але ми можемо зробити краще.

База 13 Кодування

Часто корисно думати про позицію дошки як про дуже велику кількість. Це часто робиться в галузі інформатики. Наприклад, проблема зупинки трактує комп’ютерну програму (справедливо) як велику кількість.

Перше рішення розглядає позицію як 64-значне базове число 16, але, як було продемонстровано, ця інформація є надмірною (це 3 невикористані можливості на “цифру”), тому ми можемо зменшити числовий простір до 64 базових 13 цифр. Звичайно, це неможливо зробити настільки ефективно, як це може зробити база 16, але це заощадить на вимогах до сховища (і мінімізація місця для зберігання є нашою метою).

В основі 10 число 234 еквівалентно 2 x 10 2 + 3 x 10 1 + 4 x 10 0 .

В основі 16 число 0xA50 еквівалентно 10 x 16 2 + 5 x 16 1 + 0 x 16 0 = 2640 (десяткове).

Отже, ми можемо закодувати своє положення як p 0 x 13 63 + p 1 x 13 62 + ... + p 63 x 13 0, де p i являє собою вміст квадрата i .

2 256 дорівнює приблизно 1,16e77. 13 64 дорівнює приблизно 1,96e71, що вимагає 237 біт місця для зберігання. Ця економія лише 7,5% призводить до суттєво збільшених витрат на маніпуляції.

Кодування з змінною базою

На юридичних дошках певні фігури не можуть з'являтися на певних квадратах. Наприклад, пішаки не можуть траплятись у першому чи восьмому рядах, зменшуючи можливості для цих квадратів до 11. Це зменшує можливі дошки до 11 16 x 13 48 = 1,35e70 (приблизно), що вимагає 233 біт місця для зберігання.

Насправді кодування та декодування таких значень до і з десяткової (або двійкової) є дещо складнішим, але це може бути зроблено надійно, і це залишається як вправа для читача.

Алфавіти змінної ширини

Попередні два методи можна обидва описати як алфавітне кодування з фіксованою шириною . Кожен з 11, 13 або 16 членів алфавіту замінюється іншим значенням. Кожен «символ» має однакову ширину, але ефективність можна покращити, якщо врахувати, що кожен символ не є однаково ймовірним.

азбука Морзе

Розглянемо азбуку Морзе (на фото вище). Символи у повідомленні кодуються як послідовність тире та крапок. Ці риски та крапки передаються по радіо (як правило) з паузою між ними, щоб обмежити їх.

Зверніть увагу, що буква E ( найпоширеніша буква в англійській мові ) - це одна крапка, найкоротша можлива послідовність, тоді як Z (найменш часта) - це дві риски та два звукові сигнали.

Така схема може суттєво зменшити розмір очікуваного повідомлення, але за рахунок збільшення розміру випадкової послідовності символів.

Слід зазначити, що азбука Морзе має ще одну вбудовану функцію: тире дорівнює трьом крапкам, тому наведений вище код створюється з урахуванням цього, щоб мінімізувати використання тире. Оскільки 1 і 0 (наші будівельні блоки) не мають цієї проблеми, це не функція, яку нам потрібно повторити.

Нарешті, у азбуці Морзе є два типи відпочинку. Короткий відпочинок (довжина крапки) використовується для розрізнення крапок і тире. Більший проміжок (довжина тире) використовується для розмежування символів.

То як це стосується нашої проблеми?

Кодування Хаффмана

Існує алгоритм роботи з кодами змінної довжини, який називається кодуванням Хаффмана . Кодування Хаффмана створює заміну коду змінної довжини, як правило, використовує очікувану частоту символів для призначення коротших значень загальнішим символам.

Дерево коду Хаффмана

У наведеному вище дереві буква E кодується як 000 (або ліворуч-ліворуч-ліворуч), а S дорівнює 1011. Повинно бути зрозуміло, що ця схема кодування однозначна .

Це важлива відмінність від азбуки Морзе. Код Морзе має роздільник символів, тому він може виконувати неоднозначну заміну в іншому випадку (наприклад, 4 крапки можуть бути H або 2 Is), але ми маємо лише 1 і 0, тому замість цього ми обираємо однозначну заміну.

Нижче наведено просту реалізацію:

private static class Node {
  private final Node left;
  private final Node right;
  private final String label;
  private final int weight;

  private Node(String label, int weight) {
    this.left = null;
    this.right = null;
    this.label = label;
    this.weight = weight;
  }

  public Node(Node left, Node right) {
    this.left = left;
    this.right = right;
    label = "";
    weight = left.weight + right.weight;
  }

  public boolean isLeaf() { return left == null && right == null; }

  public Node getLeft() { return left; }

  public Node getRight() { return right; }

  public String getLabel() { return label; }

  public int getWeight() { return weight; }
}

зі статичними даними:

private final static List<string> COLOURS;
private final static Map<string, integer> WEIGHTS;

static {
  List<string> list = new ArrayList<string>();
  list.add("White");
  list.add("Black");
  COLOURS = Collections.unmodifiableList(list);
  Map<string, integer> map = new HashMap<string, integer>();
  for (String colour : COLOURS) {
    map.put(colour + " " + "King", 1);
    map.put(colour + " " + "Queen";, 1);
    map.put(colour + " " + "Rook", 2);
    map.put(colour + " " + "Knight", 2);
    map.put(colour + " " + "Bishop";, 2);
    map.put(colour + " " + "Pawn", 8);
  }
  map.put("Empty", 32);
  WEIGHTS = Collections.unmodifiableMap(map);
}

і:

private static class WeightComparator implements Comparator<node> {
  @Override
  public int compare(Node o1, Node o2) {
    if (o1.getWeight() == o2.getWeight()) {
      return 0;
    } else {
      return o1.getWeight() < o2.getWeight() ? -1 : 1;
    }
  }
}

private static class PathComparator implements Comparator<string> {
  @Override
  public int compare(String o1, String o2) {
    if (o1 == null) {
      return o2 == null ? 0 : -1;
    } else if (o2 == null) {
      return 1;
    } else {
      int length1 = o1.length();
      int length2 = o2.length();
      if (length1 == length2) {
        return o1.compareTo(o2);
      } else {
        return length1 < length2 ? -1 : 1;
      }
    }
  }
}

public static void main(String args[]) {
  PriorityQueue<node> queue = new PriorityQueue<node>(WEIGHTS.size(),
      new WeightComparator());
  for (Map.Entry<string, integer> entry : WEIGHTS.entrySet()) {
    queue.add(new Node(entry.getKey(), entry.getValue()));
  }
  while (queue.size() > 1) {
    Node first = queue.poll();
    Node second = queue.poll();
    queue.add(new Node(first, second));
  }
  Map<string, node> nodes = new TreeMap<string, node>(new PathComparator());
  addLeaves(nodes, queue.peek(), &quot;&quot;);
  for (Map.Entry<string, node> entry : nodes.entrySet()) {
    System.out.printf("%s %s%n", entry.getKey(), entry.getValue().getLabel());
  }
}

public static void addLeaves(Map<string, node> nodes, Node node, String prefix) {
  if (node != null) {
    addLeaves(nodes, node.getLeft(), prefix + "0");
    addLeaves(nodes, node.getRight(), prefix + "1");
    if (node.isLeaf()) {
      nodes.put(prefix, node);
    }
  }
}

Одним з можливих результатів є:

         White    Black
Empty          0 
Pawn       110      100
Rook     11111    11110
Knight   10110    10101
Bishop   10100    11100
Queen   111010   111011
King    101110   101111

Для початкової позиції це дорівнює 32 x 1 + 16 x 3 + 12 x 5 + 4 x 6 = 164 біта.

Державна різниця

Іншим можливим підходом є поєднання найпершого підходу з кодуванням Хаффмана. Це базується на припущенні, що більшість очікуваних шахових дощок (а не випадково створених) частіше за все, принаймні частково, нагадують вихідну позицію.

Отже, що ви робите, це XOR - поточна 256-бітна позиція плати з 256-бітовою вихідною позицією, а потім кодуйте це (використовуючи кодування Хаффмана або, скажімо, якийсь метод кодування довжини циклу ). Очевидно, що це буде дуже ефективно для початку (64 0s, ймовірно, відповідає 64 бітам), але збільшення обсягу пам’яті потрібно в міру просування гри.

Позиція шматка

Як вже згадувалося, інший спосіб атаки на цю проблему полягає в тому, щоб замість цього зберігати позицію кожної фігури, яку має гравець. Це особливо добре працює з позиціями в кінцевій грі, де більшість квадратів будуть порожніми (але в підході кодування Хаффмана порожні квадрати в будь-якому випадку використовують лише 1 біт).

Кожна сторона матиме короля та 0-15 інших фігур. Через просування точний склад цих фігур може змінюватися настільки, що ви не можете припустити, що цифри на основі вихідних позицій є максимумами.

Логічний спосіб розділити це - зберегти Позицію, що складається з двох Сторін (Білої та Чорної). Кожна сторона має:

  • Король: 6 біт для місця;
  • Має пішаків: 1 (так), 0 (ні);
  • Якщо так, кількість пішаків: 3 біти (0-7 + 1 = 1-8);
  • Якщо так, місце кожному пішаку закодовано: 45 біт (див. Нижче);
  • Кількість не пішаків: 4 біти (0-15);
  • Для кожної фігури: тип (2 біти для ферзя, ладді, лицаря, єпископа) та місце розташування (6 біт)

Що стосується місця розташування пішаків, то вони можуть бути лише на 48 можливих квадратах (а не на 64, як інші). Таким чином, краще не витрачати зайві 16 значень, які використовували б 6 біт на пішака. Отже, якщо у вас 8 пішаків, то є 48 8 можливостей, що дорівнює 281779280429.056. Вам потрібно 45 біт, щоб закодувати стільки значень.

Це 105 біт на сторону або 210 біт загалом. Початкове положення - це найгірший випадок для цього методу, але він буде значно кращим, якщо ви видалите шматочки.

Слід зазначити, що існує менше 48 8 можливостей, оскільки пішаки не можуть знаходитись на одному квадраті Перший має 48 можливостей, другий 47 тощо. 48 x 47 x… x 41 = 1,52e13 = 44 біти.

Ви можете додатково поліпшити це, усунувши квадрати, зайняті іншими частинами (включаючи іншу сторону), щоб ви могли спочатку розмістити білих непішаків, потім чорних непішаків, потім білих пішаків і, нарешті, чорних пішаків. У початковій позиції це зменшує вимоги до зберігання до 44 біт для білого та 42 біт для чорного.

Комбіновані підходи

Інша можлива оптимізація полягає в тому, що кожен із цих підходів має свої сильні та слабкі сторони. Можна, скажімо, вибрати найкращий 4, а потім закодувати селектор схеми в перші два біти, а потім сховище для конкретної схеми після цього.

З такими незначними накладними витратами це, безумовно, буде найкращим підходом.

Держава гри

Я повертаюся до проблеми зберігання гри, а не позиції . Через триразове повторення нам доводиться зберігати список ходів, що відбулися до цього моменту.

Анотації

Одне, що вам потрібно визначити, це ви просто зберігаєте список ходів або коментуєте гру? Шахові ігри часто коментуються, наприклад:

  1. Bb5 !! Nc4?

Ход білих позначений двома знаками оклику як блискучий, тоді як рух Чорного розглядається як помилка. Див. Розділ пунктуації .

Крім того, вам також може знадобитися зберігати вільний текст, як описано ходи.

Я припускаю, що ходів достатньо, тому не буде жодних анотацій.

Алгебраїчні позначення

Ми могли б просто зберегти тут текст переміщення (“e4”, “Bxb5” тощо). Включаючи завершальний байт, ви переглядаєте приблизно 6 байт (48 біт) за хід (найгірший випадок). Це не особливо ефективно.

Друге, що потрібно спробувати - це зберегти початкове місце (6 біт) і кінцеве розташування (6 біт) так 12 біт за хід. Це значно краще.

В якості альтернативи ми можемо визначити всі легальні кроки з поточної позиції передбачуваним та детермінованим способом та станом, який ми вибрали. Потім це повертається до згаданого вище кодування змінної. Білі та чорні мають по 20 можливих ходів на першому ході, більше на другому тощо.

Висновок

На це питання немає абсолютно правильної відповіді. Існує багато можливих підходів, серед яких вищезазначене лише декілька.

Мені подобається в цій та подібних проблемах те, що вона вимагає здібностей, важливих для будь-якого програміста, таких як розгляд шаблону використання, точне визначення вимог та роздуми про кутові випадки.

Позиції в шахах, зроблені як скріншоти з Chess Position Trainer .


3
і gzip результат згодом (якщо заголовки не збільшать результат); ^)
Жаба

Вам не потрібно буде подвоювати пробіл для позначення чорного чи білого?
Даніель Елліотт, 02

5
Хороший пост. Невелике виправлення: рокіровка вимагає 4 біти, по одному для кожного способу рокіровки (білий і чорний, королівський і ферзячий), оскільки граки могли рухатися, а потім також рухатися назад. Дещо важливіше: ви, мабуть, повинні вказати, чий це рух. =)
А. Рекс,

9
Що стосується підвищення в лицарі, я це робив один раз. Дійсно дика ситуація - він був одним кроком від спарювання мене, я не міг цього зупинити. Він проігнорував мою пішака, тому що, хоча це сприятиме, це буде на один хід пізно. Я хотів би мати свою камеру, коли замість цього зробив лицарем і злучив його!
Loren Pechtel

2
Я здивований, що у вашій статті не згадується [FEN] [1], який стосується рокінгів, доступності пасажирів тощо [1] en.wikipedia.org/wiki/FEN
Росс,

48

Найкраще просто зберігати шахові партії в зручному для читання стандартному форматі.

Portable Game Notation передбачає стандартну стартову позицію (хоча не повинен ) і просто перераховує кроки, по черзі. Компактний, зручний для читання стандартний формат.

Напр

[Event "F/S Return Match"]
[Site "Belgrade, Serbia Yugoslavia|JUG"]
[Date "1992.11.04"]
[Round "29"]
[White "Fischer, Robert J."]
[Black "Spassky, Boris V."]
[Result "1/2-1/2"]

1. e4 e5 2. Nf3 Nc6 3. Bb5 {This opening is called the Ruy Lopez.} 3... a6
4. Ba4 Nf6 5. O-O Be7 6. Re1 b5 7. Bb3 d6 8. c3 O-O 9. h3 Nb8  10. d4 Nbd7
11. c4 c6 12. cxb5 axb5 13. Nc3 Bb7 14. Bg5 b4 15. Nb1 h6 16. Bh4 c5 17. dxe5
Nxe4 18. Bxe7 Qxe7 19. exd6 Qf6 20. Nbd2 Nxd6 21. Nc4 Nxc4 22. Bxc4 Nb6
23. Ne5 Rae8 24. Bxf7+ Rxf7 25. Nxf7 Rxe1+ 26. Qxe1 Kxf7 27. Qe3 Qg5 28. Qxg5
hxg5 29. b3 Ke6 30. a3 Kd6 31. axb4 cxb4 32. Ra5 Nd5 33. f3 Bc8 34. Kf2 Bf5
35. Ra7 g6 36. Ra6+ Kc5 37. Ke1 Nf4 38. g3 Nxh3 39. Kd2 Kb5 40. Rd6 Kc5 41. Ra6
Nf2 42. g4 Bd3 43. Re6 1/2-1/2

Якщо ви хочете зробити його меншим, просто застібніть його на блискавку . Робота виконана!


23
На мій захист проти 2-х голосів, яких отримав: 1) Він робить те, що ти хочеш 2) Він проходить тест thedailywtf.com/articles/riddle-me-an-interview.aspx : "... деякі люди, які можуть вирішити ці загадки - це саме ті люди, яких ви не хочете програмувати. Чи хотіли б ви попрацювати з хлопцем, який будує вагу водотоннажності / баржу, рулить таксі 747 до доків, а потім зважує джембо-джет, використовуючи це, замість того, щоб просто зателефонувати Boeing? " Ви не наймаєте когось, хто вигадує вам випадкове кодування на співбесіді, тому що він буде робити це також у своєму коді.
Роб Грант 02

1
Ну, якщо я спеціально прошу їх вирішити проблему, щоб отримати техніку вирішення проблем, то ви можете припустити, що я розкрию інші речі іншими питаннями ...
Ендрю Роллінгс

7
@reinier: Я не кажу, що абсолютно не знаю, що стосується проблем із щільністю інформації (ви неправильно діагностували мою відповідь як визнання некомпетентності). Звичайно, ви хочете найняти людину, яка кодує існуючий стандарт зберігання даних, і яка визнає, що використання відповідних існуючих інструментів, а не прокручування власних, може бути гарною ідеєю - "Ми винайшли The Wheel 2.0! Тепер це навіть кругліше!" Ви точно не хочете наймати людину, яка химерно вважає, що використання бібліотечних функцій є ознакою слабкості.
Роб Грант 02

18
Це абсолютно моя перша відповідь на це питання в інтерв’ю. Ви хочете показати, що ваш перший інстинкт - це пошук готового рішення. Якщо інтерв'юер скаже вам, що вони хочуть почути, що ви можете придумати самостійно, тоді ви можете скористатися рішенням, яке допоможе вам розібратися.
Білл Ящірка

2
Я з Робертом у цьому - існуюче рішення є практичним, зручним для читання та досить компактним. Усі це ОСНОВНІ подвиги порівняно із спеціальним супер упакованим рішенням зі складними алгоритмами їх декодування. Якщо мова йде про співбесіду, я б точно врахував і практичний аспект! Ви були б здивовані, скільки разів справді розумні люди придумували гіперскладні непрактичні рішення. Зазвичай це пояснюється тим, що вони можуть впоратися зі складністю у своїй голові, але тоді - а як щодо нас інших ...
MaR

15

Чудова головоломка!

Я бачу, що більшість людей зберігають позицію кожного твору. Як щодо більш простого підходу та збереження вмісту кожного квадрата ? Це автоматично подбає про просування та захоплені фігури.

І це дозволяє кодування Хаффмана . Насправді початкова частота фігур на дошці для цього майже ідеальна: половина квадратів порожня, половина квадратів, що залишилися, - пішаки тощо.

Враховуючи частоту кожного шматка, я побудував дерево Хаффмана на папері, яке я тут повторювати не буду. Результат, де cозначає колір (білий = 0, чорний = 1):

  • 0 для порожніх квадратів
  • 1c0 для пішака
  • 1c100 для ладді
  • 1c101 для лицаря
  • 1c110 для єпископа
  • 1c1110 для ферзя
  • 1c1111 для короля

Для всієї дошки у вихідній ситуації ми маємо

  • порожні квадрати: 32 * 1 біт = 32 біти
  • пішаки: 16 * 3 біти = 48 біт
  • граки / лицарі / єпископи: 12 * 5 біт = 60 біт
  • дами / королі: 4 * 6 біт = 24 біта

Разом: 164 біти для початкового стану плати. Значно менше, ніж 235 біт відповіді, яка на даний момент отримала найбільше голосів. І вона буде зменшуватися лише в міру просування гри (крім після підвищення).

Я дивився лише на положення фігур на дошці; додатковий стан (чия черга, хто в ролі, перехожий, повторювані ходи тощо) доведеться кодувати окремо. Можливо, ще максимум 16 біт, тобто 180 біт для всього стану гри. Можливі оптимізації:

  • Залишаючи рідкісні фігури та зберігаючи їх положення окремо. Але це не допоможе ... Заміна короля та ферзя на порожній квадрат економить 5 бітів, саме тих 5 бітів, які вам потрібні для кодування їхньої позиції іншим способом.
  • "Жодні пішаки на задньому ряду" не можуть бути легко закодовані, використовуючи іншу таблицю Хаффмана для задніх рядків, але я сумніваюся, що це дуже допомагає. Ви, мабуть, все-таки потрапили б до того самого дерева Хаффмана.
  • "Один білий, один чорний єпископ" може бути закодований шляхом введення додаткових символів, у яких немає cбіта, які потім можна вивести з квадрата, на якому знаходиться єпископ. (Пішаки, яких підвищують до єпископів, порушують цю схему ...)
  • Повторення порожніх квадратів можна кодувати по довжині циклу, вводячи додаткові символи, скажімо, "2 порожні квадрати в ряд" і "4 порожні квадрати в ряд". Але оцінити частоту таких випадків не так просто, і якщо ви помилитеся, це швидше зашкодить, ніж допоможе.

Жодні пішаки в банківських рядах не дозволяють трохи заощадити - ви можете вирізати біт №3 з усіх інших шаблонів. Таким чином ви заощадите один біт за штуку насправді на банківському рангу.
Loren Pechtel

2
Ви можете зробити окреме дерево Хаффмана для кожного з 64 квадратів, оскільки деякі, швидше за все, мають деякі фігури частіше за інших.
Клавдіу

9

Насправді великий підхід до таблиці пошуку

Позиція - 18 байт
Орієнтовна кількість легальних позицій - 10 43
Просто перелічіть їх усі, і позиція може зберігатися лише 143 бітами. Ще 1 біт потрібен, щоб вказати, на якій стороні грати далі

Звичайно, перерахування не є практичним, але це показує, що потрібно принаймні 144 біти.

Ходи - 1 байт
Зазвичай на кожну позицію припадає близько 30-40 легальних ходів, але їх число може досягати 218. Перелічимо всі легальні ходи для кожної позиції. Тепер кожен хід можна закодувати в один байт.

У нас ще є достатньо місця для спеціальних ходів, таких як 0xFF, які представляють відставку.


3
Прямо до суті вимоги "найефективніший у космосі спосіб, яким ви можете придумати, щоб кодувати стан гри в шахи" - Ніщо не є кращим, щоб роздушити щось, ніж словник, і це включає муху.
Ендрю

1
Я знайшов цікаве посилання на те, скільки часу знадобиться для створення такого словника :) ioannis.virtualcomposer2000.com/math/EveryChess.html
Ендрю

Оцінка Шеннонса трохи застаріла :-) Він не включав ані підвищення, ані захоплення, що збільшує кількість на чималу суму. Верхня межа 5x10 ^ 52 була дана Віктором
Аллісом

Звичайно, при кодуванні змінної довжини лише середнє значення становить щонайменше 10 ^ 43? Кодування, упереджене до більшої кількості позицій, повинно це зменшити, особливо оскільки багато позицій неможливі.
Phil H

Посилання EveryChess тепер "продається", посилання archive.org: web.archive.org/web/20120303094654/http://…
oPless

4

Додав би інтересу оптимізувати середній розмір справи для типових ігор, в які грають люди, замість найгіршого випадку. (У постановці проблеми не сказано, яку; більшість відповідей передбачають найгірший випадок.)

Для послідовності ходів, майте хороший шаховий двигун, який генерує ходи з кожної позиції; він створить список k можливих ходів, упорядкованих за рейтингом їх якості. Люди, як правило, вибирають хороші ходи частіше, ніж випадкові, тому нам потрібно вивчити картографування з кожної позиції у списку на ймовірність того, що люди вибирають ход, який є "добрим". Використовуючи ці ймовірності (на основі корпусу ігор з якоїсь бази даних Інтернет-шахів), кодуйте ходи арифметичним кодуванням . (Дешифратор повинен використовувати той самий шаховий двигун та картографування.)

Для вихідної позиції підійде підхід ralu. Ми могли б уточнити це за допомогою арифметичного кодування і там, якби мав якийсь спосіб зважити вибір за ймовірністю - наприклад, шматочки часто з’являються у конфігураціях, що захищають один одного, а не випадково. Важче побачити простий спосіб включити ці знання. Одна ідея: замість цього повернутися до вищезазначеного кодування ходу, починаючи зі стандартного положення відкриття та знаходячи послідовність, яка закінчується на потрібній дошці. (Ви можете спробувати пошук A * з евристичною відстанню, що дорівнює сумі відстаней фігур від їх кінцевих позицій, або чогось у цьому напрямку.) Це обміняє деяку неефективність від надмірного визначення послідовності ходів проти ефективності від використання переваг гри в шахи знання.

Також складно підрахувати, скільки заощаджень це виграє для вас у середній складності, не збираючи статистичних даних з фактичного корпусу. Але відправна точка з усіма ходами однаково ймовірними, я думаю, вже б перевершила більшість пропозицій тут: арифметичне кодування не потребує цілочисельної кількості бітів за хід.


Комплексність для зберігання цієї інформації в пулі - O (n), перевірте мою відредаговану відповідь.
Luka Rahne

ralu, я не впевнений, що ти кажеш, але якщо ти маєш на увазі, що твоє представлення послідовності ходів використовує оптимальний простір у гіршому випадку, то я не суперечу цьому. Ідея тут полягає в тому, щоб скористатися одними кроками, які є більш імовірними, ніж інші.
Дарій Бекон

Все, що вам потрібно, щоб знайти позиції, які є більш привабливими, - це використовувати детермінований (і сильний) шаховий двигун, який сортує доступний хід у заданій позиції детермінованим способом.
Luka Rahne

4

Атакуючи підзадачу кодування кроків після кодування початкової позиції. Підхід полягає у створенні "пов'язаного списку" кроків.

Кожен крок у грі кодується як пара "стара позиція-> нова позиція". Ви знаєте початкову позицію на початку гри в шахи; пройшовши пов'язаний список кроків, ви зможете перейти до стану після переміщення X.

Для кодування кожного кроку вам потрібно 64 значення для кодування початкової позиції (6 бітів для 64 квадратів на платі - 8x8 квадратів) та 6 бітів для кінцевої позиції. 16 біт за 1 хід кожної сторони.

Тоді кількість місця, яке займе кодування даної гри, пропорційна кількості ходів:

10 x (кількість білих ходів + кількість чорних ходів) біт.

ОНОВЛЕННЯ: потенційне ускладнення з висунутими пішаками. Потрібно мати можливість вказати, до чого просувається пішак - можуть знадобитися спеціальні біти (для цього буде використаний сірий код для економії місця, оскільки просування пішака надзвичайно рідко).

ОНОВЛЕННЯ 2: Вам не потрібно кодувати повні координати кінцевої позиції. У більшості випадків фрагмент, який переміщується, може переміститися не більше ніж на X місць. Наприклад, пішак може мати максимум 3 варіанти переміщення в будь-якій точці. Розуміючи, що максимальна кількість ходів для кожного типу шматка, ми можемо економити біти на кодуванні "пункту призначення".

Pawn: 
   - 2 options for movement (e2e3 or e2e4) + 2 options for taking = 4 options to encode
   - 12 options for promotions - 4 promotions (knight, biship, rook, queen) times 3 squares (because you can take a piece on the last row and promote the pawn at the same time)
   - Total of 16 options, 4 bits
Knight: 8 options, 3 bits
Bishop: 4 bits
Rook: 4 bits
King: 3 bits
Queen: 5 bits

Отже, просторова складність за хід чорного чи білого стає

6 біт для початкової позиції + (змінна кількість бітів залежно від типу речі, що переміщується).


Щойно оновлене, я мав на увазі 128 комбінацій - явно менше 128 біт :) :)
Алекс Вайнштейн 02

1
Ігровий стан - це не те саме, що рухатись. Будь-яке дане положення можна уявити вершиною або вузлом, а юридичний хід - направленим ребром або стрілкою, утворюючи (спрямований ациклічний) графік.
Кудлата жаба

Я не впевнений, чому негативні голоси - я б хотів почути думку людей щодо оновленої ідеї.
Алекс Вайнштейн,

1
Це не впливає на ваші міркування, але крихітна виправлення: пішак може мати чотири ходи, не включаючи підвищення, або 12 ходів, включаючи підвищення. Приклад пішака на e2: e3, e4, exd3, exf3. Приклад пішака на e7: e8Q, e8N, e8R, e8B, exd8Q, exd8N, exd8R, exd8B, exf8Q, exf8N, exf8R, exf8B.
А. Рекс,

1
Одна незначна проблема - 5 бітів кодують лише 32 значення. Щоб вказати будь-який квадрат на дошці, вам потрібно 6 біт.
Кріс Додд,

4

Я побачив це запитання вчора ввечері, і це мене заінтригувало, тому я сидів у ліжку, придумуючи рішення. Моя остаточна відповідь насправді схожа на int3.

Основне рішення

Якщо припустити стандартну гру в шахи та не кодувати правила (як завжди білий завжди йде першим), тоді ви зможете значно заощадити, закодувавши лише ходи, зроблені кожною фігурою.

Всього є 32 фігури, але під час кожного ходу ви знаєте, який колір рухається, тому є лише 16 квадратів, про які слід турбуватися, тобто 4 біти, для яких фіг рухається цей хід.

Кожен фрагмент має лише обмежений хід, який ви певним чином перелічили.

  • Пішак: 4 варіанти, 2 біти (1 крок вперед, 2 кроки вперед, 1 кожна діагональ)
  • Ладья: 14 варіантів, 4 біти (максимум 7 у кожному напрямку)
  • Єпископ: 13 варіантів, 4 біти (якщо у вас по одній діагоналі 7, у іншій - лише 6)
  • Лицар: 8 варіантів, 3 біти
  • Королева: 27 варіантів, 5 біт (Ладья + Бішоп)
  • Кінг: 9 варіантів, 4 біти (8 кроків в один крок, плюс варіант рокіровки)

Для просування є 4 штуки на вибір (Ладья, Єпископ, Лицар, Королева), тому на цьому ході ми додамо 2 біти, щоб вказати це. Я думаю, що всі інші правила охоплюються автоматично (наприклад, en passant).

Подальші оптимізації

По-перше, після того, як було захоплено 8 фрагментів одного кольору, ви можете зменшити фрагмент кодування до 3 бітів, потім 2 біти для 4 фрагментів тощо.

Основною оптимізацією є перерахування лише можливих ходів у кожній точці гри. Припустимо, що ми зберігаємо ходи Пішака як {00, 01, 10, 11}1 крок вперед, 2 кроки вперед, діагональ ліворуч і діагональ праворуч відповідно. Якщо деякі ходи неможливі, ми можемо вилучити їх із кодування для цього ходу.

Ми знаємо ігровий стан на кожному етапі (від слідування за всіма ходами), тому, прочитавши, який фрагмент буде рухатися, ми завжди можемо визначити, скільки бітів нам потрібно прочитати. Якщо ми усвідомлюємо, що в цей момент пішак рухається лише по діагоналі вправо або рухається вперед, ми знаємо, що читаємо лише 1 біт.

Коротше кажучи, перераховане сховище бітів, перераховане вище для кожного шматка, є лише максимальним . Майже кожен хід матиме менше варіантів і часто менше біт.


4

У кожній позиції отримуйте кількість усіх можливих ходів.

наступний хід генерується як

index_current_move =n % num_of_moves //this is best space efficiency
n=n/num_of_moves

очевидно найкраща космічна ефективність для зберігання випадково створеної гри і потребує приблизно 5 біт / хід в середньому, оскільки у вас є 30-40 можливих ходів. Збірка сховища - це просто генерація n у зворотному порядку.

Місце зберігання важче зламати через велику надмірність. (На борту може бути до 9 маток на одній ділянці, але в цьому випадку немає пішаків і єпископів, якщо на борту знаходяться протилежні кольорові квадрати), але загалом це схоже на зберігання комбінації одних і тих же фігур над рештою квадратиків.)

Редагувати:

Суть в збереженні ходів полягає в тому, щоб зберігати лише індекс ходу. Замість того, щоб зберігати Kc1-c2 і намагатися зменшити цю інформацію, нам слід додати лише індекс переміщення, згенерований детермінованим генератором переміщень (позиція)

При кожному русі ми додаємо інформацію про розмір

num_of_moves = get_number_of_possible_moves(postion) ;

в басейні, і це число не можна зменшити

генерування інформаційного пулу

n=n*num_of_moves+ index_current_move

додатково

Якщо в кінцевій позиції доступний лише один хід, збережіть як кількість раніше виконаних вимушених ходів. Приклад: якщо у вихідній позиції є 1 вимушений хід для кожної сторони (2 ходи), і ми хочемо зберегти це як гру в один хід, збережіть 1 у пулі n.

приклад зберігання в інформаційному пулі

Припустимо, що ми знаємо вихідні позиції і робимо 3 ходи.

У першому ході є 5 доступних ходів, і ми беремо індекс ходу 4. У другому ході є 6 доступних ходів, і ми приймаємо індекс позиції 3, а в 3 ході для цієї сторони доступно 7 ходів, і він вирішив вибрати індекс ходу 2.

Векторна форма; індекс = [4,3,2] n_moves = [5,6,7]

Ми кодуємо цю інформацію назад, тому n = 4 + 5 * (3 + 6 * (2)) = 79 (множення на 7 не потрібно)

Як розблокувати це? Спочатку ми маємо позицію, і ми з’ясовуємо, що доступно 5 ходів. Так

index=79%5=4
n=79/5=15; //no remainder

Ми беремо індекс ходу 4 і ще раз вивчаємо позицію, і з цього моменту ми з'ясовуємо, що можливих 6 ходів.

index=15%6=3
n=15/6=2

І ми беремо індекс ходу 3, який приводить нас до позиції з 7 можливими ходами.

index=2%7=2
n=2/7=0

Ми робимо останній хід індексом 2 і досягаємо остаточної позиції.

Як бачите, часова складність - O (n), а космічна складність - O (n). Редагувати: складність часу насправді O (n ^ 2), оскільки число, яке множитеся, збільшується, але не повинно виникнути проблем із зберіганням ігор до 10000 ходів.


рятувальна позиція

Можна зробити близько до оптимального.

Коли ми дізнаємося про інформацію та зберігаємо інформацію, дозвольте мені поговорити про неї більше. Загальна ідея полягає у зменшенні надмірності (про це я поговорю пізніше). Припустимо, що ніяких підвищень і не брали, тому є 8 пішаків, 2 граки, 2 лицарі, 2 єпископи, 1 король та 1 цариця на кожну сторону.

Що ми маємо врятувати: 1. положення кожного миру 2. можливості рокіровки 3. можливості ан-пассанта 4. сторона, яка має рух

Припустимо, що кожен шматок може стояти де завгодно, але не 2 штуки в одному місці. Кількість способів розташування 8 пішаків одного кольору на борту - це C (64/8) (біном), що становить 32 біти, потім 2 граки 2R-> C (56/2), 2B -> C (54/2) , 2N-> C (52/2), 1Q-> C (50/1), 1K -> C (49/1) і те саме для іншого сайту, але починаючи з 8P -> C (48/8) тощо .

Помноживши це разом для обох сайтів, отримаємо номер 4634726695587809641192045982323285670400000, що становить приблизно 142 біти, ми повинні додати 8 для одного можливого ан-пасанта (пішак-ан-пасант може бути в одному з 8 місць), 16 (4 біти) для обмежень рокінгів та один біт для сайту, який має переміщення. У підсумку ми отримуємо 142 + 3 + 4 + 1 = 150 біт

Але тепер давайте підемо на полювання за надмірністю на дошці з 32 фігурами і не братимемо.

  1. як чорні, так і білі пішаки знаходяться на одній колонці і один напроти одного. Кожна пішак звернена до іншої пішаки, що означає, що біла пішак може бути щонайбільше на 6-му рангу. Це дає нам 8 * C (6/2) замість C (64/8) * C (48/8), які зменшують інформацію на 56 біт.

  2. можливість закидання також зайва. Якщо граки не знаходяться на стартовому місці, немає можливості закидати жодну грач. Таким чином, ми можемо уявно додати 4 квадрати на борт, щоб отримати додаткову інформацію, якщо можлива рокіровка з цією ладдю, і видалити 4 ролі. Отже, замість C (56/2) * C (40/2) * 16 ми маємо C (58/2) * C (42/2), і ми втратили 3,76 біта (майже всі 4 біти)

  3. en-passant: Коли ми зберігаємо одну з 8 можливостей en passant, ми знаємо положення чорної пішака і зменшуємо інформаційну повторність (якщо це білий хід і є 3-й пішак en-passant, це означає, що чорна пішак знаходиться на c5, а біла пішак - або c2, c3 або c4), тому, згідно з C (6/2), ми маємо 3, і ми втратили 2,3 біта. Ми зменшуємо деяку надмірність, якщо зберігаємо з кількістю ан-пасанта також сторону, з якої це можна зробити (3 можливості-> ліворуч, праворуч, обидві), і ми знаємо можливість пішака, який може прийняти ан-пасанта. (наприклад, на прикладі превусі енсанса з чорним на c5, що може бути зліва, праворуч або в обох. якщо це на одному сайті, у нас є 2 * 3 (3 для зберігання псисибілітів і 2 можливі ходи для чорної пішака на 7-му чи 6-му рангу) ) на C (6/2), і ми зменшуємо на 1,3 біта, а якщо з обох сторін, зменшуємо на 4,2 біта. Таким чином, ми можемо зменшити на 2,3 + 1,3 = 3.

  4. bishops: bisops може бути лише на опоститних квадратах, це зменшує надмірність на 1 біт для кожного сайту.

Якщо підсумувати, нам потрібно 150-56-4-3,6-2 = 85 біт для зберігання шахової позиції, якщо не було взяти

І, мабуть, не набагато більше, якщо враховуються акції та акції (але я напишу про це пізніше, якщо хтось знайде цей довгий пост корисним)


Цікавий підхід. Додайте трохи детальніше :)
Ендрю Роллінгс 02

Я також додав підхід до збереження позиції. Я опустився до 85 біт на позиціях, хоч і не займаючи, і є гарною ілюстрацією, як далеко можна пройти. Я думаю, що найкраща ідея полягає в економії можливостей закидання, де майже всі 4 біти зайві.
Luka Rahne

3

Більшість людей кодували стан дошки, але щодо самих ходів. Ось короткий опис кодування.

Біт за штуку:

  • Ідентифікатор шматка: Макс. 4 біти для ідентифікації 16 штук на стороні. Білий / чорний можна зробити висновок. Визначте порядок на частинах. Оскільки кількість одиниць опускається нижче відповідних рівнів двох, використовуйте менше бітів, щоб описати решту шматочків.
  • Пішак: 3 можливості під час першого ходу, тому +2 біти (вперед на один або два квадрати, en passant.) Подальші ходи не дозволяють рухатися вперед на два, тому достатньо +1 біта. Підвищення можна зробити в процесі декодування, відмітивши, коли пішак досяг останнього рангу. Якщо відомо, що пішака підвищено, декодер очікує ще 2 біти, вказуючи на те, до якого з 4 основних фігур він підвищений.
  • Єпископ: +1 біт для діагоналі, що використовується, до +4 біт для відстані по діагоналі (16 можливостей). Декодер може зробити висновок про максимально можливу відстань, яку фрагмент може переміщати по цій діагоналі, тому, якщо це менша діагональ, використовуйте менше бітів.
  • Лицар: 8 можливих ходів, +3 біти
  • Грач: +1 біт для горизонтальної / вертикальної, +4 біти для відстані вздовж лінії.
  • Кінг: 8 можливих ходів, +3 біти. Позначте рокінг із «неможливим» ходом - оскільки рокінг можливий лише тоді, коли король знаходиться на першому рангу, закодуйте цей крок з вказівкою перемістити короля «назад» - тобто з дошки.
  • Королева: 8 можливих напрямків, + 3 біти. До +4 більше бітів для відстані по лінії / діагоналі (менше, якщо діагональ коротша, як у випадку єпископа)

Якщо припустити, що всі фігури знаходяться на дошці, це біти за хід: Пішак - 6 біт при першому ході, 5 згодом. 7, якщо підвищений. Єпископ: 9 біт (макс.), Лицар: 7, ладья: 9, король: 7, королева: 11 (макс.).


32 біти для ідентифікації фігури ??? Я думаю, ви мали на увазі 5 (32 штуки). Або 6, якщо вам потрібно закодувати стан "закінчення",
Жаба

Пішака також можна підвищити до грака, лицаря чи єпископа. Це звичайно, щоб уникнути патової ситуації або уникнути конфронтації.
Кобі

Це не впливає на ваші міркування, але крихітна виправлення: пішак може мати чотири ходи, не включаючи підвищення, або 12 ходів, включаючи підвищення. Приклад пішака на e2: e3, e4, exd3, exf3. Приклад пішака на e7: e8Q, e8N, e8R, e8B, exd8Q, exd8N, exd8R, exd8B, exf8Q, exf8N, exf8R, exf8B.
А. Рекс,

Можливо, я неправильно читаю, але пішак не може впоратися з першим ходом. Насправді вам не потрібні спеціальні позначення "en passant", оскільки це передбачено правилами гри - це буде просто діагональний хід. Перший хід - це один з 4 варіантів, а наступні ходи - до 3 варіантів.
DisgruntledGoat

3

Проблема полягає в тому, щоб дати кодування, яке є найбільш ефективним для типових шахових партій, або те, яке має найкоротший найгірший варіант кодування?

Для останнього найефективніший спосіб є також найбільш непрозорим: створити перелік усіх можливих пар (початкова дошка, юридична послідовність ходів), які, з позицією розіграшу тричі та повторенням і не більше ніж -п'ятдесят ходів з часу правил останньої пішави-переміщення-захоплення є рекурсивним. Тоді індекс позиції в цій кінцевій послідовності дає найкоротше найгірше кодування, але також і однаково довге кодування для типових випадків, і це, як я очікую, дуже дороге для обчислення. Передбачається, що найдовша шахова партія повинна перевищувати 5000 ходів, в кожному з яких гравцям зазвичай доступно 20-30 ходів (хоча менше, коли залишається мало фігур) - це дає приблизно 40000 біт, необхідних для цього кодування.

Ідея нумерації може бути застосована для отримання більш зручного рішення, як описано в пропозиції Хенка Холтермана щодо кодування ходів вище. Моя пропозиція: не мінімальна, але коротша, ніж наведені вище приклади, і розумна для реалізації:

  1. 64 біти, щоб вказати, які квадрати зайняті (матриця заповнення), плюс список фігур на кожному зайнятому квадраті (може мати 3 біти для пішаків та 4 біти для інших фігур): це дає 190 біт для початкової позиції. Оскільки на борту не може бути більше 32 штук, кодування матриці заповнюваності є зайвим, і тому може кодуватися щось на зразок загальних позицій дошки, скажімо, як 33 встановлені біти плюс індекс дошки зі списку загальних дощок.

  2. 1 біт, щоб сказати, хто робить перший хід

  3. Кодове переміщення відповідно до пропозиції Хенка: зазвичай 10 біт за пару біло-чорних ходів, хоча деякі ходи займають 0 біт, коли у гравця немає альтернативних ходів.

Це передбачає 490 біт для кодування типової гри на 30 ходів, і це буде досить ефективним поданням для типових ігор.

Зсередини, що кодують витяг тричі повторюваної позиції та не більше ніж п'ятдесят ходів з часу правил останнього переміщення пішака або захоплення: якщо ви кодуєте минуле переміщення назад до останнього руху пішака або захоплення, тоді ви мати достатньо інформації, щоб вирішити, чи застосовуються ці правила: немає потреби у всій історії гри.


Припустимо, що я б взяв великий вибір ігор і взяв усереднені результати.
Ендрю Роллінгс,

3

Позиція на дошці може бути визначена в 7 бітах (0-63, і 1 значення, що вказує, що її більше немає на дошці). Тож для кожної фігури на дошці вкажіть, де вона знаходиться.

32 штуки * 7 біт = 224 біта

РЕДАКТУВАТИ: як зазначив Кадріан ... ми також маємо справу про "підвищення пішака до королеви". Я пропоную додати додаткові біти в кінці, щоб вказати, яку пішаку підвищили.

Отже, для кожної пішаки, яку висунули, ми дотримуємося 224 біти з 5 бітами, які вказують на індекс пішака, якого просунули, і 11111, якщо це кінець списку.

Отже, мінімальний випадок (без підвищення) - 224 біти + 5 (без підвищення). Для кожної висунутої пішака додайте 5 біт.

EDIT: Як зазначає кошлатий жаба, нам потрібен ще один біт в кінці, щоб вказати, чия черга; ^)


і gzip результат згодом (якщо заголовки не збільшать результат); ^)
Жаба

Чи можете ви це покращити, враховуючи, що деякі шматочки ніколи не будуть знайдені на певних квадратних кольорах?
Ендрю Роллінгс,

andrew: насправді я не можу. Я забув взяти до уваги висунутого пішака в даму (як передбачає відповідь Кадріана). Отже, схоже, мені насправді знадобиться ще один зайвий шматочок
Жаба

Я бачу, як чорно-білих єпископів можна визначити разом. Хоча мені цікаво про лицарів ..
int3

1
Вам не вистачає рекламних акцій.
Loren Pechtel

2

Я б використовував кодування довжини циклу. Деякі шматки є унікальними (або існують лише двічі), тому я можу пропустити довжину після них. Як і клетус, мені потрібно 13 унікальних станів, тому я можу скористатися гризелем (4 біти) для кодування фрагмента. Тоді початкова дошка виглядатиме так:

White Rook, W. Knight, W. Bishop, W. Queen, W. King, W. Bishop, W. Knight, W. Rook,
W. Pawn, 8,
Empty, 16, Empty, 16
B. Pawn, 8,
B. Rook, B. Knight, B. Bishop, B. Queen, B. King, B. Bishop, B. Knight, B. Rook

що залишає у мене 8 + 2 + 4 + 2 + 8 гризків = 24 гризки = 96 біт. Я не можу кодувати 16 за допомогою гризуна, але оскільки "Порожній, 0" не має сенсу, я можу розглядати "0" як "16".

Якщо дошка порожня, але для однієї пішака у верхньому лівому куті я отримую "Пішак, 1, порожній, 16, порожній, 16, порожній 16, порожній, 15" = 10 гризків = 40 біт.

Найгірший випадок - це коли у мене порожній квадрат між кожним шматком. Але для кодування фрагмента мені потрібно лише 13 із 16 значень, тож, можливо, я можу використати інше, щоб сказати "Empty1". Тоді мені потрібно 64 гризки == 128 біт.

Для рухів мені потрібні 3 біти для фрагмента (колір дається тим, що білий завжди рухається першим) плюс 5 бітів (0..63) для нового положення = один байт на рух. Здебільшого мені не потрібна стара позиція, оскільки в межах діапазону буде лише одна штука. У непарному випадку я повинен використовувати один невикористаний код (мені просто потрібно 7 кодів для кодування фрагмента), а потім 5 бітів для старої та 5 бітів для нової позиції.

Це дозволяє мені закодувати рокіровку в 13 укусів (я можу перенести короля до Ладді, чого достатньо, щоб сказати, що я маю намір).

[РЕДАКТУВАТИ] Якщо ви дозволяєте розумний кодер, то мені потрібно 0 біт для початкового налаштування (оскільки воно не повинно кодуватися будь-яким чином: Це статично) плюс один байт за хід.

[EDIT2], що залишає пешку. Якщо пішак досягає останнього ряду, я можу перемістити його на місце, щоб сказати "перетворює", а потім додати 3 біти для фігури, яку він замінює (вам не потрібно використовувати даму; ви можете замінити пішака чим завгодно але король).


Розумний кодер не може припустити, що це ціла гра. Це може бути фрагмент гри. Я думаю, вам все-таки потрібно буде закодувати початкові позиції.
Ендрю Роллінгс,

Ну, у гіршому випадку мені потрібно або 128 біт, або, якщо гра все ще знаходиться на ранній стадії, я можу використати до 15 ходів, щоб привести її у вихідне положення = 120 біт.
Аарон Дігулла

Оскільки БУДЬ-який стан повинен бути закодований, а не лише початковий стан плати, вам також доведеться кодувати самі фігури. Отже, за штуку вам знадобиться принаймні 5 біт. Отже, це дасть вам принаймні 32 * 5 біт додатково
Жаба

@reiner: Ви помиляєтесь. Мені просто потрібно чотири біти за штуку / порожній квадрат. І я вже висвітлював це в першій частині своєї відповіді, тому жодних "32 * 5 біт зайвих". Для початкового стану мені потрібно 96 біт, а для будь-якого іншого стартового стану мені потрібно не більше 128 бітів.
Аарон Дігулла

Аарон: все-таки, як ви говорите, найгірший сценарій - це справді найгірший випадок у цьому кодуванні. Після 3 або 4 переміщень із стартової дошки для вашого кодування буде потрібно значно більше бітів, оскільки ви додаєте все більше і більше порожніх
Жаба

2

Так само, як вони кодують ігри на книгах і паперах: кожен твір має символ; оскільки це "легальна" гра, білі рухаються спочатку - немає необхідності кодувати білий або чорний окремо, просто підрахуйте кількість ходів, щоб визначити, хто перемістився. Крім того, кожен хід кодується як (фігура, кінцева позиція), де `` кінцева позиція '' зменшується до найменшої кількості символів, що дозволяє розпізнати двозначність (може бути нульовою). Тривалість гри визначає кількість ходів. Можна також кодувати час у хвилинах (з моменту останнього ходу) на кожному кроці.

Кодування фрагмента може бути виконано або шляхом присвоєння символу кожному (всього 32), або шляхом присвоєння символу класу, і використовувати кінцеву позицію, щоб зрозуміти, яку частину було переміщено. Наприклад, пішак має 6 можливих кінцевих позицій; але в середньому для нього доступна лише пара на кожному кроці. Отже, статистично кодування за кінцевою позицією може бути найкращим для цього сценарію.

Подібні кодування використовуються для шипованих поїздів в обчислювальній неврології (AER).

Недоліки: вам потрібно переграти всю гру, щоб отримати поточний стан і сформувати підмножину, подібно до обходу пов’язаного списку.


Це може бути лише фрагмент гри. Ви не можете припустити, що білі ходи першими.
Ендрю Роллінгс,

2

Є 64 можливі позиції дошки, тому вам потрібно 6 біт на позицію. Є 32 початкові фігури, тому наразі ми маємо 192 біти, де кожні 6 бітів вказують положення даного фрагмента. Ми можемо заздалегідь визначити порядок, в якому фігури відображаються, тому нам не потрібно говорити, який саме.

Що робити, якщо фішка вийшла з дошки? Що ж, ми можемо розмістити фігуру на тому самому місці, що і інша фігура, щоб вказати, що вона вибита з дошки, оскільки в іншому випадку це було б незаконно. Але ми також не знаємо, чи буде перша дошка на дошці чи ні. Отже, ми додаємо 5 біт, вказуючи, який шматок є першим (32 можливості = 5 біт, щоб представити перший шматок). Тоді ми можемо використовувати це місце для наступних фігур, які не знаходяться на дошці. Це підводить нас до 197 біт. На дошці повинен бути принаймні один шматок, так що це спрацює.

Тоді нам потрібен один біт, для якого зараз черга - доводить нас до 198 біт .

А як щодо просування пішаків? Ми можемо зробити це погано, додавши 3 біти на пішака, додавши 42 біти. Але тоді ми можемо помітити, що більшу частину пішаків не підвищують.

Отже, для кожної пішаки, яка знаходиться на дошці, біт «0» означає, що він не підвищений. Якщо пішака немає на дошці, тоді нам зовсім не потрібно трохи. Тоді ми можемо використовувати бітові рядки змінної довжини, для просування яких він має. Найчастіше це буде королева, тому "10" може означати КОРОЛЕВКУ. Тоді "110" означає грак, "1110" означає єпископ, а "1111" означає лицар.

Початковий стан прийме 198 + 16 = 214 біт , оскільки всі 16 пішаків знаходяться на дошці та не просуваються. Кінцева гра з двома підвищеними дамами-пішаками може зайняти щось на зразок 198 + 4 + 4, тобто 4 пішаки живими і не підвищеними, та 2 пішаки-дами, загалом 206 біт . Здається досить міцним!

===

Кодування Хаффмана, як зазначали інші, буде наступним кроком. Якщо ви спостерігаєте за кількома мільйонами ігор, то помітите, що кожен фрагмент набагато частіше знаходиться на певних квадратах. Наприклад, більшу частину часу пішаки тримаються по прямій лінії, або одна вліво / одна вправо. Король зазвичай тримається біля домашньої бази.

Тому розробіть схему кодування Хаффмана для кожної окремої позиції. Пішаки, швидше за все, візьмуть у середньому 3-4 біти замість 6. Король також повинен взяти кілька бітів.

Також у цю схему включіть "прийнятий" як можливу позицію. Це може дуже надійно впоратися і з рокіровкою - кожна грач і король матимуть додатковий стан "початкове положення, переміщення". Ви також можете кодувати en passant у пішаків таким чином - "вихідне положення, може en passant".

За достатньої кількості даних такий підхід повинен дати справді хороші результати.


2
Просто віднесіть вилучені фігури до тієї ж площі, що і король. Оскільки короля ніколи не можна усунути, це не буде двозначним
Джон Ла Рой,

Це хороший коментар :) Приємні аспекти цього рішення теж. Я не усвідомлював, що буде так важко вибрати переможця.
Ендрю Роллінгс,

2

Я спробував би використовувати кодування Хаффмана . Теорія, що лежить в основі цього, полягає в тому, що в кожній шаховій партії знайдуться фігури, які будуть багато рухатись, а деякі, які не рухаються багато або виключаються раніше. Якщо у вихідній позиції вже вилучено кілька фігур - тим краще. Те саме стосується квадратів - деякі квадрати бачать всі дії, а деякі не надто торкаються.

Таким чином, я мав би два столи Хаффмана - один для штук, інший для квадратів. Вони будуть генеруватися, дивлячись на фактичну гру. Я міг би мати один великий стіл на кожну пару квадрат-квадрат, але я думаю, що це було б досить неефективно, оскільки на тому самому квадраті знову не багато випадків того самого предмета.

Кожен шматок мав би присвоєний ідентифікатор. Оскільки існує 32 різні фігури, мені знадобиться всього 5 біт для ідентифікатора фігури. Ідентифікатори фігур не змінюються від гри до гри. Те саме стосується квадратних ідентифікаторів, для яких мені знадобилося б 6 бітів.

Дерева Хаффмана кодували б, записуючи кожен вузол під час їх обходу в порядку (тобто спочатку виводиться вузол, а потім його діти зліва направо). Для кожного вузла буде один біт, який вказує, чи це листок, чи вузол гілки. Якщо це листовий вузол, за ним підуть біти, що дають ідентифікатор.

Початкове положення буде просто задано низкою пар розташування деталей. Після цього на кожен хід буде одна пара фішок-розташування. Ви можете знайти кінець дескриптора початкової позиції (і початок дескриптора ходів), просто знайшовши перший фрагмент, який згадується двічі. Якщо пішака підвищать, буде 2 додаткових біта, що вказують, чим він стане, але ідентифікатор фігури не зміниться.

Щоб врахувати можливість підвищення пішака на початку гри, між деревами хафмана та даними також буде "таблиця просування". Спочатку буде 4 біти, що вказують, скільки пішаків модернізовано. Тоді для кожної пішака буде свій кодований Хафменом ідентифікатор та 2 біти, що вказують, чим він став.

Дерева Хаффмана будуть сформовані з урахуванням усіх даних (як початкової позиції, так і ходів) і таблиці просування. Хоча зазвичай таблиця акцій буде порожньою або матиме лише кілька записів.

Підсумовуючи це графічно:

<Game> := <Pieces huffman tree> <squares huffman tree> <promotion table> <initial position> (<moves> | <1 bit for next move - see Added 2 below>)

<Pieces huffman tree> := <pieces entry 1> <pieces entry 2> ... <pieces entry N>
<pieces entry> := "0" | "1" <5 bits with piece ID>

<squares huffman tree> := <squares entry 1> <squares entry 2> ... <squares entry N>
<Squares entry> := "0" | "1" <6 bits with square ID>

<promotion table> := <4 bits with count of promotions> <promotion 1> <promotion 2> ... <promotion N>
<promotion> := <huffman-encoded piece ID> <2 bits with what it becomes>

<initial position> := <position entry 1> <position entry 2> ... <position entry N>
<moves> := <position entry 1> <position entry 2> ... <position entry N>
<position entry> := <huffman-encoded piece ID> <huffman-encoded squre ID> (<2 bits specifying the upgrade - optional>)

Додано: Це все ще можна оптимізувати. Кожен твір має лише кілька юридичних кроків. Замість простого кодування цільового квадрата можна дати ідентифікатори на основі 0 для можливих ходів кожної фігури. Ті самі ідентифікатори будуть використовуватися повторно для кожної фігури, тому в цілому буде не більше 21 різних ідентифікаторів (дама може мати щонайбільше 21 різний можливий варіант переміщення). Помістіть це в таблицю Хафмана замість полів.

Однак це може спричинити труднощі у поданні вихідного стану. Можна створити серію ходів, щоб поставити кожну частину на своє місце. У цьому випадку потрібно було б якось позначити кінець початкового стану та початок ходів.

В якості альтернативи їх можна розмістити, використовуючи нестиснуті 6-бітові квадратні ідентифікатори.

Чи це може спричинити загальне зменшення розміру, я не знаю. Можливо, але варто трохи поекспериментувати.

Додано 2: Ще один особливий випадок. Якщо в ігровому стані НІХД ходів, стає важливим розрізнити, хто рухається наступним. Додайте ще один біт в кінці для цього. :)


2

[відредаговано після належного прочитання питання] Якщо ви вважаєте, що кожна правова позиція може бути досягнута з початкової позиції (що є можливим визначенням "юридичної"), тоді будь-яка позиція може бути виражена як послідовність ходів з самого початку. Фрагмент гри, що починається з нестандартної позиції, може бути виражений як послідовність ходів, необхідних для досягнення старту, перемикач для ввімкнення камери з наступними рухами.

Тож давайте назвемо початковий стан дошки єдиним бітом "0".

Рухи з будь-якої позиції можна перерахувати, нумеруючи квадрати і впорядковуючи ходи за (початок, кінець), при цьому звичайний стрибок на 2 квадрата вказує на закидання. Немає необхідності кодувати незаконні ходи, оскільки позиція дошки та правила завжди вже відомі. Прапор для увімкнення камери може бути виражений як спеціальний внутрішньосмуговий хід, або більш розумно як номер позаполосного переміщення.

Є 24 ходи відкриття для будь-якої сторони, які можуть поміститися в 5 біт кожен. Подальші ходи можуть вимагати більш-менш біт, але законних ходів завжди незліченно, тому ширина кожного ходу може щасливо зростати або розширюватися. Я не розраховував, але, думаю, 7-бітові позиції були б рідкістю.

Використовуючи цю систему, 100 ігор на половину ходу можуть бути закодовані приблизно в 500 бітів. Однак було б доцільно скористатися початковою книгою. Припустимо, він містить мільйон послідовностей. Нехай тоді початкове 0 вказує на початок зі стандартної дошки, а 1, за яким слідує 20-бітове число, вказує на початок з цієї послідовності відкриття. Ігри з дещо звичайними отворами можуть бути скорочені приблизно на 20 напівходів або на 100 біт.

Це не найбільше можливе стиснення, але (без початкової книги) його було б дуже легко здійснити, якщо у вас вже є шахова модель, яку передбачає питання.

Для подальшого стиснення ви хочете впорядковувати ходи за ймовірністю, а не у довільному порядку, та кодуйте ймовірні послідовності у меншій кількості бітів (використовуючи, наприклад, маркери Хаффмана, як люди згадували).


Початкове положення не обов'язково відомо. Це може бути фрагмент гри.
Ендрю Роллінгс,

@Andrew: так. моя помилка. Я відредагував, щоб врахувати фрагменти гри.
Douglas Bagnall

2

Якщо обчислювальний час не є проблемою, тоді ви можете використовувати детермінований генератор можливих позицій для призначення унікальних ідентифікаторів даній позиції.

З заданої позиції спочатку сформуйте кількість можливих позицій у детермінованій садибі, наприклад, починаючи знизу ліворуч, рухаючись угорі праворуч. Це визначає, скільки бітів вам знадобиться для наступного ходу, в деяких ситуаціях це може бути лише один. Тоді при здійсненні переміщення зберігайте лише унікальний ідентифікатор цього переміщення.

Правила підвищення та інші правила просто вважаються дійсними ходами, якщо вони обробляються детермінованим способом, наприклад, королеві, ладді, єпископу кожного графу як окремий хід.

Початкова позиція є найскладнішою і може генерувати близько 250 мільйонів можливих позицій (я думаю), що зажадає приблизно 28 біт плюс додатковий біт, щоб визначити, чий це хід.

Припускаючи, що ми знаємо, хто зараз (кожен поворот переходить з білого на чорний), детермінований генератор виглядатиме приблизно так:

for each row
    for each column
        add to list ( get list of possible moves( current piece, players turn) )

"отримати список можливих ходів" буде мати щось на зразок:

if current piece is not null 
    if current piece color is the same as the players turn
        switch( current piece type )
            king - return list of possible king moves( current piece )
            queen - return list of possible queen moves( current piece )
            rook - return list of possible rook moves( current piece )
            etc.

Якщо король знаходиться в чеку, тоді кожен "список можливих xxx ходів" повертає лише дійсні ходи, які змінюють ситуацію чека.


Це підле рішення ... тож ... у цьому випадку опишіть свій алгоритм генерації детермінованого числа.
Ендрю Роллінгс,

Я знайшов цікаве посилання про те, скільки часу знадобиться для генерації кожної позиції на шаховій дошці :) ioannis.virtualcomposer2000.com/math/EveryChess.html
Ендрю

2

Більшість відповідей не враховували триразове повторення. на жаль, для повторення у 3 рази ви повинні зберегти всі зіграні досі позиції ...

Питання вимагало, щоб ми зберігали в просторі ефективно, тому нам дійсно не потрібно зберігати позицію, поки ми можемо побудувати її зі списку ходів (за умови, що ми маємо стандартну вихідну позицію). Ми можемо оптимізувати PGN, і це все, що ми зробили. Нижче - проста схема.

На дошці є 64 квадрата, 64 = 2 ^ 6. Якщо ми зберігаємо лише початковий та кінцевий квадрат кожного ходу, який займе 12 біт (про підвищення буде розглянуто пізніше). Зверніть увагу, що ця схема вже охоплює гравця для переміщення, акцентації, захоплення фігури, закидання тощо; їх можна створити з простого відтворення списку переміщення.

для просування ми можемо зберегти окремий масив векторів, який би сказав: "при русі N просунути до Piece XYZ". ми можемо зберегти вектор (int, byte).

Також спокусливо оптимізувати (До, Від) вектор, оскільки багато з цих (До, Від) векторів неможливі в шахах. напр. там не буде переходу від e1 до d8 тощо. Але я не міг придумати жодної схеми. Будь-які подальші ідеї дуже вітаються.


2

Я довго про це думав (+ - 2 години). І очевидних відповідей немає.

Припускаючи:

  1. Ігнорування стану часу (гравець не використовував обмеження часу, тому може змусити до нічиєї, не граючи)
  2. Коли проводилась гра?!? Це важливо, тому що правила з часом змінювались (тому будемо вважати сучасну гру в подальшому пункті сучасною грою ...) Будь ласка, зверніться до правила мертвої пішака (наприклад, у Вікіпедії є дуже відома проблема, яка це показує), і якщо ви хочете щоб повернутися у минуле, удача, єпископ звик рухатися лише повільно, а раніше використовували кубики. Лол.

... отже, це сучасні сучасні правила. Спочатку незалежно від повторення та переміщення обмеження повторення.

-C 25 байт округлено (64b + 32 * 4b + 5b = 325b)

= 64 біти (щось / нічого) + 32 * 4 біти [1 біт = колір {чорний / з}} + 3 біт = тип фігури {Король, Дама, Єпископ, kNight, Ладья, Пішак, MovedPawn} NB: Переміщена пішак ... наприклад, якщо це була остання пішохідна пішак у попередньому ході, що вказує на те, що “en passant” здійсненний. ] + 5 біт для фактичного стану (хто черга, ан пасант, можливість грати чи ні з кожного боку)

Все йде нормально. Можливо, це можна покращити, але тоді враховуватимуть змінну довжину та просування !?

Тепер наступні правила застосовуються лише КОЛИ гравець подає заявку на нічию, це НЕ автоматично! Тож вважайте, що ці 90 ходів без захоплення чи руху пішака можливо, якщо жоден гравець не вимагає нічиєї! Це означає, що всі ходи повинні бути записані ... і доступні.

-D повторення позиції ... наприклад, стан борту, як зазначено вище (див. С) чи ні ... (див. Далі щодо правил ФІДЕ) -Е. лічильник необхідний ... Однак.

То як ви з цим справляєтесь? ... Ну насправді ніяк. Тому що жоден гравець може не захотіти малювати або усвідомлювати, що це сталося. Тепер на випадок, коли E може вистачити лічильника ... але тут є хитрість, і навіть читання правил FIDE (http://www.fide.com/component/handbook/?id=124&view=article) я не можу знайти відповідь ... а як щодо втрати здатності до граблів. Це повторення? Думаю, що ні, але тоді це розмита тема, про яку не йдеться, не з’ясовується.

Отже, є два правила, які є двома складними або невизначеними навіть для спроби кодування ... На ура.

Отже, єдиний спосіб по-справжньому закодувати гру - це записати все з самого початку ... що потім конфліктує (чи ні?) Із питанням про "стан дошки".

Сподіваюся, це допоможе ... не надто багато математики :-) Просто, щоб показати, що якесь питання не таке просте, занадто відкрите для інтерпретації чи попереднього знання, щоб бути правильним та ефективним. Не одного, кого я б розглянув для співбесіди, оскільки це відкриває занадто багато банок хробака.


2

Можливе покращення вихідної позиції у рішенні Yacoby

Жодна юридична позиція не має більше 16 частин кожного кольору. Кількість способів розмістити до 16 чорних та 16 білих фігур на 64 квадратах становить приблизно 3,63e27. Log2 (3.63e27) = 91.55. Це означає, що ви можете кодувати положення та колір усіх частин у 92 біти. Це менше, ніж 64 біти для позиції + до 32 бітів для кольору, які вимагає рішення Yacoby. Ви можете зберегти 4 біти в гіршому випадку за рахунок значної складності в кодуванні.

З іншого боку, це збільшує розмір для позицій, де бракує 5 і більше фігур. Ці позиції представляють лише <4% усіх позицій, але, мабуть, це більшість випадків, коли потрібно записати вихідну позицію, відмінну від початкової.

Це призводить до повного рішення

  1. Кодуйте положення та колір шматків відповідно до вищенаведеного методу. 92 біти .
  2. Щоб вказати тип кожної фігури, використовуйте код Хаффмана: пішак: '0', ладья: '100', лицар: '101', єпископ: '110', королева: '1110', король: '1111'. Для цього потрібно (16 * 1 + 12 * 3 + 4 * 4) = 68 біт для повного набору штук. Повна позиція борту може бути закодована в максимум 92 + 68 = 160 біт .
  3. Слід додати додатковий стан гри: поворот: 1 біт, можливий рокінг: 4 біти, можливий “en passant”: до 4 бітів (1 біт говорить про те, що це так, а 3 біти вказують, який саме). Початкове положення кодується в = 160 + 9 = 169 біт
  4. Для списку ходів перелічіть усі можливі ходи для даної позиції та збережіть позицію ходу в списку. Список ходів включає всі особливі випадки (рокіровка, ан-пасант та відставка). Використовуйте лише стільки бітів, скільки потрібно для збереження найвищого положення. У середньому він не повинен перевищувати 7 біт за хід (16 можливих фігур та 8 легальних ходів за фішку в середньому). У деяких випадках, коли переміщення змушене, для цього потрібно лише 1 біт (переміщення або звільнення).

1

На дошці 32 штуки. Кожна фігура має позицію (одна на 64 квадрати). Отже, вам потрібно лише 32 натуральних числа.

Я знаю, що 64 позиції займають 6 бітів, але я б цього не робив. Я б утримав останні біти для кількох прапорів (випав шматок, пішак королеви)


Вам не потрібно використовувати прапори для утримання стану. Можна припустити, що ваш кодер досить розумний, щоб "знати правила". Таким чином, якщо пішак раптом змінився на ферзя, це не обов'язково повинно бути позначене спеціально в кодуванні (якщо, я припускаю, гравець не вирішив підвищити).
Ендрю Роллінгс,

так, слід, оскільки ви не можете визначити за початковою позицією пішака, висунули пішака чи ні! Отже, це має бути закодовано у початковій установці
Жаба

Ах, але навіщо вам знати, якщо це вже було підвищено? Це просто шматок. У цьому випадку минулий стан не буде мати значення.
Ендрю Роллінгс,

Думаю, якщо пішак все ще є пішаком або був підвищений до ферзя, це навряд чи має значення для решти гри. Якщо ви не думаєте, я б хотів зіграти з вами
Жаба

@reinier: Він стверджує, що це не має значення, якщо поточна королева спочатку була королевою або спочатку пішаком.
А. Рекс,

1

відповідь cletus хороша, але він забув також закодувати, чия черга. Він є частиною поточного стану і необхідний, якщо ви використовуєте цей стан для керування алгоритмом пошуку (наприклад, похідна альфа-бета).

Я не шахіст, але я вважаю, що є ще один кутовий випадок: скільки ходів було повторено. Як тільки кожен гравець зробить один і той самий хід три рази, гра - нічия, ні? Якщо так, тоді вам потрібно буде зберегти цю інформацію у штаті, оскільки після третього повторення стан тепер термінальний.


йдучи цим маршрутом, вам також потрібно додати відіграний час для обох гравців, оскільки в реальній шаховій грі обидва гравці думають лише 1 або 2 години.
Жаба

2
Вам не потрібно кодувати правила у власне даних. Можна припустити, що сам кодер знає всі необхідні правила.
Ендрю Роллінгс,

Ах .. Я не розглядав час гри. Гарний дзвінок ... :)
Ендрю Роллінгс,

@Andrew Rollings: правило базується на державі, оскільки воно запускається лише тоді, коли виконується певна передумова. Відстеження цього стану передумови також є частиною ... ну, стану. :)
Кудлата жаба 02

Не має значення в даному випадку. При необхідності декодер може дослідити стан, щоб визначити переможця. Пам'ятайте, що кодер / декодер відповідає правилам. Єдине, що дійсно потрібно закодувати, це вибір гравця - все інше можна вважати відомим кодеру / декодеру.
Ендрю Роллінгс,

1

Як згадували кілька інших, ви могли б для кожного з 32 фігур зберігати, на якому квадраті вони перебувають, і якщо вони на дошці чи ні, це дає 32 * (log2 (64) + 1) = 224 біта.

Однак єпископи можуть займати лише чорні або білі квадрати, тому для них вам потрібні лише log2 (32) біти для позиції, які дають 28 * 7 + 4 * 6 = 220 біт.

І оскільки пішаки не починаються ззаду і можуть рухатись лише вперед, вони можуть бути лише на 56, то це обмеження повинно мати можливість зменшити кількість бітів, необхідних для пішаків.


єпископи теж можуть бути поза бортом, тому вам потрібен додатковий шматочок для них. Також ви забуваєте про пішаків, що висуваються, і про людину, яка повинна стартувати першою. Беручи все це до уваги, ви в основному закінчуєте моєю відповіддю; ^)
Жаба

6 бітів для єпископів - log2 (32) + 1 = 6, але це впевнене, складне питання, якщо врахувати всі деталі :)
Андреас Брінк,

Я думав у цьому напрямку, але це не допомагає. Подивіться на відповідь Томаса та змініть його кодування Хаффмана, щоб видалити поняття порожніх пробілів. Ви використовуєте 64 біти для зберігання матриці, квадрати якої зайняті, і ви вилучаєте по 1 біту з кожного кодування - таким чином точно відновлюючи ті самі 64 біти.
Loren Pechtel

1

Дошка має 64 квадрата і може бути представлена ​​64 бітами, що показують, порожній квадрат чи ні. Інформація про шматки нам потрібна лише в тому випадку, якщо в квадраті є фігура. Оскільки гравець + фігура бере 4 біти (як показано раніше), ми можемо отримати поточний стан у 64 + 4 * 32 = 192 біти. Киньте поточний хід, і у вас буде 193 біти.

Однак нам також потрібно закодувати юридичні кроки для кожного фрагмента. Спочатку ми обчислюємо кількість легальних ходів для кожної фігури і додаємо стільки бітів після ідентифікатора фігури повного квадрата. Я розрахував так:

Пішак: Вперед, перший поворот на два вперед, en passant * 2, просування = 7 біт. Ви можете поєднати перший поворот вперед і просування в один біт, оскільки вони не можуть відбуватися з однієї і тієї ж позиції, тому у вас 6. Грач: 7 вертикальних квадратів, 7 горизонтальних квадратів = 14 біт Найт: 8 квадратів = 8 біт Бішоп: 2 діагоналі * 7 = 14 біт Queen: 7 вертикальних, 7 горизонтальних, 7 діагональних, 7 діагональних = 28 біт King: 8 навколишніх квадратів

Це все ще означає, що вам потрібно буде зіставити цільові квадрати на основі поточної позиції, але це (має бути) простий розрахунок.

Оскільки у нас 16 пішаків, 4 граки / лицарі / єпископи і 2 королеви / королі, це 16 * 6 + 4 * 14 + 4 * 8 + 4 * 14 + 2 * 28 + 2 * 8 = ще 312 біт, приносячи ще загалом до 505 біт загалом.

Що стосується кількості бітів, необхідних для штуки для можливих ходів, можна додати деякі оптимізації, і кількість бітів, ймовірно, зменшилася, я просто використовував прості числа для роботи. Наприклад, для розсувних деталей ви можете зберігати, наскільки далеко вони можуть рухатися, але для цього потрібні додаткові розрахунки.

Коротше: короткі дані зберігайте лише тоді, коли зайнято квадрат, і зберігайте лише мінімальну кількість бітів для кожного фрагмента, щоб відображати його законні ходи.

EDIT1: Забув про рокінг та просування пішаків до будь-якого твору. Це може довести загальну кількість явних позицій до 557 ходів (ще 3 біти для пішаків, 2 для королів)


1

Кожна фігура може бути представлена ​​4 бітами (пішак королю, 6 типів), чорно-білий = 12 значень

Кожен квадрат на дошці може бути представлений 6 бітами (x координата, координата y).

Початкові позиції вимагають максимум 320 біт (32 штуки, 4 + 6 біт)

Кожен наступний хід може бути представлений 16 бітами (від позиції, до позиції, фігури).

Рокінг вимагає додаткових 16 біт, оскільки це подвійний хід.

Пішохідні пішаки можуть бути представлені одним із 4 запасних значень із 4 бітів.

Без детальної математики це починає економити простір після першого переміщення порівняно із збереженням 32 * 7 бітів (заздалегідь визначений масив частин) або 64 * 4 бітів (заздалегідь визначений квадрат)

Після 10 ходів з обох сторін максимальний необхідний простір становить 640 біт

... але знову ж таки, якщо ми ідентифікуємо кожну фігуру однозначно (5 біт) і додаємо шостий біт для позначення встановлених пішаків, тоді нам потрібен лише id-id + to-position для кожного ходу. Це змінює розрахунок на ...

Початкові позиції = максимум 384 біта (32 фігури, 6 + 6 бітів) Кожен хід = 12 біт (у позицію, ідентифікатор фігури)

Тоді після 10 ходів з кожної сторони максимальний необхідний простір становить 624 біта


Другий варіант має додаткову перевагу в тому, що пам'ять можна читати як 12-бітові записи, кожен запис = позиція та фрагмент. Перший рух кабіни визначається тим фактом, що деталь має попередній вхід.
Steve De Caux 02

на час між ходами додайте х бітів для лічильника до кожного запису. Для записів налаштування це буде встановлено на 0.
Стів Де Ко

Саме такий підхід я збирався виписати. Однією з оптимізацій є те, що для стандартних ігор вам зовсім не потрібно кодувати початкові позиції - достатньо одного біта в голові, який говорить "це стандартна гра". Крім того, рокіровка не вимагає подвійного ходу - оскільки рух рокіровки завжди очевидний, і існує лише один дійсний спосіб руху ладді, коли відбувається дана королівська половина рокіровки, це зайва інформація. Для просування можна просто використовувати 4 біти після того, як пішак переходить до останнього рядка, щоб вказати новий тип фігури, яким він стає.
kyoryu

Отже, для типової гри після 10 ходів ви знаходитесь на рівні 121 біта, не припускаючи жодних підвищення. Для нетипових ігор знадобиться 1 біт для прапора, шматки * 10 біт і ще один біт для позначення першого гравця. Крім того, для кожного ходу знадобиться лише 12 біт, оскільки фігура на даному квадраті є неявною з попередніх ходів у грі. Можливо, це менш ефективно, ніж деякі із запропонованих методів, але є досить чистим та досить ефективним для "стандартних" ігор.
kyoryu

@kyoro - Я не впевнений, що 12 біт за хід можна обіграти - використовуючи вашу ідею нуля для стандартного налаштування (я б все одно використовував 12 бітів, встановлених як нуль біна) - після 1000 ходів з кожного боку це 24012 біт 3002 байта (округлено) Навіть використовуючи якусь форму стиснення, вам потрібно обдурити, щоб перемогти це, оголосивши ваш словник чітко закодованим (або логічно вивідним, те саме)
Стів Де Ко

1

Як і Роберт Г., я, як правило, використовую PGN, оскільки він є стандартним і може використовуватися широким спектром інструментів.

Якщо, однак, я граю в шаховий ШІ, який знаходиться на далекому космічному зонді, і, отже, кожен біт дорогоцінний, це те, що я б зробив для ходів. Пізніше я перейду до кодування початкового стану.

Ходи не потребують запису стану; декодер може відстежувати стан, а також те, які дії є законними в будь-який момент. Усі кроки, які потрібно зафіксувати, - це те, яку з різних правових альтернатив обрано. Оскільки гравці чергуються, ходу не потрібно записувати колір гравця. Оскільки гравець може рухати лише власні кольорові фігури, першим вибором є те, яку фігуру гравець рухає (пізніше я повернусь до альтернативи, яка використовує інший вибір). Щонайбільше 16 штук, для цього потрібно не більше 4 біт. Коли гравець втрачає фігури, кількість варіантів зменшується. Крім того, певний ігровий стан може обмежити вибір фігур. Якщо король не може рухатися, не поставивши себе на перевірку, кількість варіантів зменшується на один. Якщо король стоїть на контролі, будь-яка фігура, яка не може вивести короля з-під контролю, не є життєздатним вибором.

Після того, як частина вказана, вона матиме лише певну кількість законних пунктів призначення. Точна кількість дуже залежить від компонування дошки та історії гри, але ми можемо визначити певні максимуми та очікувані значення. Для всіх, крім лицаря та під час закидання, шматок не може рухатися через інший шматок. Це буде великим джерелом обмежень переміщення, але складно визначити кількісно. Частина не може відійти від дошки, що також значною мірою обмежить кількість пунктів призначення.

Ми кодуємо пункт призначення більшості фрагментів, нумеруючи квадрати по лініях у такому порядку: W, NW, N, NE (чорна сторона - N). Лінія починається на найдальшій площі в заданому напрямку, до якого можна рухатись, і рухається до. Для необтяженого короля список ходів - W, E, NW, SE, N, S, NE, SW. Для лицаря ми починаємо з 2W1N і рухаємось за годинниковою стрілкою; пункт призначення 0 є першим дійсним пунктом призначення в цьому порядку.

  • Пішаки: Нерухлива пішак має 2 варіанти призначення, отже, вимагає 1 біт. Якщо пішак може захопити іншого, як звичайно, так і ен-пасанта (який декодер може визначити, оскільки він відстежує стан), він також може вибрати 2 або 3 варіанти ходів. Крім цього, пішак може мати лише 1 вибір, не вимагаючи жодних біт. Коли пішак займає 7- е місце, ми також беремо участь у виборі підвищення. Оскільки пішаків зазвичай підвищують до дам, а потім до лицарів, ми кодуємо вибір як:
    • ферзь: 0
    • лицар: 10
    • єпископ: 110
    • ладья: 111
  • Єпископ: щонайбільше 13 пунктів призначення при {d, e} {4,5} за 4 біти.
  • Ладья: щонайбільше 14 пунктів призначення, 4 біти.
  • Лицарі: не більше 8 напрямків, 3 біти.
  • Королі: коли варіант рокіровки є, король повертається до S і не може рухатися вниз; це дає загалом 7 напрямків. В інший час король має щонайбільше 8 ходів, даючи максимум 3 біти.
  • Королева: Те саме, що вибір для єпископа чи ладьї, загалом 27 варіантів, що становить 5 біт

Оскільки кількість варіантів не завжди дорівнює двом, вищезазначене все одно витрачає біти. Припустимо, що кількість варіантів дорівнює C, а конкретний вибір пронумерований c , і n = ceil (lg ( C )) (кількість бітів, необхідних для кодування вибору). Ми використовуємо ці витрачені в іншому випадку значення, досліджуючи перший біт наступного вибору. Якщо 0, нічого не робити. Якщо це 1 і c + C <2 n , додайте C до c . Декодування числа змінює це: якщо отримане c > = C , відніміть C і встановіть перший біт для наступного числа на 1. Якщо c<2 n - C , а потім встановіть перший біт для наступного числа на 0. Якщо 2 n - C <= c < C , тоді нічого не робити. Назвіть цю схему "насиченість".

Іншим можливим типом вибору, який може скоротити кодування, є вибір фігури опонента для захоплення. Це збільшує кількість варіантів для першої частини ходу, вибору фігури, щонайбільше для додаткового біта (точна кількість залежить від того, скільки фігур може рухати поточний гравець). Цей вибір супроводжується вибором фігури для захоплення, яка, ймовірно, набагато менша за кількість ходів для будь-якої з даних фігур гравців. Фігуру може атакувати лише одна фігура з будь-якого кардинального напрямку плюс лицарі загалом щонайбільше 10 фігур, що атакують; це дає загалом максимум 9 бітів для руху захоплення, хоча я б очікував 7 біт в середньому. Це було б особливо вигідно для захоплення королевою, оскільки часто у неї буде досить багато законних пунктів призначення.

З насиченістю кодування захоплення, ймовірно, не дає переваг. Ми могли б дозволити обидва варіанти, вказавши в початковому стані, які використовуються. Якщо насичення не використовується, кодування гри також може використовувати невикористані номери вибору ( C <= c <2 n ) для зміни параметрів під час гри. Будь-коли C дорівнює двом, ми не могли змінити параметри.


1

Томас має правильний підхід до кодування дошки. Однак це слід поєднувати з підходом ralu до зберігання ходів. Складіть список усіх можливих ходів, випишіть кількість бітів, необхідних для вираження цього числа. Оскільки декодер робить той самий розрахунок, він знає, скільки їх можливо, і може знати, скільки бітів читати, коди довжини не потрібні.

Таким чином, ми отримуємо 164 біти за фігури, 4 біти для інформації про рокінг (припускаючи, що ми зберігаємо фрагмент гри, інакше її можна реконструювати), 3 біти для інформації про прийнятність учасника - просто збережіть стовпець, де відбувся перехід ( Якщо en passant неможливо, збережіть стовпець там, де це неможливо - такі стовпці повинні існувати) та 1 для того, хто має переміщуватись.

Переміщення зазвичай триває 5 або 6 біт, але може варіюватися від 1 до 8.

Ще один ярлик - якщо кодування починається з 12 1 біт (неприпустима ситуація - навіть фрагмент не матиме двох королів на одній стороні), ви скасуєте декодування, витираєте дошку і налаштовуєте нову гру. Наступним бітом буде біт переміщення.


1

Алгоритм повинен детерміновано перераховувати всі можливі пункти призначення під час кожного руху. Кількість напрямків:

  • 2 єпископи, по 13 пунктів призначення = 26
  • 2 граки, по 14 пунктів призначення = 28
  • 2 лицарі, по 8 пунктів призначення = 16
  • королева, 27 пунктів призначення
  • король, 8 пунктів призначення

8 лап у гіршому (в перерахунку) випадку можуть стати королевами, що робить найбільшу кількість можливих напрямків 9 * 27 + 26 + 28 + 16 + 8 = 321. Таким чином, усі пункти призначення для будь-якого переміщення можуть бути перераховані на 9-бітове число.

Максимальна кількість ходів обох сторін - 100 (якщо я не помиляюся, не шахіст). Таким чином, будь-яку гру можна записати в 900 біт. Плюс початкове положення кожного фрагмента можна записати, використовуючи 6 бітових чисел, що становить 32 * 6 = 192 біти. Плюс один біт для запису "хто рухається першим". Таким чином, будь-яку гру можна записати, використовуючи 900 + 192 + 1 = 1093 біти.


1

Зберігання стану дошки

Найпростіший спосіб, про який я думав, - це спочатку масив 8 * 8 біт, що представляє розташування кожної фігури (Отже, 1, якщо там є шахова фігура, і 0, якщо її немає). Оскільки це фіксована довжина, нам не потрібен термінатор.

Далі представляйте кожну шахову фігуру в порядку її розташування. Використовуючи 4 біти за штуку, це займає 32 * 4 біти (загалом 128). Що справді справді марнотратно.

Використовуючи двійкове дерево, ми можемо зобразити пішака в одному байті, лицаря та ладью та єпископа в 3, а короля та королеву у 4. Оскільки нам також потрібно зберегти колір шматка, який займе зайвий байт, він закінчується як (вибачте мене, якщо це неправильно, я ніколи раніше не розглядав кодування Хаффмана будь-якими деталями):

  • Пішак: 2
  • Ладья: 4
  • Лицар: 4
  • Єпископ: 4
  • Король: 5
  • Королева: 5

Враховуючи підсумки:

2*16 + 4*4 + 4*4 + 4*4 + 2*5 + 2*5 = 100

Який б'є, використовуючи набір бітів фіксованого розміру на 28 біт.

Тож найкращий метод, який я знайшов, - це зберігати його у 8 2 + 100 бітовому масиві

8*8 + 100 = 164



Зберігання ходів
Перше, про що нам потрібно знати, це те, яка частина куди рухається. Враховуючи, що на дошці є максимум 32 фігури, і ми знаємо, що таке кожен шматок, а не ціле число, що представляє квадрат, ми можемо мати ціле число, що представляє зміщення фігури, а це означає, що ми повинні відповідати лише 32 можливим значенням для представлення шматок.

На жаль, існують різні спеціальні правила, такі як рокінг або повалення короля та формування республіки (довідка Террі Пратчетта), тому перед тим, як ми зберігаємо фігуру для переміщення, нам потрібен один біт із зазначенням, це спеціальний хід чи ні.

Отже, для кожного нормального ходу ми маємо необхідні 1 + 5 = 6біти. (1 бітний тип, 5 біт за штуку)

Після декодування номера фігури ми тоді знаємо тип фігури, і кожна фігура повинна представляти свій хід найбільш ефективно. Наприклад (якщо мої шахові правила до нуля), пішак має в цілому 4 можливих ходи (візьміть ліворуч, візьміть праворуч, рухайтесь один вперед, рухайтесь два вперед).
Отже, щоб зобразити рух пішака, нам потрібні біти '6 + 2 = 8'. (6 біт для заголовка початкового переміщення, 2 біти для якого переміщення)

Переміщення для ферзя було б більш складним, оскільки найкраще мати напрямок (8 можливих напрямків, тобто 3 біти) і загалом 8 можливих квадратів, щоб рухатись для кожного напрямку (тобто ще 3 біти). Отже, щоб зобразити королеву, що рухається, їй знадобляться 6 + 3 + 3 = 12біти.

Останнє, що для мене трапляється, це те, що нам потрібно зберігати, які гравці це перетворюють. Це повинен бути один біт (білий або чорний, щоб рухатися далі)



Результатний формат
Отже, формат файлу буде виглядати приблизно так

[64 біти] Розташування
початкових фігур [макс. 100 біт] Початкові фігури [1 біт] Поворот гравця
[n біт] Переміщення

Де Move -
[1 біт] Тип переміщення (спеціальний або звичайний)
[n бітів] Move Detail

Якщо переміщення - це звичайний хід, деталізація переміщення виглядає приблизно так, як
[5 біт] фрагмент
[n біт] конкретний хід (зазвичай в діапазоні від 2 до 6 бітів)

Якщо це спеціальний хід,
він повинен мати цілочисельний тип, а потім будь-яку додаткову інформацію (наприклад, якщо це рокінг). Я не пам’ятаю кількість спеціальних ходів, тому може бути нормально лише вказати, що це спеціальний хід (якщо є лише один)


1

У базовій справі початкової дошки плюс наступні ходи, враховуйте наступне.

За допомогою шахової програми призначте ймовірності всіх можливих ходів. Наприклад, 40% для e2-e4, 20% для d2-d4 тощо. Якщо деякі кроки є законними, але не враховуються цією програмою, надайте їм низьку ймовірність. Використовуйте арифметичне кодування, щоб зберегти, який вибір було обрано, який буде деяким числом від 0 до 0,4 для першого ходу, 0,4 та 0,6 для другого тощо.

Зробіть те ж саме для іншої сторони. Наприклад, якщо є 50% шансів e7-e5 як відповідь на e2-e4, тоді закодоване число буде від 0 до 0,2. Повторюйте, поки гра не буде закінчена. Результат - потенційно дуже малий діапазон. Знайдіть двійкову частку з найменшою основою, яка підходить для цього діапазону. Це арифметичне кодування.

Це краще, ніж Хаффман, оскільки це можна сприймати як дробове кодування бітів (плюс деякі в кінці гри, щоб округлити до цілого біта).

Результат повинен бути більш компактним, ніж Хаффман, і немає особливих випадків для підвищення, ан-пассанта, руху за правилом 50 та інших деталей, оскільки ними займається програма оцінки шахів.

Щоб повторити, знову використовуйте шахову програму, щоб оцінити дошку та призначити всі ймовірності кожному ходу. За допомогою закодованого арифметичного значення визначте, який хід насправді було зіграно. Повторювати до закінчення.

Якщо ваша шахова програма достатньо хороша, ви можете отримати кращу компресію за допомогою двоступеневого кодера, де ймовірності визначаються на основі ходів як для чорного, так і для білого. У найекстремальнішому випадку з приблизно 200 штатів це кодує весь набір усіх можливих шахових партій, а тому неможливе.

Це майже інший спосіб сказати те, що Дарій вже писав, лише з невеликим прикладом того, як може працювати арифметичне кодування, і реальним прикладом використання існуючої шахової програми, яка допомагає оцінити ймовірність наступних кроків.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.