Haskell , 1080 1033 байта
;
f=
g
ij=f
a =hi
hi = g
hij= ij
g ' ' =0
g '"' =0;
g '$' =0;
g '&' =0-0
g '(' =0-0-0
g '*' =0-0-0;
g ',' =0-0-0;
g '.' =0-0-0-0
g '0' =0-0-0-0-0
g '2' =0-0-0-0-0;
g '4' =0-0-0-0-0;
g '6' =0; g '8' =0
g ':' =0; g '<' =0-0
g '>' =0; g '@' =0-0;
g 'B' =0; g 'D' =0-0;
g 'F' =0; g 'H' =0-0-0
g 'J' =0; g 'L' =0-0-0-0
g 'N' =0; g 'P' =0-0-0-0;
g 'R' =0; g 'T' =0-0-0-0;
g 'V' =0; g 'X' =0-0-0-0-0
g 'Z' =0; g '^' =0; g '`' =0
g 'b' =0; g 'd' =0; g 'f' =0;
g 'h' =0; g 'j' =0; g 'l' =0;
g 'n' =0; g 'p' =0; g 'r' =0-0
g 't' =0; g 'v' =0; g 'x' =0-0-0
g 'z' =0; g '\92' =0-0; g '|' =0;
g '~' =0; g y = 1 ;z=0; i(-0)z=z;
i m('\10':y ) ="y"; ; ; ; ; ; ; ;
i m(mnmnmnmnm:y ) = i(m - 1 ) y ; ;
i k m ="y"; ; k i [ ] =01<1010101010;
k m('\10':y ) = k(m + 1 )(i m y ) ; ;
k m y =01>10; m o = k 1$'\10':o ; ; ;
o i('\10':y ) = o i y ; ; ; ; ; ; ; ; ;
o i(k:y )|g k<i = o(1 - i ) y ; ; ; ; ; ;
o i(k:y )|g k>i = o(1 - i ) y ; ; ; ; ; ;
o i [ ] =01<10; o i y =01>10;v=01>10101010
s y|o 1 y = m y|o(-0) y = m y ; s y =v; ; ;
Попробуйте онлайн!
объяснение
Это было довольно интересное задание для Haskell.
паритет
Для начала нам нужен способ определить, имеет ли символ четную или нечетную кодовую точку. Обычный способ сделать это - получить кодовую точку и изменить ее на 2. Однако, как известно, получение кодовой точки символа требует импорта, что из-за ограничения исходного кода означает, что это невозможно используемый. Более опытный Хаскеллер подумал бы использовать рекурсию. Char
Это часть класса Enum
типов, поэтому мы можем получить их предшественников и преемников. Однако pred
и succ
они также непригодны для использования, потому что они не чередуют четность байтов.
Так что это оставляет нас в тупике, мы почти не можем манипулировать символами. Решение этой проблемы - жестко закодировать все. Мы можем представить (большинство) четных символов как литералы, с которыми мы сталкиваемся с проблемами, потому что они '
странные, поэтому он не может быть рядом с самим символом, что делает литерал невозможным для выражения большинства нечетных символов. Таким образом, мы жестко кодируем все четные байты, а затем добавляем перехват всех нечетных байтов в конце.
Проблема в байтах
Вы можете заметить, что есть некоторые четные байты, для которых литералы нельзя создать, заключив их в одинарные кавычки. Это непечатные, новые строки и \
. Нам не нужно беспокоиться о непечатаемых печатях, поскольку, пока мы не используем ни один из них, нам не нужно проверять. На самом деле мы все еще можем использовать странные непечатаемые шрифты, такие как tab, мне просто не нужно. Новая строка может быть проигнорирована, потому что она все равно будет удалена из программы. (Мы могли бы включить символ новой строки, потому что его код довольно удобен, но нам это не нужно). Это оставляет \
, теперь \
имеет кодовую точку 92, которая удобно является нечетным числом, за которым следует четное число, так что \92
чередуется между четными и нечетными числами, таким образом, литералом'\92'
совершенно верно. Позже, когда нам нужно будет представить символ новой строки, мы заметим, что он, к счастью, обладает тем же свойством '\10'
.
Пространственные проблемы
Теперь, чтобы начать писать настоящий код, мы должны иметь возможность поместить значительное количество символов в одну строку. Для этого я написал шапку:
;
f=
g
ij=f
a =hi
hi = g
hij= ij
Кепка не делает ничего, кроме как быть действительным Haskell. Сначала я надеялся дать определения, которые позже помогут нам в коде, но это не помогло. Есть также более простые способы сделать ограничение, например, пробел и точку с запятой, но они не сохраняют байты таким образом, поэтому я не потрудился изменить его.
Hardcoder
Теперь, когда у меня достаточно места в строке, я начинаю жестко кодировать значения. Это в основном довольно скучно, но есть несколько интересных вещей. Один раз, когда строки становятся еще длиннее, мы можем использовать ;
для размещения нескольких объявлений в строке, что экономит нам тонну байтов.
Во-вторых, так как мы не всегда можем начинать строку с g
символа так часто, нам приходится немного отступать от строки. Теперь Haskell действительно заботится об отступах, поэтому он будет жаловаться на это. Однако, если последняя строка перед отступом заканчивается точкой с запятой, это разрешит это. Почему? У меня нет слабых, но это работает. Таким образом, мы просто должны помнить, чтобы поставить точку с запятой в конце строки.
Функциональные блоки
Как только хардкодер готов, он плавно подходит к концу программы. Нам нужно построить несколько простых функций. Сначала я создаю версию drop
, называемую i
. i
отличается от того, drop
что если мы пытаемся пропустить конец строки, он просто возвращается "y"
. i
отличается от drop также тем, что, если он попытается удалить новую строку, он вернется. "y"
Это будет полезно, потому что позже, когда мы проверяем, что программа является треугольником, это позволит нам вернуться, False
когда последняя строка не завершена или когда линия заканчивается рано.
k
k
NssTrue
Nk
n + 1False
Затем сделать псевдоним k
, m
. m
просто k
с 1
первым аргументом, и символом новой строки добавляется второй аргумент.
Далее у нас есть o
. o
занимает число и строку. Он определяет, чередуются ли строковые байты (игнорируя символы новой строки) по четности (используя нашу g
), начиная с входного числа.
Наконец, у нас есть, s
который работает o
с обоими 1
и 0
, если любой из них удастся, это откладывает m
. Если это терпит неудачу оба, это только возвращается False
. Это функция, которую мы хотим. Он определяет, что вход является треугольным и чередующимся.