Я думал, что воспользуюсь этой возможностью, чтобы показать новую функцию 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.