Haskell , 1080 1033 octets
;
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; ; ;
Essayez-le en ligne!
Explication
Cela a été une tâche très intéressante pour Haskell.
Parité
Pour commencer, nous avons besoin d'un moyen de déterminer si un caractère a un point de code pair ou impair. La façon normale de le faire est d'obtenir le point de code et de le modifier par 2. Cependant, comme vous le savez peut-être, obtenir le point de code d'un caractère nécessite une importation qui, en raison de la restriction de la source, signifie qu'il ne peut pas être utilisé. Un Haskeller plus expérimenté penserait à utiliser la récursivité. Char
font partie de la Enum
classe de type afin que nous puissions obtenir leurs prédécesseurs et successeurs. Cependant pred
, ils succ
sont également inutilisables car ils n'alternent pas la parité des octets.
Donc, cela nous laisse assez coincés, nous ne pouvons pratiquement pas faire de manipulation avec les caractères. La solution est de tout coder en dur. Nous pouvons représenter (la plupart) même les caractères comme des littéraux, les probabilités avec lesquelles nous avons des problèmes parce qu'ils '
sont étranges, donc ils ne peuvent pas être à côté du caractère lui-même, ce qui rend le littéral impossible d'exprimer la plupart des caractères impairs. Nous codons donc en dur tous les octets pairs, puis ajoutons un catch all pour les octets impairs à la fin.
Les octets problématiques
Vous pouvez remarquer qu'il existe certains octets pairs pour lesquels des littéraux ne peuvent pas être créés en les encapsulant entre guillemets simples. Ce sont les non imprimables, les nouvelles lignes et \
. Nous n'avons pas à nous soucier des non imprimables, tant que nous n'en utilisons aucun, nous n'avons pas besoin de le vérifier. En fait, nous pouvons toujours utiliser d'étranges non imprimables, comme tab, je n'en ai tout simplement pas besoin. Le retour à la ligne peut être ignoré car il sera de toute façon supprimé du programme. (Nous pourrions inclure la nouvelle ligne, car son point de code est plutôt pratique, mais nous n'en avons pas besoin). Cela laisse \
, a maintenant \
le point de code 92, qui est commodément un nombre impair suivi d'un nombre pair, \92
alterne donc entre les evens et les cotes donc le littéral'\92'
est parfaitement valable. Plus tard, lorsque nous aurons besoin de représenter une nouvelle ligne, nous remarquerons qu'elle a heureusement cette même propriété '\10'
.
Problèmes d'espacement
Maintenant, pour commencer à écrire du code réel, nous devons pouvoir mettre un nombre important de caractères sur une seule ligne. Pour ce faire, j'ai écrit la casquette:
;
f=
g
ij=f
a =hi
hi = g
hij= ij
La casquette ne fait rien d'autre que d'être Haskell valide. J'avais initialement espéré faire des définitions qui nous aideraient dans le code plus tard, mais ce n'est pas le cas. Il existe également des moyens plus simples de créer un plafond, par exemple des espaces et des points-virgules, mais ils n'économisent pas d'octets de cette manière, je n'ai donc pas pris la peine de le modifier.
Hardcoder
Alors maintenant que j'ai assez d'espace sur une ligne, je commence à coder en dur les valeurs. C'est surtout assez ennuyeux, mais il y a quelques choses intéressantes. Pour une fois que les lignes commencent à devenir encore plus longues, nous pouvons utiliser ;
pour mettre plusieurs déclarations sur une ligne, ce qui nous permet d'économiser une tonne d'octets.
La seconde est que, comme nous ne pouvons pas toujours commencer une ligne avec un de g
temps en temps, nous devons indenter un peu les lignes. Maintenant, Haskell se soucie vraiment de l'indentation, donc il s'en plaindra. Cependant, si la dernière ligne avant la ligne en retrait se termine par un point-virgule, cela sera autorisé. Pourquoi? Je n'ai pas le moindre, mais ça marche. Il suffit donc de se rappeler de mettre les points-virgules à la fin des lignes.
Blocs fonctionnels
Une fois le hardcoder terminé, la navigation se fait en douceur jusqu'à la fin du programme. Nous devons construire quelques fonctions simples. Je construis d'abord une version de drop
, appelée i
. i
est différent de ce drop
que si nous essayons de passer au-delà de la fin de la chaîne, il retourne simplement "y"
. i
est différent de drop également en ce que s'il tente de supprimer une nouvelle ligne, il reviendra "y"
, ceux-ci seront utiles car plus tard, lorsque nous vérifierons que le programme est un triangle, cela nous permettra de revenir False
lorsque la dernière ligne n'est pas terminée, ou lorsque une ligne se termine tôt.
Ensuite, nous avons k
qui vérifie en fait qu'une chaîne est triangulaire. k
est assez simple, il faut un nombre et une chaîne . Si est vide, il revient . Si la chaîne commence par une nouvelle ligne, elle supprime la nouvelle ligne et caractères du premier plan. Il rappelle ensuite avec et la nouvelle chaîne. Si la chaîne ne commence pas par une nouvelle ligne, elle retourne .s s n n + 1nssTrue
nk
n+1False
Nous faisons ensuite un alias pour k
, m
. m
est juste k
avec 1
dans le premier argument, et une nouvelle ligne est ajoutée au second argument.
Ensuite, nous avons o
. o
prend un nombre et une chaîne. Il détermine si les octets de chaîne (ignorant les nouvelles lignes) alternent en parité (en utilisant notre g
) en commençant par le numéro d'entrée.
Enfin, nous avons s
qui fonctionne o
avec les deux 1
et 0
, si l'un ou l'autre réussit, il s'en remet m
. S'il échoue, il revient simplement False
. C'est la fonction que nous voulons. Il détermine que l'entrée est triangulaire et alternée.