Это, очевидно, правильный язык для задачи. : ^ D
s:({c<L>}{c<R>}0[(<R> <L>)(<L> <R>)_?])%{30}
c:0 *$
Соответствует всему вводу, если это допустимая змея; не соответствует, если это не так. Попробуй это здесь!
объяснение
SnakeEx - это двумерный язык сопоставления с образцом . Программа состоит из списка определений «змей», которые ползут по вводимым совпадающим символам, меняют направления и порождают других змей. В нашей программе мы определяем двух змей, sи c.
Начнем с cтого, что проще. Это определение 0 *$, которое должно быть вполне читабельным, если вы знаете регулярное выражение: match 0, за которым следует ноль или более пробелов, за которыми следует край сетки. Основной улов здесь: это сопоставление может продолжаться в любом направлении. Мы будем использовать cкак змею вверх, так и вниз, чтобы убедиться, что 0в каждом столбце нет лишних s.
Теперь для главной змеи, s . Он принимает форму (...)%{30}, что означает «сопоставить содержимое скобок 30 раз» - один раз для каждого 0в змее. Все идет нормально. Что входит в круглые скобки?
{c<L>}
Это порождает новый c змею, повернутую влево на 90 градусов. Направление относительно направления sзмеи, поэтому новая змея движется к вершине сетки (главная змея движется вправо). В cзмее проверяет , что текущая ячейка сетки представляет собой 0и что каждая клетка над ним пространство. Если это не удается, весь матч не удается. Если это удастся, мы продолжим с
{c<R>}
который делает то же самое, только повернул направо (к нижней части сетки).
Обратите внимание, что эти порождения не влияют на положение указателя совпадения в главной змее. Они немного похожи на взглядов в регулярных выражениях. (Может быть, здесь мы могли бы назвать их «lookb Кроме»?) Итак, после проверки, что мы указываем на0 а остальная часть столбца содержит только пробелы, нам нужно на самом деле соответствовать 0:
0
Теперь указатель совпадения находится на символе справа от 0 . Нам нужно проверить три разных варианта: змея наклонена вниз, змея наклонена вверх, или змея идет прямо. Для этого мы можем использовать выражение OR:
[...]
Внутри нашего OR у нас есть три возможности:
(<R> <L>)
Поверните направо, найдите пробел и снова поверните налево (углы змеи вниз).
(<L> <R>)
Поверните налево, найдите пробел и снова поверните направо (змея наклонена вверх).
_?
Совпадение ноль или подчеркивание. Поскольку на входе нет подчеркиваний, это всегда будет пустое совпадение (змея идет прямо).
После сопоставления с одним из трех приведенных выше вариантов указатель совпадения должен указывать на 0следующий столбец, готовый снова сопоставить выражение в скобках.