Conseils pour jouer au brainfuck


23

Quels conseils généraux avez-vous pour jouer au brainfuck? Je cherche des idées qui peuvent être appliquées aux problèmes de golf de code en général qui sont au moins quelque peu spécifiques au brainfuck (par exemple, "supprimer les commentaires" n'est pas une réponse). Veuillez poster un pourboire par réponse.

Réponses:


25

Mettre un conseil par réponse serait bien trop de réponses.

  • Apprenez à penser dans Brainfuck. C'est très différent de tout le reste. Lisez et écrivez, réécrivez et réécrivez de nombreux programmes de brainfuck. La langue ne vous donne pas beaucoup de travail, il est donc important d'utiliser ce qu'elle vous donne de manière flexible et efficace. Ne laissez aucune abstraction s'interposer entre vous et la langue - entrez là-dedans et essayez-la.

  • Soyez très à l'aise avec le contrôle de flux non destructif. Pour sortir d'une boucle de décision, plutôt que de mettre à zéro la cellule de départ en la copiant ailleurs puis en la recopiant après avoir quitté la boucle, il est souvent préférable de déplacer le pointeur vers un zéro préexistant à proximité. Oui, cela signifie que le pointeur se trouvera à différents endroits selon que vous avez parcouru la boucle, mais cela signifie également que ces endroits ont probablement des dispositions différentes de zéros et de non-zéros proches, que vous pouvez utiliser pour resynchroniser l'emplacement du pointeur à l'aide d'une autre boucle. Cette technique est fondamentale pour une bonne programmation Brainfuck, et ses diverses formes se révéleront constamment utiles.

  • Cela et le fait que chaque >ou chaque <coût signifie que les détails de la disposition de la mémoire sont importants. Essayez autant de variantes de votre mise en page que vous en avez la patience. Et rappelez-vous, votre disposition de mémoire ne doit pas être une cartographie rigide des données aux emplacements. Il peut évoluer au cours de l'exécution.

  • À plus grande échelle, envisagez et essayez même d'implémenter une variété d'algorithmes différents. Au départ, il ne sera pas évident de savoir exactement quel algorithme sera le meilleur; il ne sera peut-être même pas évident quelle approche de base sera la meilleure, et ce sera probablement quelque chose de différent de ce qui serait le mieux dans une langue normale.

  • Si vous traitez des données volumineuses ou de taille variable, voyez s'il existe un moyen de les traiter localement, sans avoir à garder une trace de leur taille ou de votre emplacement numérique.

  • Les mêmes données peuvent être deux choses différentes. (Le plus souvent, un nombre ou un caractère et également un marqueur de position non nul. Mais voir random.b , où un compteur de bits double la valeur d'une cellule d'un automate cellulaire.)

  • Le même code peut faire deux choses différentes, et il est beaucoup plus facile de le faire dans un langage où le code est aussi générique que <+<. Soyez attentif à ces possibilités. En fait, vous pouvez parfois remarquer, même dans ce qui semble être un programme bien écrit, qu'il existe de petites portions qui pourraient être supprimées entièrement, rien ajouté, et la chose, par hasard, fonctionnerait toujours parfaitement.

  • Dans la plupart des langues, vous utilisez fréquemment un compilateur ou un interpréteur pour vérifier le comportement de votre programme. Le langage Brainfuck exige un plus grand contrôle conceptuel; si vous avez besoin d'un compilateur pour vous dire ce que fait votre programme, vous n'avez pas une compréhension suffisamment ferme de votre programme, et vous devrez probablement le regarder un peu plus - du moins si vous voulez avoir une image suffisamment claire de le halo conceptuel de programmes similaires pour être bon au golf. Avec de la pratique, vous produirez une douzaine de versions de votre programme avant d'en essayer une, et à ce stade, vous serez sûr à 95% que votre version la plus courte fonctionnera correctement.

  • Bonne chance! Très peu de gens prennent la peine d'écrire Brainfuck de manière concise, mais je pense que c'est la seule façon dont le langage peut éventuellement justifier une attention continue - en tant que forme d'art incroyablement obscure.


3
Lire cela me donne envie d'essayer la programmation dans Brainfuck maintenant ..
Claudiu

Putain de merde, j'ai cru reconnaître ton nom. Grand fan de vos programmes de brainfuck, en particulier de votre auto-interprète super court!
Jo King

"vous remarquerez peut-être occasionnellement ... qu'il y a de petites portions qui pourraient être supprimées entièrement, rien ajouté, et la chose, par hasard, fonctionnerait toujours parfaitement." C'est tellement vrai, surtout pour un débutant. Je n'ai jamais écrit qu'une seule réponse en BF pour autant que je me souvienne, mais son historique de révision contient au moins 3 cas où je jouais avec le programme et je suis allé au hasard ", hé, le programme fonctionne toujours si je supprime ce bit! "
ETHproductions

"Essayez autant de variantes de votre mise en page que vous en avez la patience", ou peut
utiliser la

9

Quelques conseils ici:

Constantes:

La page des constantes des Esolangs contient une liste extrêmement utile des moyens les plus courts de créer des valeurs spécifiques. Je me retrouve à consulter cette page au moins deux fois par programme.

Le début de tout:

+++[[<+>>++<-]>]

Cela configure la bande au format 3 * n ^ 2, qui ressemble à

3 6 12 24 48 96192128 0 0 »

Pourquoi est-ce si important?

Descendons la liste:

  • 3 et 6 sont ennuyeux
  • 12: Près de 10 (nouvelle ligne) ou 13 (retour chariot). Peut également être utilisé pour le compteur pour 0-9
  • 24: Près de 26, le nombre de lettres de l'alphabet
  • 48: ASCII pour 0
  • 96: près de 97, ASCII pour a
  • 196 et 128: 196-128 = 64, près de 65, l'ASCII pour A.

À partir de cet algorithme, nous sommes au début de pratiquement toutes les séquences de la plage ASCII, avec un compteur pour chacune et une nouvelle ligne à portée de main.

Un exemple pratique:

Impression de toutes les lettres et chiffres majuscules et minuscules.

Avec algorithme:

+++[[<+>>++<-]>]<<[-<->]<<<<++[->>+.>+.<<<]<--[>>.+<<-]

Sans pour autant:

+++++++++++++[->+++++++>++>+++++>++++>+<<<<<]>+++++>[-<+.>>.+<]>>---->---[-<.+>]

Nous passons la plupart des octets à initialiser la bande dans le deuxième exemple. Elle est en partie compensée par les mouvements supplémentaires dans le premier exemple, mais cette méthode a clairement l'avantage.

Quelques autres algorithmes intéressants dans la même veine:

3 * 2 ^ n + 1:

+++[[<+>>++<-]+>]
Tape: 4 7 13 25 49 65 197 129 1 0'

Cela compense les valeurs de 1, ce qui accomplit quelques choses. Cela rend le 12 un retour chariot, le 64 le début réel de l'alphabet majuscule et le 24 plus proche de 26.

2 ^ n:

+[[<+>>++<-]>]
Tape: 1 2 4 8 16 32 64 128

Parce que 64 est bon pour les lettres majuscules, 32 est l'ASCII pour l'espace et 128 peut être utilisé comme compteur pour 26 (130/5 = 26). Cela peut économiser des octets dans certaines situations où les chiffres et les lettres minuscules ne sont pas nécessaires.

Choisissez l'implémentation qui convient à la question:

  • Les cellules négatives sont presque toujours utiles, et il n'y a aucune raison de les éviter (à moins que cela ne change pas votre bytecount)
  • Presque exactement la même chose avec les cellules d'habillage, d'autant plus que de nombreuses constantes utilisent l'habillage.
  • Les tailles de cellules arbitraires sont utiles pour des séquences mathématiques infinies, telles que le calcul de la séquence de Fibonacci à l'infini ( +[[-<+>>+>+<<]>]) ou le traitement de nombres plus grands / négatifs. L'inconvénient est que certaines méthodes courantes, telles que [-]et [->+<]ne peuvent pas être invoquées, juste au cas où le nombre serait négatif.
  • EOF comme 0, -1 ou aucun changement. 0 est généralement préférable, car vous pouvez boucler sur une entrée entière sans vérifications supplémentaires. -1 est utile lors du bouclage sur des structures de tableau. Je n'ai pas encore trouvé d'utilisation pour aucun changement :(.

Gardez une trace de ce qui se passe:

À tout moment, vous devez avoir des commentaires sur l'emplacement du pointeur par rapport aux données qui l'entourent et vous assurer que vous connaissez la plage de valeurs possibles de chaque cellule. C’est surtout important lorsque vous avez divisé le pointeur avant une boucle, car vous souhaiterez ensuite réunir les deux possibilités.

À tout moment, mon code est jonché de commentaires sur toutes les autres lignes qui ressemblent à ceci:

*0 *dat a_1 ?  0' !0 0*
 or
*0 *dat 0' ap1 0  !0 0*

Un conseil supplémentaire consiste à attribuer aux symboles des significations spéciales. Dans l'exemple ci-dessus, 'est l'endroit où se trouve le pointeur, *signifie la répétition dans cette direction, ?signifie une cellule avec une valeur inconnue, !0signifie une cellule non nulle, _est un substitut -et pest un substitut de +.orimplique que la bande pourrait ressembler à l'une ou l'autre des représentations et doit être traitée comme telle.

Votre schéma de symboles ne doit pas nécessairement être le même que le mien (qui a quelques défauts), il doit simplement être cohérent. Ceci est également extrêmement utile lors du débogage, car vous pouvez l'exécuter jusqu'à ce point et comparer la bande réelle à ce que vous devriez avoir, ce qui peut signaler des failles potentielles dans votre code.


5

Mon principal conseil serait de ne pas le faire.

OK, d'accord, tu veux quelque chose de plus utile que ça. BF est déjà un langage très laconique, mais ce qui vous tue vraiment, c'est l'arithmétique, qui doit effectivement être faite de manière unaire. Il vaut la peine de lire la page des constantes dans Esolang pour savoir exactement comment écrire de grands nombres efficacement et exploiter le wrapping autant que possible.

L'accès à la mémoire est également très coûteux. Puisque vous lisez à partir d'une cassette, vous devez garder à l'esprit où votre tête bouge à tout moment. Contrairement à d' autres langues où vous pouvez simplement écrire a, b, cen bf vous devez explicitement déplacer la tête un certain nombre d'octets à gauche ou à droite, vous devez donc être conscient de l' endroit où vous stockez quoi. Je suis à peu près sûr que l'organisation de votre mémoire de manière optimale est NP-difficile, alors bonne chance avec celui-là.


5

Dans cette réponse, je vais me référer plusieurs fois à une cellule spécifique de la bande. Peu importe de quelle cellule il s'agit, mais c'est la même cellule tout au long de la réponse. Aux fins de cet article, j'appellerai cette cellule "Todd".

Lorsque vous essayez de définir une cellule sur une valeur constante, il est parfois avantageux de ne pas la terminer immédiatement. Par exemple, supposons que vous vouliez que Todd en contienne 30. Plus tard dans votre code (qui peut modifier la valeur de Todd mais ne la lit jamais), vous revenez à Todd. Si la valeur de Todd est 0, le programme se ferme. Sinon, la valeur de Todd est imprimée pour toujours.

Selon la page esolangs.org des constantes brainfuck (qui pourrait probablement faire l'objet d'une astuce à elle seule!), Le moyen le plus court d'obtenir 30 est >+[--[<]>>+<-]>+. Ce début >n'est là que pour garantir que rien à gauche du pointeur n'est modifié, mais dans ce cas, nous supposerons que nous ne nous soucions pas de cela et le supprimons. En utilisant ce code, votre code ressemblerait à ceci:

+[--[<]>>+<-]>+(MISC. CODE)(GO TO TODD)[.]

Vous pouvez penser au premier morceau de code comme ceci:

(SET TODD TO 30)(MISC. CODE)(GO TO TODD)[.]

Mais rappelez - vous les deux derniers caractères dans ce morceau: >+. Il est tout aussi valable de penser de cette façon:

(SET TODD TO 29)(GO TO TODD)(ADD 1 TO TODD)(MISC. CODE)(GO TO TODD)[.]

Remarquez que vous (GO TO TODD)deux fois! Vous pouvez à la place écrire votre code de cette façon:

(SET TODD TO 29)(MISC. CODE)(GO TO TODD)(ADD 1 TO TODD)[.]
+[--[<]>>+<-](MISC. CODE)(GO TO TODD)+[.]

En supposant que le nombre d'octets requis (GO TO TODD)est le même avant, un mouvement de moins == un octet de moins! Parfois, le fait que votre position de départ ait changé enlève cet avantage, mais pas toujours.


0

Une toute petite astuce pour relever des défis sans contribution. Vous pouvez utiliser à la ,place de [-], si vous devez effacer rapidement la cellule, car la plupart des interprètes (y compris celui de TIO.run) définiront le contenu de la cellule sur une représentation EOF égale à zéro. Cela rend les programmes un peu infimes, mais qui s'en soucie quand même dans le code golf?

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.