Le but de ce défi est de produire (éventuellement) tous les programmes d'arrêt possibles dans la langue de votre choix. Au début, cela peut sembler impossible, mais vous pouvez le faire avec un choix très attentif de l'ordre d'exécution.
Voici un diagramme ASCII pour illustrer cela. Laissez les colonnes représenter une numérotation de chaque programme possible (chaque programme est un nombre fini de symboles d'un alphabet fini). Que chaque ligne représente une étape singulière dans l'exécution de ce programme. An X
représente l'exécution effectuée par ce programme à ce pas de temps.
step# p1 p2 p3 p4 p5 p6
1 X X X X X X
2 X X X X X
3 X X X X
4 X X X X
5 X X X
6 X X
7 X X
8 X X
9 X X
∞ X X
Comme vous pouvez le constater, les programmes 2 et 4 ne s'arrêtent pas. Si vous les exécutiez un par un, votre contrôleur resterait coincé dans la boucle infinie qu'est le programme 2 et ne sortirait jamais les programmes 3 et au-delà.
Au lieu de cela, vous utilisez une approche en queue d'aronde . Les lettres représentent un ordre d'exécution possible pour les 26 premières étapes. Les *
s sont des endroits où ce programme s'est arrêté et est sorti. Les .
s sont des étapes qui n'ont pas encore été exécutées.
step# p1 p2 p3 p4 p5 p6
1 A C F J N R V
2 B E I M Q * Z
3 D H * P U
4 G L T Y
5 K O X
6 * S .
7 W .
8 . .
9 . .
∞ . .
Exigences pour la langue cible
La langue cible (celle qui est interprétée en parallèle) doit être Turing-complete. À part cela, il peut s'agir de langue Turing-complete, y compris des sous-ensembles Turing-complete de langues beaucoup plus grandes. Vous êtes également libre d'interpréter des choses comme les règles du système d'étiquettes cycliques. Vous êtes également autorisé à créer un langage à tester, tant que vous pouvez montrer pourquoi il est Turing-complet.
Par exemple, si vous choisissez de tester le brainfuck, il est préférable de tester uniquement []-+<>
sous ensemble, car l'entrée n'est pas prise en charge et la sortie est simplement jetée (voir ci-dessous).
En ce qui concerne le programme "contrôleur" (auquel vous jouez), il n'y a pas d'exigences particulières. Des restrictions linguistiques normales s'appliquent.
Comment créer une liste infinie de programmes
La majorité des langages de programmation peuvent être représentés comme une série de symboles d'un alphabet fini. Dans ce cas, il est relativement facile d'énumérer une liste de tous les programmes possibles par ordre de longueur croissante. L'alphabet que vous utilisez doit être représentatif des exigences de la langue cible. Dans la plupart des cas, il s'agit d'un fichier ASCII imprimable. Si votre langue prend en charge Unicode en tant que fonctionnalité supplémentaire, vous ne devez pas tester toutes les combinaisons possibles de caractères Unicode, uniquement ASCII. Si votre langue utilise uniquement, []-+<>
ne testez pas les différentes combinaisons de caractères ASCII "commentaire". Des langues comme APL auraient leurs propres alphabets spéciaux.
Si votre langue est mieux décrite d'une manière non alphabétique, comme Fractran ou Turing Machines, il existe d'autres méthodes également valables pour générer une liste de tous les programmes valides possibles.
Interpréter une liste sans cesse croissante de programmes
L'élément clé de ce défi est d'écrire un interprète parallèle pour une liste croissante de programmes. Il y a quelques étapes de base pour cela:
- Ajouter un nombre fini de programmes à la liste
- Interprétez chaque programme de la liste individuellement pour une durée limitée. Cela peut être accompli en effectuant une étape d'instruction pour chacune. Enregistrez tous les états.
- Supprimer tous les programmes se terminant / générant des erreurs de la liste
- Sortie des programmes * correctement arrêtés
- Ajoutez d'autres programmes à la liste
- Simulez chaque programme à tour de rôle, reprenant l'exécution des anciens programmes là où ils s'étaient arrêtés
- Supprimer tous les programmes se terminant / générant des erreurs de la liste
- Sortie des programmes * correctement arrêtés
- répéter
* Vous ne devez sortir que les programmes qui s'arrêtent proprement. Cela signifie qu'aucune erreur de syntaxe ni exception non interceptée n'a été levée lors de l'exécution. Les programmes qui demandent une entrée doivent également être interrompus sans les sortir. Si un programme produit une sortie, vous ne devriez pas y mettre fin, jetez simplement la sortie.
Plus de règles
- Vous ne devez pas générer de nouveaux threads pour contenir les programmes testés, car cela décharge le travail de parallélisation sur le système d'exploitation hôte / autre logiciel.
- Modifier: pour fermer les futures failles potentielles, vous n'êtes pas autorisé à
eval
(ou toute fonction connexe) une partie du code du programme testé . Vous pouvezeval
un bloc de code à partir du code de l'interpréteur. (La réponse BF-in-Python est toujours valide selon ces règles.) - C'est du code-golf
- La langue dans laquelle vous écrivez votre soumission n'a pas besoin d'être la même que la langue que vous testez / produisez.
- Vous devez supposer que votre mémoire disponible est illimitée.
- Lorsque vous prouvez l'intégralité de Turing, vous pouvez supposer que l'entrée est codée en dur dans le programme et que la sortie peut être lue dans l'état interne du programme.
- Si votre programme sort lui-même, c'est probablement faux ou un polyglotte.
la source
"If your program outputs itself, it is probably wrong or a polyglot."
Réponses:
subleq OISC en Python,
317269 octetshttps://esolangs.org/wiki/Subleq
Un programme subleq est une liste extensible d'entiers (p) et un pointeur d'instruction (i). Cette variante de subleq utilise l'adressage relatif, ce que la page de discussion wiki suggère est requis pour garantir l'exhaustivité avec des valeurs bornées. A chaque tick, l'opération
p[i+p[i+1]]-=p[i+p[i]]
est effectuée, puisi+=p[i+2]
si le résultat de l'opération était <= 0, sinoni+=3
. Si i est négatif, le programme s'arrête.Cette implémentation teste chaque programme dont l'état initial est composé d'entiers non négatifs à un chiffre (0-9) avec un pointeur d'instruction initial de 0.
La sortie est inversée, pour des raisons de golf. La spécification ci-dessus pourrait être reformulée à l'envers, mais ne correspondrait pas au code utilisé dans l'implémentation, donc je ne l'ai pas décrit de cette façon.
EDIT: Le premier programme qui présente une croissance simple et non bornée est 14283, ce qui diminue la valeur à l'emplacement de mémoire 6 et écrit un 0 explicite (par opposition au 0 implicite dans chaque cellule) dans la cellule négative suivante, tous les trois ticks.
la source
Balise cyclique au niveau du bit dans CJam,
98878477 octetsComme il s'agit d'une boucle infinie, vous ne pouvez pas directement tester cela dans l'interpréteur en ligne. Cependant, voici une version alternative qui lit le nombre d'itérations de STDIN pour que vous puissiez jouer avec. Pour tester le programme complet, vous aurez besoin de l'interpréteur Java .
BCT est une variante minimaliste des systèmes d'étiquettes cycliques . Un programme est défini par deux chaînes binaires: une liste (cyclique) d'instructions et un état initial. Pour me faciliter la vie lors de l'impression des programmes, j'ai défini ma propre notation: chacune des chaînes est donnée sous la forme d'un tableau d'entiers de type CJam, et le programme entier est entouré
[[...]]
, par exempleJe n'autorise pas non plus les états initiaux vides ou les listes d'instructions vides.
Les instructions dans BCT sont interprétées comme suit:
0
, supprimez le bit de tête de l'état actuel.1
, lisez un autre bit de la liste d'instructions, appelez celaX
. Si le bit de tête de l'état actuel est1
, ajoutez-leX
à l'état actuel, sinon ne faites rien.Si l'état actuel devient vide, le programme s'arrête.
Les premiers programmes d'arrêt sont
Si vous voulez en voir plus, consultez la version dans l'interpréteur en ligne que j'ai lié ci-dessus.
Explication
Voici comment fonctionne le code. Pour garder une trace de la queue d'aronde, nous aurons toujours un tableau sur la pile qui contient tous les programmes. Chaque programme est une paire d'une représentation interne du code de programme (similaire
[[0 1 0] [1 0]]
) ainsi que de l'état actuel du programme. Nous n'utiliserons que ce dernier pour effectuer le calcul, mais nous devrons nous souvenir du premier pour imprimer le programme une fois qu'il s'arrête. Cette liste de programmes est simplement initialisée dans un tableau vide avecL
.Le reste du code est une boucle infinie
{...1}g
qui ajoute d'abord un ou plusieurs programmes à cette liste et calcule une étape sur chaque programme. Les programmes qui s'arrêtent sont imprimés et supprimés de la liste.J'énumère les programmes en comptant un nombre binaire. Le chiffre de tête est supprimé pour garantir que nous pouvons également obtenir tous les programmes avec des 0 de tête. Pour chacune de ces représentations binaires tronquées, je pousse un programme pour chaque division possible entre les instructions et l'état initial. Par exemple, si le compteur est actuellement à
42
, sa représentation binaire est101010
. Nous nous débarrassons de l'amorce1
et poussons toutes les séparations non vides:Puisque nous ne voulons pas d'instructions ou d'états vides, nous commençons le compteur à 4, ce qui donne
[[[0] [0]]]
. Cette énumération est effectuée par le code suivant:Le reste du code mappe un bloc sur la liste des programmes, qui effectue une étape du calcul BCT sur la seconde moitié de ces paires et supprime le programme s'il s'arrête:
la source
Brainfuck en Python, 567 octets
Une solution relativement simple, car Brainfuck n'est pas la langue la plus difficile à écrire pour un interprète.
Cette implémentation de Brainfuck a le pointeur de données commençant à 0, autorisé uniquement à prendre une valeur positive (considéré comme une erreur s'il essaie d'aller à gauche de 0). Les cellules de données peuvent prendre des valeurs de 0 à 255 et se terminer. Les 5 instructions valides sont
><+[]
(-
est inutile en raison de l'emballage).Je pense que la sortie est tout à fait correcte maintenant, mais il est difficile d'être sûr qu'elle imprime toutes les solutions possibles, donc je peux en manquer.
Les premières sorties:
Et une liste des premiers 2000: http://pastebin.com/KQG8PVJn
Et enfin une liste des 2000 premières sorties avec
[]
en elles: http://pastebin.com/iHWwJprs(tout le reste est trivial tant qu'ils sont valides)
Notez que la sortie n'est pas dans un ordre trié, bien qu'elle puisse apparaître de cette façon pour beaucoup d'entre eux, car les programmes qui prennent plus de temps seront imprimés plus tard.
la source
[-]
et[+]
doivent apparaître définitivement car le contenu de la boucle est simplement ignoré (aucun habillage n'est impliqué).[-]
et[+]
était un bug qui devrait maintenant être corrigé et j'ai mis à jour les paramètres.
? Ce n'est pas nécessaire pour un sous-ensemble de Turing complet de BF et la sortie doit être ignorée de toute façon. De plus, comme vous encapsulez les valeurs des cellules, je pense que vous n'avez besoin que d'un-
et+
.barres obliques en Python,
640498 octetshttps://esolangs.org/wiki////
Un programme slash est une chaîne, dans cet interpréteur limité aux caractères '/' et '\'. Dans cette implémentation, / est '1' et \ est '0' pour permettre une partie de golf avec l'utilisation de bin (x) de python. Lorsque l'interpréteur rencontre un \, le caractère suivant est sorti et les deux caractères sont supprimés. Lorsqu'il rencontre un /, il recherche les modèles de recherche et de remplacement comme / search / replace / y compris les caractères d'échappement dans les modèles (\\ représente \ et \ / représente /). Cette opération de remplacement est ensuite effectuée sur la chaîne de façon répétée jusqu'à ce que la chaîne de recherche ne soit plus présente, puis l'interprétation continue à nouveau depuis le début. Le programme s'arrête lorsqu'il est vide. Un programme sera tué s'il y a un ensemble non fermé de / motifs ou un \ sans caractère après.
la source
Treehugger à Java,
1,2991,2571,2511,2071,2031,2011,1931,189 octetsla source
Brachylog → Problème de correspondance post , 10 octets
Essayez-le en ligne!
Fonction qui est un générateur qui génère tous les problèmes de correspondance possible pour lesquels les solutions de forçage brutal s'arrêtent finalement. (Les solutions de forçage brutal au problème de post-correspondance sont connues pour être une opération Turing-complete.) Le lien TIO contient un en-tête qui convertit un générateur en un programme complet et imprime chaque sortie immédiatement lors de sa génération (ainsi, lorsque TIO tue le programme en raison de la consommation de plus de 60 secondes de temps d'exécution, la sortie produite jusqu'à présent est visible).
Cela utilise une formulation du problème dans laquelle les chaînes sont données sous forme de chaînes de chiffres, les zéros non significatifs ne sont autorisés que pour
0
lui-même, les solutions au problème impliquant les zéros non significatifs ne sont pas acceptées et une chaîne de chiffres peut être représentée soit par le nombre ou moins le nombre. De toute évidence, rien de tout cela n'a un impact sur l'intégralité de Turing de la langue (car il n'y a aucun besoin d'un problème de correspondance de poste pour utiliser le chiffre zéro).Ce programme fonctionne en générant toutes les solutions possibles aux problèmes, puis en reculant pour trouver les programmes originaux qui sont résolus par eux. En tant que tel, un programme individuel peut être émis plusieurs fois. Il n'est pas clair si cela invalide la réponse ou non; notez que tous les programmes d'arrêt seront éventuellement sortis au moins une fois (en fait, infiniment de fois, comme tout programme qui a des solutions a une infinité de solutions), et les programmes sans arrêt ne seront jamais sortis.
Explication
la source
"Violet sans E / S" à Ceylan, 662
Le violet est un langage à instruction unique auto-modifiable qui a été demandé d'interpréter ici . Étant donné que l'entrée et la sortie ne sont pas pertinentes pour cette tâche, j'ai supprimé le
o
le sens du symbole de l'interprète, de sorte que les (potentiellement) symboles valides sont justea
,b
,A
,B
,i
et1
(le dernier seulement pour la lecture, et non pour l' écriture).Mais comme Purple se modifie automatiquement (et utilise son code source comme données), potentiellement aussi des programmes contenant d'autres que ces caractères sont utiles, j'ai donc choisi d'autoriser tous les caractères ASCII imprimables (non blancs) dans le code (d'autres pourraient être également utiles, mais ne sont pas aussi faciles à imprimer).
(Vous pouvez modifier l'interpréteur pour prendre à la place une chaîne de caractères autorisés comme argument de ligne de commande - changez la ligne commentée définissant
a
ci-dessous. La longueur devient alors 686 octets.)Mon interprète "parallèle" crée ainsi toutes les chaînes finies à partir de ces caractères (en longueur et en ordre lexicographique croissants) et essaie chacun d'eux.
Purple s'arrêtera sans erreur chaque fois que la commande à lire sur la bande pour exécution n'est pas valide - il n'y a donc pas de programmes invalides et beaucoup, beaucoup de programmes d'arrêt. (La plupart s'arrêtent même à la première étape, seuls certains des programmes de longueur 3 arrivent à la deuxième étape (et s'arrêteront alors), les premiers non-arrêtants ont la longueur 6.
Je pense que le tout premier programme sans interruption dans l'ordre essayé par mon interprète est
aaaiaa
, qui dans la première étape définit lea
registre à 0 (ce qu'il était déjà), et la deuxième et chaque étape suivante remet le pointeur d'instruction à 0, l'amenant à exécuteriaa
nouveau.J'ai réutilisé une partie du code écrit pour mon interprète de "standard" Purple , mais en raison de la suppression des entrées et des sorties, mon interprète parallèle devient même légèrement plus court que cela, tout en incluant la logique supplémentaire pour exécuter plusieurs programmes à la fois.
Voici une version commentée et formatée:
la source
Calculateur combinatoire SK à Haskell , 249 octets
Essayez-le en ligne!
Comment ça marche
Les règles d'évaluation de l'appel par valeur pour le calcul du combinateur SK sont les suivantes:
(a) S xyz ↦ xz ( yz ), pour x , y , z sous forme normale;
(b) K xy ↦ x , pour x , y sous forme normale;
(c) xy ↦ x ′ y , si x ↦ x ′;
(d) xy ↦ xy ′, pour x sous forme normale, si y ↦ y ′ .
Comme nous ne souhaitons que stopper le comportement, nous développons légèrement le langage en introduisant un symbole H qui n'est pas sous forme normale, mais auquel toutes les formes normales «évaluent»:
(a) S xyz ↦ xz ( yz ), pour x , y , z sous forme normale;
(b ′) K x H ↦ x , pour x sous forme normale;
(c) xy ↦ x ′ y , si x ↦ x ′;
(d) xy ↦ xy ′, pour x sous forme normale, si y ↦ y ′ ;
(e) S ↦ H;
(f) K ↦ H;
(g) SH ↦ H;
(h) KH ↦ H;
(i) SHH ↦ H.
Nous considérons toute application H x comme une erreur d'exécution à traiter comme si elle était une boucle infinie, et nous ordonnons des évaluations telles qu'aucun H ne soit produit par (e) - (i) sauf dans un contexte où il sera ignoré (niveau supérieur, tout K x ☐, tout K☐ ignoré, tout S x ☐ ignoré pour x sous forme normale, tout S☐H ignoré). De cette façon, nous n'affectons pas le comportement d'arrêt des termes habituels dépourvus de H.
Les avantages de ces règles modifiées sont que chaque terme normalisable a un chemin d'évaluation unique vers H, et que chaque terme a un nombre fini de préimages possibles sous ↦. Ainsi, au lieu d'utiliser l'approche en queue d'aronde, nous pouvons faire une recherche en largeur beaucoup plus efficace en premier de tous les chemins d'évaluation inverse de H.
n
vérifie si un terme est sous forme normale,f
trouve toutes les pré-images possibles d'un terme etl
est une liste infinie paresseuse de termes normalisables produite par une recherche en largeur de H.la source