Golunar / unaire est un moyen d'encoder tous les valides Brainfuck programmes, mais ce n'est pas une énumération, puisque la plupart des nombres naturels ne correspondent pas à un programme valide.
Pour les besoins de ce défi, supposons une bande doublement infinie et aucun commentaire, c’est-à-dire qu’un programme Brainfuck est valide si et seulement si il est composé uniquement des caractères <>+-.,[]
et que tous les crochets gauche et droit correspondent.
Par exemple, les programmes vides ,[+][-].
, [>+<[--].]
et +[+[+][+[+]+]+]+.
sont des programmes Brainfuck valides, alors que ][
et a[]
ne le sont pas.
Tâche
Ecrivez un programme ou une fonction qui accepte un programme Brainfuck valide en entrée et renvoie un nombre naturel ( 1 , 2 , 3 ,…), avec les contraintes suivantes:
La sortie générée doit être différente pour tous les programmes Brainfuck valides.
Pour chaque nombre naturel n , il doit exister un programme Brainfuck valide qui, lorsqu'il est fourni en entrée, génère la sortie n .
Règles supplémentaires
Avec un programme Brainfuck de 100 octets ou moins, votre programme ou votre fonction doit s'achever en une minute.
Cela signifie que vous ne pouvez pas parcourir tous les programmes Brainfuck valides tant que vous ne correspondez pas à l'entrée.
Les règles standard de code-golf s'appliquent.
Réponses:
Python 3,
443158155154134131128124117116115 octetsPlusieurs octets grâce à Sp3000 et Mitch Schwartz: D
Comment ça marche:
Ceci mappe tous les programmes BF valides dans tous les programmes BF possibles, valides ou invalides, qui ne commencent pas par un
[
, dans un rapport un à un. Après cela, le nouveau programme est simplement converti en octal.Voici la formule de mappage:
[
caractères. La troisième partie est le plus grand postfix composé de]
caractères uniquement . La deuxième partie est le milieu.]
supports de la troisième partie qui correspondent aux[
supports de la deuxième partie. Ceux-ci peuvent également être recalculés plus tard.Si vous ne comprenez pas cette explication, vous pouvez trouver une explication détaillée dans le chat en commençant ici .
Pour référence, voici les 20 premiers programmes:
Voici les 1000 premiers programmes: http://pastebin.com/qykBWhmD
Voici le programme que j'ai utilisé pour les générer: http://ideone.com/e8oTVl
Voici
Hello, World!
:la source
Python 2, 157 octets
Ça a toujours l'air assez golfable, mais je poste ceci pour le moment. Il utilise la récursivité avec un peu de cache. De manière ennuyeuse,
D.get
ne court-circuite pas pour la mise en cache, je ne peux donc pas économiser 9 octets de cette façon ...Le mappage donne la priorité à la longueur, puis à l'ordre lexicographique par rapport à l'ordre
"][><.-,+"
(voir les exemples de sortie ci-dessous). L'idée principale est de comparer les préfixes.La variable
o
garde trace du nombre de[
crochets encore ouverts pour le préfixe actuel, tandis que la variabled
prend l'une des trois valeurs suivantes:d = 1
: Le préfixe actuel est lexicographiquement antérieur às
. Ajoutez tous les programmes avec ce préfixe et cette longueur<= s
,d = -1
: Le préfixe actuel est lexicographiquement plus tard ques
. Ajoutez tous les programmes avec ce préfixe et cette longueur< s
.d = 0
: Le préfixe actuel est un préfixe des
, nous pourrions donc passerd
à 1 ou -1 plus tard.Par exemple, si nous avons
s = "[-]"
et que notre préfixe actuel estp = "+"
, puisqu’ilp
est plus tard ques
lexicographe, nous ne savons ajouter que les programmes commençant parp
qui sont strictement plus courts ques
.Pour donner un exemple plus détaillé, supposons que nous ayons un programme d’entrée
s = "-[]"
. La première expansion récursive fait ceci:Notez que nous ne pas utiliser réellement les préfixes dans la récursivité - tout ce que nous soucions d'eux est capturé par les variables
d
,o
et le programme d'entrée diminues
. Vous remarquerez beaucoup de répétitions ci-dessus - c’est là que la mise en cache intervient, nous permettant de traiter les programmes de 100 caractères dans les délais impartis.Quand
s
est vide, nous regardons(d>=0 and o==0)
, qui décide s'il faut retourner 1 (compter ce programme parce que c'est lexicographiquement précoce / égal et que le programme est valide), ou 0 (ne pas compter ce programme).Toute situtation avec
o < 0
retour immédiat0
, car tous les programmes avec ce préfixe ont plus de]
s que[
, et sont donc invalides.Les 20 premières sorties sont:
En utilisant le même exemple Hello World que la réponse de @ TheNumberOne:
la source
Python 2, 505 (non golfé)
J'ai aimé développer cette approche, mais je ne me dérangerai peut-être pas parce que ce n'est pas compétitif par rapport à d'autres approches. Je le publie dans l'intérêt de la diversité et de son intérêt esthétique. Cela implique de la récursion et un peu de maths.
La fonction
f(n)
compte le nombre de programmes de brainfuck validesn
.h(x)
mappe des programmes de longueurn
à[0..f(n)-1]
, etg(x)
constitue la fonction de classement bijective en question.L'idée principale est qu'un programme non vide peut commencer avec
[
ou avec l'un des 6[]
caractères non . Dans le premier cas, nous pouvons itérer sur les emplacements possibles de l'appariement]
et de la récidive sur la partie incluse et sur la queue (où queue signifie la sous-chaîne qui suit la]
). Dans ce dernier cas, on peut récidiver sur la queue (où queue signifie laisser tomber le premier caractère). Ce raisonnement peut être utilisé à la fois pour compter et pour calculer le rang.Les programmes les plus courts auront toujours un rang inférieur aux programmes les plus longs et le modèle de parenthèse est un facteur déterminant secondaire. Les non-
[]
caractères sont triés selon "+ - <>,". (ce qui est arbitraire).Par exemple avec
n=4
nous avons ces cas:où
z
représente non-[]
caractère etx
désigne n'importe quel caractère, sous réserve du]
fait qu'il doit correspondre à l'initiale[
. Les programmes sont classés en fonction de cet ordre, et de manière récurrente dans lesx
sous - sections, la section de gauche ayant la priorité sur la section de droite dans les derniers cas. Le calcul du rang est similaire à celui des systèmes à numération à base variable etf
est important pour le calcul de la "base" courante.la source
Cette réponse est une preuve formelle de la réponse fournie par TheNumberOne . Énumérez des programmes Brainf ** k valides , où il peut être un peu difficile de comprendre les détails de la raison pour laquelle l'énumération est correcte. Il n’est pas inutile de comprendre pourquoi aucun programme non valide ne correspond à un nombre non couvert par un programme valide.
Tout au long de cette réponse, les majuscules désignent les programmes et les variables minuscules, les fonctions et les entiers. ~ est l'opérateur de concaténation.
Proposition 1:
Soit la fonction f le programme décrit dans cette réponse. Il existe alors pour chaque programme U un programme valide V tel que f (U) = f (V)
Définition 1:
Soit g (X) le numéro de
[
celui qui apparaît dans le programme X, et h (X) le nombre de]
celui-ci.Définition 2:
Définissez P (x) comme étant cette fonction:
Définition 3:
Pour un programme X, notons X1 comme étant son plus grand préfixe de
[
caractères, X2 son centre et X3 son suffixe le plus grand]
.Preuve de la proposition 1:
Si g (U) = h (U), U est un programme valide et nous pouvons prendre V = U. (cas trivial).
Si g (U) <h (U), nous pouvons créer V en ajoutant des symboles n = h (U) à g (U)
[
. Évidemment, f (V) = f (U) car tous les[
symboles du préfixe sont supprimés.Considérons maintenant g (U)> h (U). Définissez T = U2 ~ U3. si g (T) <= h (T), alors nous pouvons construire V en supprimant n = g (U) - h (U)
[
symboles.Nous pouvons donc supposer que h (T) <g (T). Construire V = T ~ P (g (T) - h (T)).
Nous avons besoin de trois petits faits pour procéder:
Revendication 1: g (U2) = g (T)
U3 ne contient aucun
[
symbole par sa définition. Comme T = U2 ~ U3, ses[
symboles sont tous dans la première partie.Revendication 2: h (U3) <g (T)
Cela découle du fait que h (T) <g (T) et h (U3) <h (U3 ~ U2) = h (T).
Revendication 3: h (V3) = g (U2) - h (U2)
Maintenant, nous montrons que f (V) = f (U).
Ceci complète la preuve. QED
Faisons l'unicité aussi.
Proposition 2:
Soit U, V deux programmes différents et valides. Alors f (U)! = F (V)
Ceci est assez simple par rapport à la proposition précédente.
Supposons que U2 = V2. Mais alors la seule façon dont U et V peuvent être différents est d’ajouter ou de supprimer n
[
et les]
symboles dans U1 et U3 respectivement. Pourtant, cela change la sortie de f, puisque f comptera le nombre de]
symboles non appariés dans le suffixe.Donc, U2! = V2.
Évidemment, cela mène à une contradiction. Comme U2 et V2 sont littéralement contenus dans les sorties de f (U) et f (V) respectivement, ils ne peuvent pas différer, sauf au niveau du "bord", le lieu où U2 est concaténé avec U3. Mais les premier et dernier symboles de U2 et V2 ne peuvent pas être
[
ou]
par définition, alors que ce sont les seuls symboles autorisés dans U1, U3, V1, V3 respectivement et respectivement à nouveau. Nous obtenons donc U2 = V2. QEDla source