Мовний дизайн: 2-D узгодження шаблону


49

Це Fortnightly Challenge # 6 . Тема: Мовний дизайн

Для цього виклику є чат . Приходьте та приєднуйтесь до нас, якщо хочете обговорити ідеї!

А тепер про щось зовсім інше ...

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

Змагання

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

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

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

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

Ваша відповідь повинна містити:

  • Опис мови.
  • Робоча реалізація . Це може бути програма або набір функцій / класів мовою на ваш вибір.
  • Ви повинні продемонструвати свою мову, показавши, як її можна використовувати для вирішення наведених нижче прикладів . Ваша мова не повинна бути здатною відповідати всім, але ви повинні вміти відповідати принаймні 8 із них. Якщо ваша мова може зробити щось фантазійне, про що ми не думали, сміливо додайте її також.

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

Розширення

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

  • Можливість прив’язання шаблону до одного або декількох країв, щоб можна було перевірити, чи є вся область вводу певним шаблоном.
  • Проведення всіх матчів замість лише одного. Ви можете вибрати семантику збігів, що перекриваються.
  • Введення не прямокутного тексту як вхідного.
  • Дозволяючи шаблонам задавати не прямокутні збіги. У такому випадку висновок повинен бути підбитий до прямокутника з деяким зарезервованим символом.
  • Дозволяє шаблонам задавати збіги з отворами.
  • Дозволення безперервних збігів, як-от два символи, що з’являються з певним зміщенням.
  • Легка специфікація обертання та відбиття.
  • Необов'язково розглядати вхід циклічно як циліндр або торус, таким чином, щоб протилежні краї вважалися суміжними.

Оцінка балів

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

  • Виразність. Чи може мова вирішити різноманітні проблеми, навіть поза прикладами, представленими в цьому питанні? Чи підтримує воно будь-яке із запропонованих розширень?
  • Читабельність. Наскільки інтуїтивним є позначення (принаймні, для людей, які знають основний синтаксис)?
  • Гольф. Це все ще CodeGolf.SE. Для цілей цього сайту, звичайно, було б добре мати відповідну мову, для опису шаблону якого потрібно дуже мало коду.

Приклад проблем

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

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

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


Чи існує загальний часовий обмеження на ці проблеми? Мені дуже цікаво вирішити це, але я дуже зайнятий, це може зайняти 2 тижні.
Девон Парсонс

7
@DevonParsons Не існує терміну вступу.
PhiNotPi

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

1
@ mbomb007 Є бонусні бали за створення двомовної мови. Я майже впевнений, що це отримає гідну суму грошей. ;)
Мартін Ендер

@ MartinBüttner Я навіть не знаю, як створити мову. Чи може це бути на кшталт (просто?), Як створення програми Python, яка бере файл коду вашої нової мови (та інтерпретує / виконує його на основі заданого синтаксису) та створює вихід?
mbomb007

Відповіді:


32

SnakeEx

Досі вирішує 15/16 проблем!

Інтернет-перекладач ! - Повна мова Spec - Джерело Javascript

Скріншот інтерпретатора

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

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

Кожна програма, по суті, буде схожа на набір регулярних виразів, але з додаванням команд спрямування форми, <dir>які змінюють напрям змії, та виклику команд форми, {label<dir>params}що породить більше змій.

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

Це не дуже стисло, але він дуже потужний і (я думаю) досить читабельний.

Оновлення

  • Змінено! логічно не і ~ не позначати збіги
  • Додано <!>для розв’язування колін
  • Вирішили відповідні хрести
  • Вирішували шахові дошки менш жахливим способом
  • Додано обмежений синтаксис закриття %{min,max}
  • Додано приклад рекурсії

Рішення

15 вирішених, 1 триває

Ви можете легко спробувати ці програми, використовуючи Інтернет-перекладач, зв'язаний вище!

Завдання 1 - Пошук шахових дощок

m:{v<R>2}{h<>1}
v:{c<L>A1}+
h:{c<R>A2}+
c:_?(#_)+#?

Для детального вступу почніть з проблеми 3.

Завдання 2 - Перевірка шахових дощок

m:{v<R>2}{h<>1}
v:${c<L>A1}+$
h:${c<R>A2}+$
c:$_?(#_)+#?$

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

Завдання 3 - Виявлення прямокутника цифр

m:{c<R>A1}%{2,}
c:[0-9]%{2,}

У mзмії рухається прямо, породжуючи на мінімум 2 змія ( %{2,}це замикання означає «2 в нескінченність») , використовуючи визначення з ( c) і переміщенням вправо ( <R>), або , вірніше , вниз в даному випадку, оскільки всі напрямки по відношенню до поточної змії. AПарам є цукор , який просто вказує , що нерест змія повинна рухатися після виклику. 1Параметр , як ми обмежуємо матчі прямокутників - параметри числення змія в «групах». Матч не зараховується, якщо всі змії в одній групі проїжджають точно однакову відстань.

Завдання 4 - Пошук слова в пошуку слова

m:<*>GOLF

Команда напряму <*>вказує, що змія повинна повертатись у будь-якому діагональному чи ортогональному напрямку. Потім, він шукає простий регулярний вираз.

Завдання 5 - Виявити квадратні входи

m:{v<R>1}{h<>1}
v:${c<L>A1}+$
h:${c<R>A1}+$
c:$.+$

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

Завдання 6 - Знайдіть планери в грі життя

m:<+>[({l1<R>A}{l2<R>A}{l3<R>})({l1<L>A}{l2<L>A}{l3<L>})]
l1:##\.
l2:[(#\.)(\.#)]#
l3:#\.\.

mпочинається в будь-якому з чотирьох ортогональних напрямків ( <+>), досягаючи обертання. Потім, вона дивиться або вліво, або вправо на три ряди в порядку, досягаючи відображення.

(Зауважте, що я замінив пробіли періодами лише тому, що текстові області HTML, які використовуються в моєму інтерпретаторі, здаються дурними, якщо вони мають кілька пробілів підряд)

Проблема 7 - відповідність порталів Nether

m:{e<R>A1}{d<R>A1}%{2,22}{e<R>1}
e:~.X%{3,22}~.
d:X\.+X

У mзмії рухається вправо, породжуючи змію , щоб перевірити лівий край, 2-22 змія , щоб перевірити середні колони, і , нарешті , змію , щоб перевірити правий край. ~Оператор вказує на те, що все , що наступним має бути перевірений , але не повинні бути позначені як частина рішення.

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

Проблема 8 - Розміщення грудної клітки Minecraft

m:~{s<>}~!{d<+>}\.
s:<+>.<BR>([$\.]<R>)%{3}
d:.<+>CC

Тут ми використовуємо логічний not ( !), який відповідає тоді і лише тоді, коли наступний маркер нічого не відповідає. Декларація dвиявляє подвійну скриню в певному напрямку, тому !{d<+>}переконайтеся, що немає подвійних скринь у жодному ортогональному напрямку. sрухається невеликим діамантом навколо поточного квадрата, перевіряючи, що принаймні 3 з цих просторів є порожніми або поза дошкою. Кінцевий результат, \.нарешті, відповідає площі, припускаючи, що всі попередні умови були успішними.

Завдання 9 - Горизонтальна і вертикальна вирівнювання

m:<R>?#~.*#

Змія mнеобов'язково повертає праворуч ( <R>?) перед узгодженням послідовності. .являє собою підстановку, як у регулярному вираженні.

Завдання 10 - Колінеарні очки

m:<!>#~.*#~.*#

Додавши <!>напрямок, ми можемо вирішити це зараз! <!>це як, <+>але замість того, щоб розгалужуватися в чотирьох напрямках, воно розгалужується в усіх можливих напрямках.

Завдання 12 - Уникайте літери Q

m:{h<R>A}%{4}
h:[^Qq]%{4}

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

Проблема 13 - Алмазне видобуток

m:{tl<RB>1}{tr<RF>1}
tl:X/*{bl<L>1}X
tr:X\\*{br<R>1}X
bl:X\\*X
br:X/*X

Цей досить акуратний. mпороджує дві змії, одна йде правою спиною, а одна - правою вперед. Кожен з них слідує за косою рисою до X, потім породжує іншу змію під прямим кутом до її поточного напрямку, яка слідує за косою донизу X.

Завдання 14 - Узгодження хрестів

m:{a<R>A}+{b<R>A}+{a<R>A}+
a:{e<>P1}{c<>P2}{e<>P3}
b:{c<>P1}{c<>P2}{c<>P3}
e:\.+
c:#+

Ось я вперше застосував Pпараметр iggyback. Зазвичай змії є незалежними, але якщо ви телефонуєте за цим параметром, дзвінка, що викликає, буде переміщена за допомогою виклику. Тож e2можна перевірити послідовність '.', Потім послідовність '#', потім іншу послідовність '.', І всі вони будуть окремими дзвінками, щоб ми могли згрупувати їх з '1,' 2 'та' 3 ' , змушуючи їх довжину збігатися.

Проблема 15 - Зіставте слово на дошці Boggle

m{I}:<*>p<*>a<*>n<*>a<*>m<*>a

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

m{EI}:<*>p<*>a<*>n<*>a<*>m<*>a

Це версія не повторного використання символів. Параметр Exclusive забороняє змії відповідати будь-якому символу, який уже був позначений, як і сліди слідів Feersum.

Проблема 16 - Оберніть навколо країв

m{W}:{c<R>WA}%{3}
c:###

WПараметр дозволяє змії загорнути , коли він працює поза межами. Ми також маємо Hі Vдопускати лише горизонтальне або вертикальне обгортання.

Додатково - лабіринт Solver

m{E}:$(<P>\.)+$

Вирішує лабіринт ASCII, де підлоговий простір - це періоди. <P>Напрямок означає вперед, вліво або вправо (цукор для [<F><L><R>]).

Додаткові - батьківські відповідники

m:\(~{r<>P}\)
r:[^\(\)]*(\({r<>P}\))?[^\(\)]*

Ще не зрозуміли, як зробити Прелюдію, але ось перший крок! Тут я використовую rзмію рекурсивно, щоб відповідати відповідним дужкам, перевіряючи, чи немає між ними непорівняних дужок.

Додаткова - топологія ASCII: підрахунок петель


Чи можете ви додати синтаксис, щоб ця мова могла замінити, а не просто відповідати? Я хочу використати якесь рішення цього завдання, щоб написати запис для codegolf.stackexchange.com/questions/51231/…, але жодне рішення тут не знайде та замінить. (Я знаю, що моя відповідь не буде дійсною через правила специфікації мови)
Sparr

@Sparr. Не погана ідея, вона, безумовно, була б кориснішою для коду гольфу. Не впевнений, коли я встигну це зробити самостійно, але пам’ятаю про це.
BMac

3
окремо: синтаксис змін напряму заплутаний. оскільки змія прогресує після узгодження персонажа, мені здається, що я повинен зробити так, щоб мій напрямок змінив одного персонажа заздалегідь, де це має сенс для мене. Приклад: рядок "ABC \ nDEF", і я хочу відповідати фрагменту тетрису L у формі, визначеному ABCF, я хочу записати свою змію як "m: ABC <R> F", але я повинен написати "m: AB <R> CF "замість цього. Я розумію, що це відповідає специфікації, але я вважаю це дуже контрсуєтивним.
Спарр

У мене є часткове рішення для синтаксису прелюдії. Єдина проблема полягає в тому, що я не можу змусити його не збігатися, якщо він не відповідає всьому входу: m:{a<>} a:[({n<R>A})({n<R>A}*{l<R>A}{a<>P}{r<R>A})]*{n<R>A}* l:$[^\(\)]*\([^\(\)]*$ r:$[^\(\)]*\)[^\(\)]*$ n:$[^\(\)]+$
TheNumberOne

21

Slip, Python 3.4 ( Вікі Github , онлайн-перекладач )

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

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


Оновлення

(Докладні новини див. На сторінці Github)

  • 5 квітня 2015 року : У "Slip" зараз є перекладач онлайн ! Він ще на ранній стадії, тому може бути кілька помилок.

  • 5 квітня 2015 року : оновлення ефективності! Тепер чисті портали вводять набагато швидше (2 секунди). Також відбулася низка змін синтаксису, тому обов'язково перевірте вікі. Фіксована також групова нумерація.


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

Напрямок покажчика матчу може бути встановлено в певний напрям з ^<digit>, де ^0, ^1, ^2..., ^7встановити покажчик на N, NE, E, ..., NW відповідно (що йде по годинниковою стрілкою).

Також доступні такі ярлики:

  • ^* перевіряє всі 8 ортогональних або діагональних напрямків,
  • ^+ перевіряє всі 4 ортогональні напрямки.

(План майбутнього: Дозволити встановлення довільних напрямків, наприклад, (1, 2)для руху лицаря)

Наприклад ( проблема 4 - Пошук слова при пошуку слова ),

^*GOLF

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

GOLF
O
L
FLOG

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

Аналогічно ( Завдання 15 - Зіставте слово на дошці Boggle ),

p^*a^*n^*a^*m^*a

збігається panama, намагаючись кожен раз в іншому напрямку. Використовуйте iпрапор для нечутливості корпусу. Ковзання повторно використовує символи за замовчуванням, але це можна змінити rпрапором без повтору.

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

Напрямок вказівника відповідності також можна повертати на 90 градусів вліво або вправо, відповідно <або >відповідно. Наприклад,

 `#`#< `#<  <`#<`#

шукає візерунок

  #
## 
 ##

дивлячись у такому порядку:

765
894
123

Це дозволяє нам вирішити проблему 6 - Пошук планерів за допомогою

^+(`#`# >`# > `#>`#> |`#`# <`# < `#<`#< | `#`#> `#>  >`#>`#| `#`#< `#<  <`#<`#)

де частини 1 і 2 кодують форми планера, а частини 3 і 4 кодують їх відбиті аналоги.

Зауважте, що `для втечі Slip використовує backtick . Це тому, що Slip має іншу форму руху, яка дає мові свою назву - команду slip. /ковзає вказівник відповідності ортогонально ліворуч, а \ортогонально - вказівник праворуч.

Наприклад,

abc   ghi
   def

може відповідати abc\def/ghi.

Незважаючи на те, що сама по собі не є особливо корисною, ковзання стає важливішим у поєднанні зі (?| <regex> )стаціонарною групою, яка діє на зразок узгодженого пошуку. Зворотний вираз всередині узгоджується, після чого в кінці його положення та напрямок відповідника вказують на стан перед стаціонарною групою.

Наприклад,

abc
def
ghi

можна зіставити (?|abc)\(?|def)\(?|ghi).

Аналогічно, проблема 12 - Уникнення літери Q можна вирішити

%(\(?|[^qQ]{4})){4}

де %команда без ковзання зупиняє \активацію першого .

У ковзання також є затвердження довжини (?_(<group num>) <regex> ), яке відповідає регексу всередині, лише якщо його довжина збігання буде такою ж довжиною, як у заданої кількості групи.

Наприклад, проблема 13 - Видобуток алмазів можна легко вирішити

^1X(`/*)X>(?_(1)`\*)X>(?_(1)`/*)X>(?_(1)`\*)

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

(Виконати з vпрапором для багатослівного виведення)

Match found in rectangle: (8, 0), (12, 4)
  X
 / \
X   X
 \ /
  X

Match found in rectangle: (0, 0), (6, 6)
   X
  / \
 /   \
X     X
 \   /
  \ /
   X

Match found in rectangle: (2, 2), (4, 4)
 X
X X
 X

Match found in rectangle: (10, 2), (14, 6)
  X
 / \
X   X
 \ /
  X

Match found in rectangle: (5, 3), (9, 7)
  X
 / \
X   X
 \ /
  X

Match found in rectangle: (0, 6), (2, 8)
 X
X X
 X

Альтернативою для гравців є

^1X(`/*)(X>(?_(1)`\*)X>(?_(1)`/*)){2}

що відповідає першій стороні двічі.

Багато інших проблем можна вирішити за допомогою ковзання, нерухомих груп та тверджень про довжину:

Завдання 14 - Узгодження хрестів:

(?|(`.+)(`#+)(`.+))(\(?|(?_(2)`.+)(?_(3)`#+)(?_(4)`.+)))*(\(?|(?_(2)`#+)(?_(3)`#+)(?_(4)`#+)))+(\(?|(?_(2)`.+)(?_(3)`#+)(?_(4)`.+)))+

Після того, як ви зафіксуєте ширини .s і #s в першому ряду, він просто ковзає всю дорогу вниз.

Вихід:

Match found in rectangle: (0, 1), (5, 5)
.###..
######
######
.###..
.###..

Match found in rectangle: (4, 6), (6, 8)
.#.
###
.#.

Цей, ймовірно, може бути гольф з невеликою рекурсією, як тільки я отримаю кілька помилок.

Завдання 3 - Виявити прямокутник цифр:

(?|`d`d+)(\(?|(?_(1)`d+)))+

Підберіть верхній рядок з двох чи більше цифр, а потім переконайтесь, що кожен рядок нижче однакової довжини. `dце заздалегідь визначений клас символів, еквівалентний [0-9].

Зауважте, що це знаходить усі збіги .

Проблема 7 - Матчі нижчих порталів:

(?|.X{2,22}.)\((?|(?_(1)X`.+X))\){3,22}(?_(1).X+.)

який виводить, для верхнього прикладу в початковій потоці :

Match found in rectangle: (2, 1), (5, 5)
XXXX
X..X
X..X
X..X
XXXX

Match found in rectangle: (9, 1), (14, 5)
.XXXX.
X....X
X....X
X....X
.XXXX.

Match found in rectangle: (13, 4), (17, 8)
.XXXX
X...X
X...X
X...X
.XXX.

Нарешті, деякі інші функції Slip включають:

  • $0, $1, $2, ..., $7закріплюють північний край, північно-східний кут, східний край тощо. $+прив’язують будь-який край і $*прикріплюють будь-який кут.
  • $з наступним символом малих літер встановлюється якір у поточному положенні, який згодом може бути узгоджений з $подальшим відповідним великим символом, наприклад, $aта $A.
  • # перемикає прапор без руху, що зупиняє рух покажчика збігу після наступного матчу.
  • ,відповідає подібному знаку ., але не додає його до результату, дозволяючи нестигнутих збігів, а також може бути розпізнаний (?_()).

... і більше. На цій сторінці насправді занадто багато.

Інші проблеми

Завдання 1 - Пошук шахових дощок:

(?|`#?(`_`#)+`_?)(?_(1)(?|...+))(\(?_(1)(?|`#?(`_`#)+`_?$a)))+<(?|`#?(`_`#)+`_?)(?_(9)(?|...+))(\(?_(9)(?|`#?(`_`#)+`_?)))+$A

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

Потім повертаємо вліво і повторюємо стовпці, переконуючись, що ми відповідаємо $Aв кінці.

Завдання 2 - Перевірка шахових дощок:

$7%(\(?|`_?(`#`_)*`#?$2))+$5<%(\(?|`_?(`#`_)*`#?$0))+$3

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

Завдання 9 - горизонтальне та вертикальне вирівнювання:

>?`#,*`#

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

Завдання 10 - Колінеарні точки

^+`#(?|(,*)<(,*))(((?_(2),*)<(?_(3),*),>)+#`#){2}

Зіставте #потім кілька горизонтальних знаків і кілька вертикальних, а потім повторіть до другого #і повторіть до третього #.

Завдання 5 - Виявлення квадратних входів:

$7.(.*)>(?_(1).*)$3>((?|.*)\)*

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

Проблема 8 - Розміщення грудної клітки Minecraft:

`.^+(($^|(?|`.))>){3}($^|`.|C<(($^|(?|`.))>){3})

Біжи з pпрапором, щоб отримати позиції кожного матчу. $^- це якір, який відповідає, якщо наступний хід виведе покажчик відповідності за межі.

Спочатку ми співпадаємо з a ., потім перевіряємо, чи нас оточують три .s / межі, потім переконуємось, що четвертий навколишній квадрат також є ./ межею або є однією скринкою (перевіряючи навколишні його квадрати).

Проблема 11 - Перевірка синтаксису прелюдії :

$7>%(/(?|[^()]+$4)(?1)?|/(?|[^()]*`([^()]*$4)(?1)?/(?|[^()]*`)[^()]*$4)(?1)?)$1

Був кілька спроб, але я вважаю, що це правильно. Тут ми використовуємо рекурсію, яка має той самий синтаксис, що і PCRE.

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

Ось такий самий підхід, який гольфується з більшою рекурсією:

$7>%((/(?|([^()]*)$4)|/(?|(?4)`((?3))(?1)?/(?|(?4)`)(?3)))*)$1

Проблема 16 - Оберніть по краях:

%(\(?|`#{3})){3}

(Примітка: обгортання ще не передано онлайн-перекладачу)

Для цього необхідний обгортковий прапор w. Технічно початковий режим %без ковзання не є необхідним, але тоді матч вважатиметься таким, що починається з квадрата вище.

Проблема EX 1 - Лабіринт:

S(^+`.)*^+E

Проблема з коментарем BMac у чаті . Використовуйте rпрапор не в режимі повтору, щоб покажчик збігу не застряг ідучи вперед і назад.

Проблема EX 2 - Розпізнавання обличчя :

(?|O(,*),(?_(2),*)O)(?_(2)(\(?|,))*)\(?|,(?_(2),*)O)(?_(2)(\(?|,))*)\`\(?_(2)`_*)`_(?_(2)`_*)`/

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


Цей хеш-зразок - планер Conway
Heimdall

17

PMA / Равлики (C ++)

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

Зараз достатньо операторів, що нам знадобиться список пріоритетів, щоб відстежувати їх. Операції вирішуються в такому порядку:

  1. Всередині груп ( ) [ ]
  2. Розділити по чергуванню символів |
  3. Оцініть все зліва від `групи як групи
  4. Квантори [m],[n]таn
  5. Твердження = !
  6. Сполучення

Перекладач написаний на C ++. Вихідний код плачевні можна знайти тут .

Проблема 4: Пошук слів

Програма

z\G\O\L\F

достатньо, щоб отримати значення "truthy" або "falsey" для того, чи знайдено слово. z(одна з 15 абсолютних або відносних команд спрямованості) збігається в будь-якому восьмилінійному напрямку. Кілька послідовних команд вказівки ORI разом. Наприклад, це ruldyбуло б майже рівнозначно тому z, що це команди вправо, вгору, вліво, вниз і в будь-якому напрямку діагоналі. Однак напрямки будуть перевірені в іншому порядку. Перший відповідний персонаж - це завжди той, з якого починається равлик, незалежно від напрямку. \<character> відповідає одному буквальному символу.

Стратегія за замовчуванням - спробувати візерунок на кожному квадраті в обмежувальному полі з обґрунтованим лівим введенням та вивести кількість збігів. Якщо булеве значення 1або 0потрібне, можна використовувати наступну програму:

?
z\G\O\L\F

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

Проблема 15: Блукання

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

\p|\P)z(\a|\A)z{\n|\N)z{\a|\A}z(\m|\M)z(\a|\A

|працює точно так само, як і одновимірний регулярний вираз. Для групування існують дві пари розділювачів, а саме ()і {}. Закриваючий кронштейн закриє будь-які відкриті групи протилежного типу, які стоять між ним та найближчим того ж типу. Наприклад, слідуючи {({{), відкрита залишається лише крайня ліва група. Як бачимо, незрівняні символи групування по краях неявно закриваються. Є ще одна команда групування, в `яку я зараз не заходжу.

Проблема 8: Скрині для Minecraft

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

\.!(o\C)2o(!\Cw)3
  • \. відповідає крапці буквально, у початковій точці матчу.
  • !(o\C)2еквівалентно !((o\C)2)тому, що кількісне визначення є вищим пріоритетом, ніж твердження. <atom> <number>означає повторити <atom>рівно <number>рази. oповертає равлика в будь-якому ортогональному напрямку. !є негативним твердженням. Таким чином, ця частина перевіряє відсутність сусідньої подвійної скрині.
  • o повороти в деякому ортогональному напрямку.
    • (!\Cw)3стверджує, що Cперед слимаком немає, а потім повертається проти годинникової стрілки 3 рази.

Завдання 2: Перевірка шахових дощок

&
\#!(o^_)|\_!(o^#

&Опція встановлює вихід програми в 1разі , якщо збіг знайдено на всі позиції, і в 0іншому випадку. ^cвідповідає символу, якого немає c, що еквівалентно [^c]регексу. В цілому програма означає: Друкуйте 1, якщо в кожному положенні в обмежувальному прямокутнику вводу є або a, #яке не ортогонально суміжне з символом, який не є _, або _який не ортогонально суміжний з символом, який є ні #; інакше 0.


Ідея про слизьку трасу - це гарна ідея для боротьби з багном, у мене були проблеми з цим
BMac

Це приємне рішення для проблеми з Богом. Я не можу це вирішити своїм підходом.
Логічний лицар

14

Клас Re2d, Python 2

Оновлення: додано проблему "9. Вирівнювання".

Мій підхід полягає у використанні модуля Python re для пошуку та узгодження. Клас Re2d готує текст для обробки, виконує повторні функції та форматує результати для виведення.

Зауважте, що це не зовсім нова мова - це стандартна мова регулярного вираження, спроектована на 2 виміри з доданими прапорцями для додаткових двовимірних режимів.

Клас має таке використання:

re2dobject = Re2d(<horizontal pattern>, [<vertical pattern>], [<flags>])

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

Тестування

1. Finding chessboards
Chessboard pattern at (2, 1, 4, 3)

print '\n1. Finding chessboards'
reob1 = Re2d('#(_#)+_?|_(#_)+#?')
found = reob1.search('~______~\n~##_#_#~\n~#_#_##~\n~##_#_#~\n~______~')
print 'Chessboard pattern at', found
assert not reob1.search('#_##\n_#_#\n__#_\n#_#_\n#_#_')

Метод пошуку знайшов шаблон шахової дошки і повертає положення з 4-ма кордонами. Кортеж маєx,y позицію першого символу матчу, а width, heightобласть відповідає. Наведено лише один зразок, тому він буде використовуватися для горизонтального та вертикального узгодження.

2. Verifying chessboards
Is chess? True

print '\n2. Verifying chessboards'
reob2 = Re2d('^#(_#)*_?|_(#_)*#?$')
print 'Is chess?', reob2.match('_#_#_#_#\n#_#_#_#_\n_#_#_#_#')
assert not reob2.match('_#_#_#__\n__#_#_#_\n_#_#_#__')

Шахова дошка була перевірена методом відповідності, який повертає булеву форму. Зауважимо, що^ і $початкова і кінцеві символи повинні відповідати всьому тексту.

3. Rectangle of digits
Found: [(0, 1, 5, 3), (1, 1, 4, 3), (2, 1, 3, 3), (3, 1, 2, 3), (0, 2, 5, 2), (1, 2, 4, 2), (2, 2, 3, 2), (3, 2, 2, 2), (6, 3, 2, 2)]
Not found: None

print '\n3. Rectangle of digits'
reob3 = Re2d(r'\d\d+', flags=MULTIFIND)
print 'Found:', reob3.search('hbrewvgr\n18774gwe\n84502vgv\n19844f22\ncrfegc77')
print 'Not found:', reob3.search('uv88wn000\nvgr88vg0w\nv888wrvg7\nvvg88wv77')

Тепер ми використовуємо MULTIFINDпрапор, щоб повернути всі можливі збіги для блоку 2+ знаків. Метод знаходить 9 можливих збігів. Зверніть увагу, що вони можуть перекриватися.

4. Word search (orthogonal only)
Words: [(0, 0, 4, 1), (0, 3, 4, 1), (3, 3, -4, -1), (3, 2, -4, -1), (3, 0, -4, -1)] [(0, 0, 1, 4), (3, 0, 1, 4), (3, 3, -1, -4), (0, 3, -1, -4)]
Words: ['SNUG', 'WOLF', 'FLOW', 'LORE', 'GUNS'] ['S\nT\nE\nW', 'G\nO\nL\nF', 'F\nL\nO\nG', 'W\nE\nT\nS']
No words: [] []

print '\n4. Word search (orthogonal only)'
words = 'GOLF|GUNS|WOLF|FLOW|LORE|WETS|STEW|FLOG|SNUG'
flags = HORFLIP | VERFLIP | MULTIFIND
reob4a, reob4b = Re2d(words, '.', flags), Re2d('.', words, flags)
matching = 'SNUG\nTEQO\nEROL\nWOLF'
nomatch = 'ABCD\nEFGH\nIJKL\nMNOP'
print 'Words:', reob4a.search(matching), reob4b.search(matching)
print 'Words:', reob4a.findall(matching), reob4b.findall(matching)
print 'No words:', reob4a.findall(nomatch), reob4b.findall(nomatch)

Цей тест показує використання вертикального та горизонтального гортання. Це дозволяє відповідати словам, які перевернуті. Діагональні слова не підтримуються. MULTIFINDПрапор дозволяє використовувати кілька перекриваються матчі у всіх 4 -х напрямках. Метод findall використовує пошук для пошуку відповідних полів, а потім витягує відповідні блоки тексту. Зверніть увагу, як для пошуку використовується негативна ширина та / або висота для збігів у зворотному напрямку. У словах у вертикальному напрямку є нові символи рядка - це узгоджується з концепцією 2D-символьних блоків.

7. Calvins portals
Portals found: [(3, 1, 5, 6)]
Portal not found None

print '\n7. Calvins portals'
reob7 = Re2d(r'X\.{2,22}X|.X{2,22}.', r'X\.{3,22}X|.X{3,22}.', MULTIFIND)
yes = '....X......\n.XXXXXX.XX.\n...X...X...\n.X.X...XXX.\n...X...X.X.\n.XXX...X.X.\nX..XXXXX.X.'
no = 'XX..XXXX\nXX..X..X\nXX..X..X\n..X.X..X\n.X..X.XX'
print 'Portals found:', reob7.search(yes)
print 'Portal not found', reob7.search(no)

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

9. Alignment
Found: ['#.,##', '##'] ['#\n.\n,\n.\n#', '#\n,\n.\n#']
Found: [(3, 4, 5, 1), (6, 4, 2, 1)] [(7, 0, 1, 5), (3, 1, 1, 4)]
Not found: None None

print '\n9. Alignment'
reob9a = Re2d(r'#.*#', r'.', MULTIFIND)
reob9b = Re2d(r'.', r'#.*#', MULTIFIND)
matching = '.,.,.,.#.,\n,.,#,.,.,.\n.,.,.,.,.,\n,.,.,.,.,.\n.,.#.,##.,\n,.,.,.,.,.'
nomatch = '.,.#.,.,\n,.,.,.#.\n.,#,.,.,\n,.,.,.,#\n.#.,.,.,\n,.,.#.,.\n#,.,.,.,\n,.,.,#,.'
print 'Found:', reob9a.findall(matching), reob9b.findall(matching)
print 'Found:', reob9a.search(matching), reob9b.search(matching)
print 'Not found:', reob9a.search(nomatch), reob9b.search(nomatch)

Цей набір із 2-х пошукових запитів знаходить 2 вертикальних та 2 горизонтальних збіги, але вбудований не може знайти #.,# рядок.

10. Collinear Points (orthogonal only)
Found: [(0, 1, 7, 1)] [(3, 1, 1, 4)]
Not found: None None

print '\n10. Collinear Points (orthogonal only)'
matching = '........\n#..#..#.\n...#....\n#.......\n...#....'
nomatch = '.#..#\n#..#.\n#....\n..#.#'
reob10h = Re2d(r'#.*#.*#', '.')
reob10v = Re2d('.', r'#.*#.*#')
flags = MULTIFIND
print 'Found:', reob10h.search(matching, flags), reob10v.search(matching, flags)
print 'Not found:', reob10h.search(nomatch, flags), reob10v.search(nomatch, flags)

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

12. Avoid qQ
Found: (2, 2, 4, 4)
Not found: None

print '\n12. Avoid qQ'
reob12 = Re2d('[^qQ]{4,4}')
print 'Found:', reob12.search('bhtklkwt\nqlwQklqw\nvtvlwktv\nkQtwkvkl\nvtwlkvQk\nvnvevwvx')
print 'Not found:', reob12.search('zxvcmn\nxcvncn\nmnQxcv\nxcvmnx\nazvmne')

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

13. Diamond Mining
.X.
X.X
.X.

.X.
X.X
.X.

..X..
./.\.
X...X
.\./.
\.X..

..X..
./.\.
X...X
.\./.
..X..

.XX.\
//.\.
X...X
.\./.
..X..

...X...
../.\..
./.X.\.
X.X.X.X
.\.X.//
..\./X.
.X.X..\

Diamonds: [(2, 2, 3, 3), (0, 6, 3, 3)] [(8, 0, 5, 5), (10, 2, 5, 5), (5, 3, 5, 5)] [(0, 0, 7, 7)]
Not found: None None None

print '\n13. Diamond Mining'
reob13a = Re2d(r'.X.|X.X', flags=MULTIFIND)
reob13b = Re2d(r'..X..|./.\\.|X...X|.\\./.', flags=MULTIFIND)
reob13c = Re2d(r'...X...|../.\\..|./...\\.|X.....X|.\\.../.|..\\./..', flags=MULTIFIND)
match = '''
...X......X....
../.\..../.\...
./.X.\..X...X..
X.X.X.XX.\./.\.
.\.X.//.\.X...X
..\./X...X.\./.
.X.X..\./...X..
X.X....X.......
.X.............
'''.strip().replace(' ', '')
nomatch = '''
.X......./....
.\....X.......
...X.\.\...X..
..X.\...\.X.\.
...X.X...X.\.X
../X\...\...X.
.X...\.\..X...
..\./.X....X..
...X..../.....
'''.strip().replace(' ', '')
for diamond in reob13a.findall(match)+reob13b.findall(match)+reob13c.findall(match):
    print diamond+'\n'
print 'Diamonds:', reob13a.search(match), reob13b.search(match), reob13c.search(match)
print 'Not found:', reob13a.search(nomatch), reob13b.search(nomatch), reob13c.search(nomatch)

Проблема з алмазами складніше. Для трьох розмірів потрібні три об’єкти пошуку. У тестовому наборі можна знайти шість діамантів, але він не масштабується до діамантів змінних розмірів. Це лише часткове рішення алмазної проблеми.

Код Python 2

import sys
import re

DEBUG = re.DEBUG
IGNORECASE = re.IGNORECASE
LOCALE = re.LOCALE
UNICODE = re.UNICODE
VERBOSE = re.VERBOSE
MULTIFIND = 1<<11
ROTATED = 1<<12     # not implemented
HORFLIP = 1<<13
VERFLIP = 1<<14
WRAPAROUND = 1<<15  # not implemented

class Re2d(object):
    def __init__(self, horpattern, verpattern=None, flags=0):
        self.horpattern = horpattern
        self.verpattern = verpattern if verpattern != None else horpattern
        self.flags = flags

    def checkblock(self, block, flags):
        'Return a position if block matches H and V patterns'
        length = []
        for y in range(len(block)):
            match = re.match(self.horpattern, block[y], flags)
            if match:
                length.append(len(match.group(0)))
            else:
                break
        if not length:
            return None
        width = min(length)
        height = len(length)
        length = []
        for x in range(width):
            column = ''.join(row[x] for row in block[:height])
            match = re.match(self.verpattern, column, flags)
            if match:
                matchlen = len(match.group(0))
                length.append(matchlen)
            else:
                break
        if not length:
            return None
        height = min(length)
        width = len(length)
        # if smaller, verify with RECURSIVE checkblock call:
        if height != len(block) or width != len(block[0]):
            newblock = [row[:width] for row in block[:height]]
            newsize = self.checkblock(newblock, flags)
            return newsize
        return width, height

    def mkviews(self, text, flags):
        'Return views of text block from flip/rotate flags, inc inverse f()'
        # TODO add ROTATED to generate more views
        width = len(text[0])
        height = len(text)
        views = [(text, lambda x,y,w,h: (x,y,w,h))]
        if flags & HORFLIP and flags & VERFLIP:
            flip2text = [row[::-1] for row in text[::-1]]
            flip2func = lambda x,y,w,h: (width-1-x, height-1-y, -w, -h)
            views.append( (flip2text, flip2func) )
        elif flags & HORFLIP:
            hortext = [row[::-1] for row in text]
            horfunc = lambda x,y,w,h: (width-1-x, y, -w, h)
            views.append( (hortext, horfunc) )
        elif flags & VERFLIP:
            vertext = text[::-1]
            verfunc = lambda x,y,w,h: (x, height-1-y, w, -h)
            views.append( (vertext, verfunc) )
        return views

    def searchview(self, textview, flags=0):
        'Return matching textview positions or None'
        result = []
        for y in range(len(textview)):
            testtext = textview[y:]
            for x in range(len(testtext[0])):
                size = self.checkblock([row[x:] for row in testtext], flags)
                if size:
                    found = (x, y, size[0], size[1])
                    if flags & MULTIFIND:
                        result.append(found)
                    else:
                        return found
        return result if result else None

    def search(self, text, flags=0):
        'Return matching text positions or None'
        flags = self.flags | flags
        text = text.split('\n') if type(text) == str else text
        result = []
        for textview, invview in self.mkviews(text, flags):
            found = self.searchview(textview, flags)
            if found:
                if flags & MULTIFIND:
                    result.extend(invview(*f) for f in found)
                else:
                    return invview(*found)
        return result if result else None

    def findall(self, text, flags=0):
        'Return matching text blocks or None'
        flags = self.flags | flags
        strmode = (type(text) == str)
        text = text.split('\n') if type(text) == str else text
        result = []
        positions = self.search(text, flags)
        if not positions:
            return [] if flags & MULTIFIND else None
        if not flags & MULTIFIND:
            positions = [positions]
        for x0,y0,w,h in positions:
            if y0+h >= 0:
                lines = text[y0 : y0+h : cmp(h,0)]
            else:
                lines = text[y0 : : cmp(h,0)]
            if x0+w >= 0:
                block = [row[x0 : x0+w : cmp(w,0)] for row in lines]
            else:
                block = [row[x0 : : cmp(w,0)] for row in lines]
            result.append(block)
        if strmode:
            result = ['\n'.join(rows) for rows in result]
        if flags & MULTIFIND:
            return result
        else:
            return result[0]

    def match(self, text, flags=0):
        'Return True if whole text matches the patterns'
        flags = self.flags | flags
        text = text.split('\n') if type(text) == str else text
        for textview, invview in self.mkviews(text, flags):
            size = self.checkblock(textview, flags)
            if size:
                return True
        return False

Якщо проблема з алмазами була не ясна, алмази можуть бути будь-якого розміру, а не лише 0, 1 або 2. Редагувати: я редагував специфікацію, щоб зробити це більш зрозумілим.
PhiNotPi

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

Так, це добре.
PhiNotPi

14

Грім , Хаскелл

Вступ

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

EDIT: виправлено хрести (завдяки DLosc за виявлення помилки) та додано видобуток алмазів.

EDIT2: Додано класи символів, натхненні класами Slip. Також змінили синтаксис прапорів опцій, покращили аналізатор виразів та додали проблему без Q.

EDIT3: Реалізовано обмеження розміру та додано проблему порталів Nether.

Використання

Програма Grime називається граматикою , а правильне розширення файлу для граматики є .gr, хоча це не застосовується. Граматика оцінюється як

runhaskell grime.hs [options] grammarfile matrixfile

де matrixfileфайл, що містить матрицю символів. Наприклад, граматика цифр буде оцінена як

runhaskell grime.hs digits.gr digit-matrix

Для додаткової швидкості рекомендую компілювати файл з оптимізаціями:

ghc -O2 grime.hs
./grime digits.gr digit-matrix

За замовчуванням інтерпретатор виводить перше знайдене відповідність, але це можна контролювати за допомогою прапорців опцій:

  • -e: відповідати лише всій матриці, друкувати 1за відповідність і 0не відповідати.
  • -n: вивести кількість збігів або всю матрицю, якщо -eвона також задана.
  • -a: друк усіх збігів.
  • -p: друкуйте також позиції сірників у форматі (x,y,w,h).
  • -s: не друкуйте сірники самі.
  • -d: друкувати інформацію про налагодження.

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

Синтаксис і семантика

Граматика Grime складається з одного або декількох визначень , кожне в окремому рядку. Кожен з них визначає значення нетерміналу , і один з них повинен визначати анонімний нетермінал верхнього рівня . Синтаксис визначення - N=Eабо E, де Nвелика літера і Eє виразом .

Вирази будуються так.

  • Будь-який символ уникав \відповідності будь-якому 1x1прямокутнику, що містить цей символ.
  • . відповідає будь-якому одному символу.
  • $відповідає 1x1прямокутнику поза матрицею символів.
  • _ відповідає будь-якому прямокутнику нульової ширини або висоти.
  • Заздалегідь визначені групи символів - digit, uppercase, lowercase, alphabetic, alfa numeric та symbol.
  • Нові класи символів можна визначити за синтаксисом [a-prt-w,d-gu]. Літери зліва включаються, а праворуч виключаються, так що це точно відповідає літерам abchijklmnoprtvw. Якщо ліва сторона порожня, вона містить усі символи. Кома може бути опущена, якщо права сторона порожня. Персонажі [],-\повинні бути уникнуті за допомогою \.
  • Немає великої літери - це нетермінальний знак, який відповідає викладеному йому виразом.
  • Якщо Pі Qє виразами, то PQце просто їх горизонтальне з'єднання і P/Qє їх вертикальним конкатенацією, Pзверху.
  • P+є однією або декількома Ps, вирівняними по горизонталі, і P/+однакові, вирівняні вертикально.
  • Булеві операції позначені P|Q, P&Qі P!.
  • P?це скорочення для P|_, P*для P+|_і P/*для P/+|_.
  • P#відповідає будь-якому прямокутнику, який містить відповідність P.
  • P{a-b,c-d}, Де abcdневід'ємні цілі числа, є обмеження розміру на P. Якщо Pце клас символів, то вираз відповідає будь-якому mxnпрямокутнику, що містить лише ті символи, за умови, що mце між aі bвключно, і nзнаходиться між cі dвключно. В інших випадках вираз відповідає будь-якому прямокутнику, який має правильний розмір і який Pтакож відповідає. Якщо aабо cпропущено, вони вважаються такими 0, що є , а якщо bабо dопущені, вони є нескінченними. Якщо дефіс між aі bпропущений, то використовуємо однакове число для обох кінців інтервалу. Якщо цілийc-dчастина опущена, обидві осі обмежені. Для уточнення, {-b}еквівалент рівносильний .{0-b,0-b} і{a-,c}{a-infinity,c-c}

Примітки

Grime дійсно дозволяє парадоксальні визначення, наприклад, A=A!з невизначеною поведінкою. Однак вони не спричинять збоїв або нескінченних циклів.

Grime підтримує не прямокутні входи; рядки просто вирівнюються ліворуч, а проміжки можна зіставити за допомогою $.

Надалі я хотів би реалізувати наступне:

  • Швидше відповідність. Наразі перекладач не враховує того факту, що, наприклад, .може відповідати лише 1x1прямокутникам. Поки він не знаходить відповідності, він намагається впорядкувати всі прямокутники всіх розмірів, миттєво виходячи з ладу для кожного з них.
  • Операції обертання та відображення для задач пошуку слова та планера.
  • Не прямокутні сірники з використанням контекстів , які були б корисні у виклику дошки Boggle. Наприклад, Pv(Q>R)засоби Pз нижчим контекстом ( Qз правильним контекстом R). Він би відповідав L-образним візерункам

    PPP
    PPP
    QQQRRRR
    QQQRRRR
    QQQRRRR
    

Завдання

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

Прямокутник цифр

d{2-}

Це просто: прямокутник цифр розміром не менше 2x2.

Ні q або Q

[,qQ]{4}

Це майже так само просто, як і перше; тепер у нас є більш обмежений розмір і спеціальний клас символів.

Горизонтальне та вертикальне вирівнювання

\#.*\#|\#/./*/\#

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

Виявити квадратні входи

S=.|S./+/.+
e,S

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

Пошук слова в пошуку слова

G=\G
O=\O
L=\L
F=\F
GOLF|FLOG|G/O/L/F|F/L/O/G|G.../.O../..L./...F|...G/..O./.L../F...|F.../.L../..O./...G|...F/..L./.O../G...

Це жахливо, оскільки у Grime немає операцій з обертання чи відображення. Це також надзвичайно повільно, оскільки Гриме не знає, що сірники можуть бути лише розмірами 4x1, 1x4або 4x4.

Проблему з планером можна вирішити аналогічно, але я лінивий це записати.

Нижчі портали

.\X+./\X/+\.{2-22,3-22}\X/+/.\X+.

З оператором обмеження розміру це не так складно. Середня частина \.{2-22,3-22}відповідає будь-якому прямокутнику .правильних розмірів, а потім ми просто додаємо стовпці Xs з обох сторін і обклеюємо рядки Xs з ігнорованими кінцями вгорі та внизу.

Узгодження хрестів

E=\.+/+
F=\#+/+
EFE/F/EFE&(E/F/E)F(E/F/E)

Ми маємо тут сполучення (логічне І) двох виразів. Нетермінал Eвідповідає не порожньому прямокутнику .s, а Fнепустому прямокутнику #s. Ліва сторона сполучника відповідає прямокутникам типу

...####..
...####..
...####..
#########
#########
.....##..
.....##..

де ми маємо EFEна вершині, потім F, і потім EFEзнову. Права сторона відповідає транспортам цих, тому ми отримуємо саме хрести.

Видобуток алмазів

C=./+
T=\X|CTC/\/.+\\
B=\X|\\.+\//CBC
CTC/\X.+\X/CBC

Нетермінал C- це стенограма для будь-якого 1xnстовпця. Верхня половина алмазу узгоджена T: це або одинарний X, або інший, Tоточений стовпчиком з обох сторін, і ряд /[something]\нижче цього. Bаналогічно відповідає нижній частині алмазу, а нетермінал верхнього рівня - це лише ряд форми X[something]Xміж верхньою і нижньою половиною.

Пошук шахових дощок

(\#\#|\#/\#|\_\_|\_/\_)#!&[#_]{3-}

Права сторона [#_]{3-}відповідає будь-якому 3x3або більшому прямокутнику #s і _s, тоді як ліва гарантує, що він не містить двох сусідніх #s або _s.

Перевірка шахових дощок

e,(\#\#|\#/\#|\_\_|\_/\_)#!&[#_]+/+

Це в основному те саме, що вище, за винятком того, що ми можемо відповідати будь-якому не порожньому прямокутнику, але потрібно використовувати eпрапор для всієї перевірки вводу.

Перевірте синтаксис прелюдії

A=[,()]/*
P=A*|P(A/\(/A)P(A/\)/A)P
e,P

Це, мабуть, найцікавіша граматика поки що. Нетермінальний Aзбігається з будь-яким стовпцем, що не містить (або ), і Pвідповідає або деякій кількості As, або двом збірним дужкам, між якими і поза ними є більше Ps.


@DLosc Виправлено, дякую, що знайшли помилку!
Згарб

Було б \#(.*|./*)\#працювати?
seequ

@Sieg Для вирівнювання? На жаль, ні, тому що це буде розбиратися як "один #зліва, потім рядок або стовпець нічого, потім один #праворуч". Мені потрібно вказати, що #s вертикально приєднані до стовпця за допомогою косої риски /.
Згарб

10

TMARL

Мова відповідності шаблонів та мова розпізнавання

Опис

Мій перекладач займає 24 К символів ( фрагменти коду містять символи? ), Тому повний опис можна знайти тут .

Найкраща частина: перекладач знаходиться у Javascript, тобто ви можете спробувати прямо тут!

А для проблем:

№1 - Пошук шахових дощок

$#_#
a
$_#_
bvacvbS5&(avcS5)G0G2P

&додає пошукові запити. В кінці G2 отримує 3-й елемент у елементі відповідності, фактичний збіг. Перші 2 елементи - це координати x і y (на основі 1, а не 0).

№3 - Виявлення прямокутника цифр

$DD
$DD
S1G2P

Я думаю, що це досить просто.

№4 - Пошук слова в пошуку слова

$GO\LF
a
$G
$*O
$**\L
$***F
S6&(aS6)G0G2P

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

№ 5 - Виявлення квадратних входів

IL-(IG0L)!P

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

№6 - Знайдіть планери в грі життя

$## 
$# #
$# 
a
$ ##
$## 
$  #
bS6&(bMS6)&(aS6)&(aMS6)G0G2P

Нарешті, використання для дзеркала!

№ 12 - Уникайте букви Q

$[^Qq]
~4*4S1G2P

S1, тому що потрібно лише 1 матч.

Деякі складніші я зроблю пізніше.

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