Треки
/
Python
Python
/
Вправи
/
Розбір SGF
Розбір SGF

Розбір SGF

Середня

Вказівки

Розбір рядка тексту у форматі Smart Game Format.

SGF - це стандартний формат для зберігання файлів настільних ігор, зокрема ґо.

Формат SGF доволі простий. Файл SGF зазвичай містить одне дерево вузлів, де кожен вузол є масивом властивостей. Масив властивостей містить пари ключ-значення; кожен ключ може траплятися лише один раз, але може мати кілька значень.

У цій вправі ми розберемо рядок тексту (англ. string) у форматі SGF і повернемо деревоподібну структуру властивостей.

Файл SGF може мати такий вигляд:

(;FF[4]C[root]SZ[19];B[aa];W[ab])

Це дерево з трьома вузлами:

  • Вузол верхнього рівня має три властивості: FF[4] (ключ = "FF", значення = "4"), C[root](ключ = "C", значення = "root") і SZ[19] (ключ = "SZ", значення = "19"). (FF позначає версію SGF, C - коментар, а SZ - розмір дошки.)
    • Вузол верхнього рівня має єдиний дочірній вузол із єдиною властивістю: B[aa]. (Чорні грають у точці, закодованій як "aa", тобто в точці 1-1).
      • Вузол B[aa] має єдиний дочірній вузол із єдиною властивістю: W[ab].

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

SGF може кодувати варіанти гри. Гравці в ґо часто повертаються назад під час розбору партій (спробуймо так, не працює, спробуймо інакше), і SGF підтримує варіанти послідовностей гри. Наприклад:

(;FF[4](;B[aa];W[ab])(;B[dd];W[ee]))

Тут кореневий вузол має два варіанти. Перший (за домовленістю він показує, як насправді зіграли) - це той, де чорні грають у точці 1-1. Цей файл чорним надіслав їхній учитель, який вказав на розумніший хід у другому дочірньому вузлі кореневого вузла: B[dd] (точка 4-4, дуже стандартний початок, щоб зайняти кут).

Ключ може мати кілька повʼязаних із ним значень. Наприклад:

(;FF[4];AB[aa][ab][ba])

Тут AB (додати чорні) використовують, щоб додати на дошку три чорні камені.

Усі значення властивостей належатимуть до типу Text у SGF. Решту типів значень реалізовувати не потрібно. Можна прочитати повну документацію типу Text, але нижче наведено стислий виклад найважливішого:

  • Символи нового рядка видаляються, якщо вони стоять одразу після \, інакше вони залишаються символами нового рядка.
  • Усі пробільні символи, крім символу нового рядка, перетворюються на пробіли.
  • \ - це символ екранування. Будь-який не-пробільний символ після \ вставляється як є. Будь-який пробільний символ після \ підпадає під наведені вище правила. Зауважте, що SGF не має керуючих послідовностей для пробільних символів, як-от \t чи \n.

Будьмо уважні та не сплутаймо:

  • Рядок тексту, як його записано в рядковому літералі в тестах
  • Рядок тексту, який передають парсеру SGF

Керуючі послідовності в рядкових літералах могли вже бути оброблені парсером мови програмування, перш ніж їх передали парсеру SGF.

У SGF (і в розборі загалом) є ще кілька складнощів, які здебільшого можна залишити поза увагою. Вважатимемо, що вхідні дані закодовані в UTF-8, а тести не міститимуть властивості charset, тож про це можна не хвилюватися. Крім того, можемо припустити, що всі символи нового рядка мають unix-стиль (\n, жодних \r чи \r\n у тестах не буде) і що в тестах не буде необовʼязкових пробільних символів між властивостями, вузлами тощо.

Повідомлення про винятки

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

У цій вправі потрібно скористатися інструкцією raise, щоб «кинути» ValueError, якщо у вхідних даних немає належних роздільників, вони записані не у верхньому регістрі, не утворюють дерева з вузлами або не утворюють дерева взагалі. Тести пройдуть, лише якщо і викликати exception за допомогою raise, і додати до нього повідомлення.

Щоб викликати ValueError з повідомленням, потрібно записати повідомлення як аргумент типу exception:

# if the tree properties as given do not have proper delimiters.
raise ValueError("properties without delimiter")

# if the tree properties as given are not all in uppercase.
raise ValueError("property must be in uppercase")

# if the input does not form a tree, or is empty.
raise ValueError("tree missing")

# if the input is a tree without any nodes.
raise ValueError("tree with no nodes")
Редагувати через GitHub Посилання відкривається в новому вікні або вкладці
Python Exercism

Час розпочати Розбір SGF?

Зареєструйтеся на Exercism, щоб вивчати й опановувати Python, а також 17 концепцій146 вправ та справжнє наставництво від людей, і все це безкоштовно.