Haskell , 1080 1033 bytes
;
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; ; ;
Pruébalo en línea!
Explicación
Esta ha sido una tarea bastante interesante para Haskell.
Paridad
Para comenzar, necesitamos alguna forma de determinar si un personaje tiene un punto de código par o impar. La forma normal en que se puede hacer esto es obtener el punto de código y modificarlo en 2. Sin embargo, como se puede saber, obtener el punto de código de un personaje requiere una importación, lo que debido a la restricción de origen significa que no puede ser usado. Un Haskeller más experimentado pensaría usar la recursividad. Char's son parte de la Enumclase de tipos para que podamos obtener sus predecesores y sucesores. Sin embargo pred, y succtambién son tanto inutilizable porque no hacen byte de paridad alternativo.
Esto nos deja bastante atascados, prácticamente no podemos hacer ninguna manipulación con los caracteres. La solución a esto es codificar todo. Podemos representar (la mayoría) caracteres pares como literales, probabilidades con las que tenemos problemas porque 'es extraño, por lo que no puede estar al lado del personaje en sí, haciendo que el literal sea imposible de expresar la mayoría de los caracteres impares. Así que codificamos todos los bytes pares y luego agregamos un catch all para los bytes impares al final.
El problema Bytes
Puede notar que hay algunos bytes pares para los que no se pueden hacer literales envolviéndolos entre comillas simples. Son los no imprimibles, las nuevas líneas y \. No debemos preocuparnos por los no imprimibles, ya que siempre que no usemos ninguno de ellos no necesitamos verificarlo. De hecho, todavía podemos usar extrables no imprimibles, como tab, simplemente no termino necesitando. Newline puede ignorarse sabiamente porque de todos modos será recortado del programa. (Podríamos incluir nueva línea, porque su punto de código es bastante conveniente, pero no es necesario). Esto deja \, ahora \tiene el punto de código 92, que convenientemente es un número impar seguido de un número par, por lo que \92alterna entre pares e impares , por lo tanto, el literal'\92'Es perfectamente válido. Más adelante, cuando necesitemos representar una nueva línea, notaremos que, afortunadamente, tiene esta misma propiedad '\10'.
Problemas de espacio
Ahora, para comenzar a escribir el código real, necesitamos poder colocar una cantidad considerable de caracteres en una sola línea. Para hacer esto escribí el gorro:
;
f=
g
ij=f
a =hi
hi = g
hij= ij
La gorra no hace nada excepto ser válida Haskell. Inicialmente esperaba hacer definiciones que nos ayudaran en el código más tarde, pero no fue así. También hay formas más fáciles de hacer el límite, por ejemplo, espacios en blanco y punto y coma, pero no guardan bytes de esta manera, así que no me he molestado en cambiarlo.
Codificador duro
Entonces, ahora que tengo suficiente espacio en una línea, comienzo a codificar valores. Esto es bastante aburrido, pero hay algunas cosas de interés. Por una vez, las líneas comienzan a alargarse aún más, podemos usar ;para poner varias declaraciones en una línea, lo que nos ahorra una tonelada de bytes.
La segunda es que, dado que no siempre podemos comenzar una línea con una gfrecuencia cada tanto, debemos sangrar un poco las líneas. Ahora Haskell realmente se preocupa por la sangría, por lo que se quejará de esto. Sin embargo, si la última línea antes de la línea con sangría termina en punto y coma, lo permitirá. ¿Por qué? No tengo nada, pero funciona. Así que solo tenemos que recordar poner los puntos y comas al final de las líneas.
Bloques de construcción de funciones
Una vez que el hardcoder está listo, es fácil navegar hasta el final del programa. Necesitamos construir algunas funciones simples. Primero construyo una versión de drop, llamada i. ies diferente de dropeso si intentamos pasar más allá del final de la cadena, simplemente regresa "y". ies diferente de soltar también en que si intenta soltar una nueva línea, volverá "y". Esto será útil porque más tarde, cuando verifiquemos que el programa es un triángulo, nos permitirá volver Falsecuando la última línea no esté completa, o cuando una línea termina temprano.
kknortessTruenortekn + 1False
A continuación hacemos un alias para k, m. mes solo kcon 1en el primer argumento, y una nueva línea antepuesta al segundo argumento.
A continuación tenemos o. otoma un número y una cadena. Determina si los bytes de cadena (ignorando las nuevas líneas) se alternan en paridad (usando nuestro g) comenzando con el número de entrada.
Por último, tenemos scuál funciona ocon ambos 1y 0, si alguno tiene éxito, difiere m. Si falla ambos, simplemente regresa False. Esta es la función que queremos. Determina que la entrada es triangular y alterna.