2.}<@>%?<{>$"/\M!8;
Lisible:
2 . }
< @ > %
? < { > $
" / \ M
! 8 ;
Essayez-le en ligne!
Cela peut probablement être joué par un octet ou deux, mais cela pourrait nécessiter une mise en page vraiment ingénieuse, qui pourrait être plus facilement trouvée via la force brute (même si cela peut prendre un certain temps pour le trouver).
Explication de haut niveau
Le programme suit principalement ce pseudocode:
while (read number is not zero)
{
if (number is even)
print number;
}
Ce qui abuse de la façon dont Hexagony essaie de lire un nombre une fois que STDIN est vide (il renvoie un zéro). Un grand merci à Martin pour son aide dans l'élaboration de cette approche.
Explication complète
Je n'ai pas encore tripoté Mono pour faire tourner l' IDE ésotérique fantastique de Timwi , alors je me suis appuyé sur Martin pour me fournir de jolies photos utiles!
Tout d'abord, une petite introduction au flux de contrôle de base en hexagonie. Le premier pointeur d'instruction (IP), qui est le seul utilisé dans ce programme, commence en haut à gauche du code source hexagonal et commence à se déplacer vers la droite. Chaque fois que l'IP quitte le bord de l'hexagone, il déplace les side_length - 1
rangées vers le milieu de l'hexagone. Étant donné que ce programme utilise un côté hexagonal de trois côtés, l'IP se déplacera toujours de deux lignes lorsque cela se produit. La seule exception est si elle se déplace hors de la ligne du milieu, où elle se déplace conditionnellement vers le haut ou le bas de l'hexagone, en fonction de la valeur du bord de mémoire actuel.
Maintenant, un peu sur les conditions. Les seules conditions dans les Hexagony de flux de commande sont >
, <
et le bord intermédiaire de l'hexagone. Ils suivent tous une règle constante: si la valeur sur le front de mémoire actuel est nulle ou si le flux de contrôle négatif se déplace vers la gauche et s'il est positif, le contrôle circule vers la droite. Les crochets supérieurs et inférieurs redirigent l'IP à des angles de soixante degrés, tandis que le bord de l'hexagone contrôle la ligne sur laquelle l'IP saute.
Hexagony a également un modèle de mémoire spécial, où toutes les données sont stockées sur les bords d'une grille hexagonale infinie. Ce programme n'utilise que trois arêtes: une pour stocker deux, une pour le nombre actuellement lu et une pour le nombre modulo deux. Cela ressemble à quelque chose comme:
Mod \ / Input
|
2
Je ne vais pas expliquer avec soin où nous sommes en mémoire à chaque moment pendant l'explication du programme, alors revenez ici si vous êtes confus par où nous sommes en mémoire.
Avec tout cela à l'écart, l'explication réelle peut commencer. D'abord, nous remplissons le bord "2" en mémoire avec un 2, puis nous exécutons un no-op et déplaçons le pointeur de mémoire vers la droite ( 2.}
).
Ensuite, nous commençons la boucle du programme principal. Nous lisons le premier nombre de STDIN puis nous frappons un conditionnel ( ?<
). S'il n'y a plus de chiffres dans STDIN, cela lit un zéro dans le bord de mémoire actuel, nous tournons donc à gauche sur le @
, ce qui termine le programme. Sinon, nous rebondissons sur un miroir, déplaçons le pointeur de mémoire vers l'arrière et vers la gauche, enroulons autour de l'hexagone pour calculer le reste de la division de l'entrée par 2, puis frappons un autre conditionnel ( /"%>
).
Si le reste était un (c.-à-d. Que le nombre était impair), nous tournons à droite en suivant le chemin bleu ci-dessus en commençant par exécuter à nouveau le no-op, puis nous enroulons autour du bas de l'hexagone, multiplions le bord actuel par 10, puis ajoutons huit, rebondissez sur quelques miroirs, effectuez la même multiplication et addition à nouveau, en obtenant 188 sur le bord actuel, en revenant au sommet de l'hexagone, en exécutant à nouveau le no-op et en terminant enfin le programme ( .8/\8.@
). Ce résultat alambiqué était un heureux accident, j'avais à l'origine écrit un peu de logique beaucoup plus simple, mais j'ai remarqué que je pouvais le supprimer en faveur du no-op, ce que je pensais être plus dans l'esprit d'Hexagony.
Si le reste était nul, nous tournerons à gauche en suivant le chemin rouge ci-dessus. Cela nous amène à déplacer le pointeur de mémoire vers la gauche, puis à y imprimer la valeur (la valeur d'entrée) sous forme de nombre. Le miroir que nous rencontrons agit comme un no-op en raison de la direction dans laquelle nous nous déplaçons ( {/!
). Ensuite, nous frappons le bord de l'hexagone qui agit comme un conditionnel avec un seul résultat, car la valeur d'entrée d'avant a déjà été testée pour être positive, nous nous déplaçons donc toujours vers la droite (si vous vous imaginez face à la direction de l'IP) . Nous multiplions ensuite l'entrée par 10 et en ajoutons deux, seulement pour changer de direction, envelopper et écraser la nouvelle valeur avec la valeur ascii de la lettre majuscule M, 77. Ensuite, nous frappons quelques miroirs et sortons sur le bord du milieu de l'hexagone avec un trampoline (2<M\>$
). Puisque 77 est positif, nous nous déplaçons à droite vers le bas de l'hexagone et à cause du trampoline sautez la première instruction ( !
). Nous multiplions ensuite le bord de mémoire actuel par 10 et ajoutons 8, obtenant 778. Nous sortons ensuite cette valeur mod 256 (10) sous forme de caractère ASCII, qui se trouve être une nouvelle ligne. Enfin, nous quittons l'hexagone et revenons au premier ?
qui remplace le 778 avec la prochaine valeur d'entrée.