Я думал, что воспользуюсь этой возможностью, чтобы показать новую функцию Retina: многоступенчатые петли. Это должно значительно сократить многие задачи (особенно условная замена).
ii
-
+`(.)\1|0
(.)-|(\d)(\d)
-$1$3$2
12
i3
23
i1
31
i2
)`(\d)i
i$1
^\D*$
$&0
Retina - это мой собственный язык программирования на основе регулярных выражений. Исходный код может быть сгруппирован по этапам: каждый этап состоит из двух строк, где первая содержит регулярное выражение (и, возможно, некоторую конфигурацию), а вторая строка является строкой замены. Затем этапы применяются к STDIN по порядку, а окончательный результат выводится на STDOUT.
Вы можете использовать вышеперечисленное непосредственно в качестве исходного файла с параметром -s
командной строки. Тем не менее, я не считаю переключение, потому что вы также можете просто поместить каждую строку в отдельный файл (тогда вы потеряете 15 байтов для новых строк, но добавите +15 для дополнительных файлов).
объяснение
Новым в этом решении является )
предпоследняя стадия. Это закрывает многоступенчатый цикл. Нет соответствия (
, что означает, что цикл неявно начинается на первом этапе. Следовательно, первые 7 этапов повторяются до тех пор, пока полный проход через все 7 из них не перестанет изменять результат. Эти 7 этапов просто выполняют различные преобразования, которые постепенно уменьшают количество матриц в строке и объединяют фазы. Как только мы достигаем конечного результата, ни один из семи шаблонов больше не совпадает, и цикл заканчивается. После этого мы добавляем 0, если в результате еще нет цифры (поскольку на предыдущих этапах просто отбрасываются все идентификаторы, включая результат).
Вот что делают отдельные этапы:
ii
-
Объединяет все пары i
в, -
чтобы уменьшить фазу символов.
+`(.)\1|0
<empty>
Теперь, если осталось два последовательных идентичных символа, это либо одна, --
либо две идентичные матрицы. В любом случае, умножение их дает идентичность. Но нам не нужны идентификаторы, поэтому мы просто удаляем их все, а также явные идентификаторы 0
. Этот этап повторяется сам по себе, +
пока результат не перестанет меняться. Это гарантирует, что такие вещи, как, 123321
будут решены полностью, так что следующий шаг может предполагать, что все пары цифр различны.
(.)-|(\d)(\d)
-$1$3$2
На самом деле это две отдельные трансформации в одну (для гольфа). Обратите внимание, что если первая альтернатива совпадает $2
и $3
пуста, а вторая $1
- пуста. Так что это можно разложить на эти два шага:
(\d)(\d)
-$2$1
Это просто меняет все пары цифр и добавляет знак минус. Так как мы удалили все 0
с и все одинаковые пары, то это будет соответствовать только 12
, 23
, 31
, 21
, 32
, 13
. Этот шаг может показаться странным, но он позволяет мне проверить только половину этих случаев позже, потому что те, которые я не могу обработать, будут заменены здесь на следующей итерации.
Другая часть вышеупомянутой стадии была:
(.)-
-$1
Это постепенно перемещает -
знаки полностью влево (одна позиция на итерацию). Я делаю это так, что в конечном итоге они все рядом и решаются на более раннем этапе.
12
i3
23
i1
31
i2
Эти три этапа теперь просто разрешают три пары продуктов. Как я уже говорил выше, это отловит только половину соответствующих случаев, но другая половина будет учтена на следующей итерации, после того как на предыдущем шаге поменялись местами все пары.
)`(\d)i
i$1
Это последний этап цикла. Это похоже на тот, который сдвигается -
влево, за исключением i
. Основное отличие состоит в том, что этот обмен i
только с цифрами. Если бы я использовал (.)i
тогда, в случаях, когда я получаю a -i
или i-
два, меняли местами бесконечно, и программа не заканчивалась. Так что это только меняет их справа от -
знаков. Этого достаточно - пока все -
и i
появляются вместе в какой-то момент, они могут быть решены правильно.
^\D*$
$&0
Последний шаг (вне цикла). Помните, что мы всегда удаляли все идентификаторы, поэтому, если результат фактически является идентификатором (умноженным на фазу), у нас больше не будет требуемой цифры в выводе, поэтому мы добавляем ее обратно.
В качестве примера, вот все промежуточные формы 0223202330203313021301011023230323
(этапы пропуска, которые не вносят никаких изменений):
0223202330203313021301011023230323
321321312 # Remove identities
-23-31-12-132 # Swap all pairs
-23-31-i3-132 # Resolve 12
-i1-31-i3-132 # Resolve 23
-i1-i2-i3-132 # Resolve 31
-i-1i-2i-3-312 # Move - to the left and swap pairs
-i-1i-2i-3-3i3 # Resolve 12
-i-i1-i2-3-i33 # Move i to the left
-i-i1-i2-3-i # Remove identities
--ii-1i-2-3i # Move - to the left
--ii-i1-2-i3 # Move i to the left
----i1-2-i3 # Resolve ii
i1-2-i3 # Remove identities
i-1-2i3 # Move - to the left
i-1-i23 # Move i to the left
-i-1i-32 # Move - to the left and swap pairs
-i-i1-32 # Move i to the left
--ii-1-23 # Move - to the left and swap pairs
--ii-1-i1 # Resolve 23
----1-i1 # Resolve ii
1-i1 # Remove identities
-1i1 # Move - to the left
-i11 # Move i to the left
-i # Remove identities. Now the loop can't change this any longer.
-i0 # Fix the result by adding in the 0.