Journal TapTempo en Advanced Brainfuck

Posté par  . Licence CC By‑SA.
31
28
mar.
2018

Très cher journal,

Je me suis rendu compte que tu es en perte de vitesse sur TapTempo, que la fréquence de nouveaux portages diminue significativement. Étant donné l'importance du projet, je me suis dit "il faut que je fasse quelque chose!". J'ai cherché un langage à utiliser, mais le choix est restreint. Je me suis attardé sur la version brainfuck, avec le regret de ne pas avoir pouvoir utiliser ce langage universellement reconnu (la note du journal parle d'elle même). Et je me suis confronté à la terrible vérité: le brainfuck avait besoin de pipes, sans cela il était impossible de créer taptempo! Comment était-ce possible? Il fallait faire quelque chose! J'ai donc créé Advanced Brainfuck, ou ABrainfuck.

Dans l'état d'esprit originel de simplicité extrême, qui fait toute sa puissance, je n'ai créé qu'un seul nouvel opérateur: le switcher "~". À quoi sert-il? À ouvrir des fichiers! et en rw part défaut (simplicité oblige, les utilisateurs n'ont qu'à pas se tromper). Alors comment ça marche?

Et bien, par défaut, à l'instar du brainfuck, les opérateurs ">", "<", "+", "-" modifient le pointeur courant (décalage et +/-1). Nous sommes en mode "mémoire", et le pointeur sera appelé "pointeur mémoire". Les opérateurs "." et "," quant à eux servent à lire et écrire dans le fichier ouvert, appliqué sur la position du "pointeur fichier". En écriture si un caractère existe, il le remplace, "." et "," décalent automatiquement le pointeur fichier de +1 (l'agrandissant si nécessaire). Le fichier ouvert par défaut est /dev/stdout. "." permet donc d'imprimer, et "," ne fait rien.

Oui mais comment fait-ont pour ouvrir un fichier? et bien on prépare d'abord la mémoire avec une chaîne de caractères correspondant à l'adresse du fichier, terminant par \0 bien sûr. On se met sur le premier caractère et on utilise l'opérateur "~". On passe alors en mode fichier. Les opérateurs ">", "<", "+", "-" s'applique sur le pointeur fichier et l'adresse pointée dans le fichier. "," écrit du fichier vers la mémoire et "," écrit de la mémoire vers le fichier, les deux décalent automatiquement le pointeur mémoire de +1. En réutilisant l'opérateur "~" on retourne en mode mémoire, le fichier restant ouvert.

Vous l'aurez compris, ouvrir /dev/stdin permet d'avoir l'entrée standard, et, par exemple, l'ouverture du fichier /proc/uptime permet d'obtenir un temps relatif!

Et voilà le travail, on peut maintenant implémenter un TapTempo sans pipe grâce à ce nouveau langage qui, je n'en doute pas un instant, figurera parmi les plus utilisés!

Maintenant: le code de TapTempo.abf. Il donne un BPM toute les 4 pressions sur entrée, sur une base de 240 BPM (plus facile à mettre en mémoire, ça nécessite qu'un byte). Il fait donc une approximation et donne 120, 60, 48… en fonction de votre vitesse. La prochaine version codera la base sur 2 bytes, et permettra une bien meilleure précision. L'algorithme est commenté et contient pas mal de choses intéressantes telles que des if, des opérations et notamment des divmod. Et le voici:

preparation of the stdout address:
/
>+++
[>+++
[<<+++++>>-]<-]
<++.

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

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

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

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

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

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

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

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

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

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

NULL
>

preparation of the stdin address
/
>
>+++
[>+++
[<<+++++>>-]<-]
<++.

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

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

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

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

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

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

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

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

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

NULL
>

preparation of the uptime file address

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

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

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

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

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

/
>
>+++
[>+++
[<<+++++>>-]<-]
<++.
u
>
>++++
[>+++++
[<<++++++>>-]<-]
<---.

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

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

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

m
>
>++
[>+++++
[<<+++++++++++>>-]<-]
<-.
e
>
>+++++
[>+++++
[<<++++>>-]<-]
<+.

NULL
>[-]

newline
>
++++++++++
.
return to the begining
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
[
moving to stdin and open it
>>>>>>>>>>>>
~~
moving to random memory space read 4 times remove

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
,,,,[-]

return to the begining
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~~
moving to stdin
>>>>>>>>>>>>
moving to uptime
>>>>>>>>>>>

open
~~
shift from the file names
>>>>>>>>>>>>>>>>>>>>

save the time (cleaning a bit first)
20 to get space

[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]

<<<<<<<<<<<<<
get the data (need loops to stop at the dot)

first loop looking for the dot
+
[
,

>[-]>[-]>[-]<<< clean a bit

>>+++[>++++[<<++++>>-]<-]<-- create dot character on next

[-<->] substract it from the previous char

>>>+<<< increase counter

< shit to it and check if it 0
]

>>>>--- decrease the counter to take 2 num before the dot

reopen the file:
return to the begining
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
moving to stdin
>>>>>>>>>>>>
moving to uptime
>>>>>>>>>>>
open
~~
shift memory to the same zone
20 to get space
>>>>>>>>>>>>>>>>>>>>

read first characters and clean mem
>>>>

[
<,[-]>-
]
<< go back
read it for real
,>,>
prepare the 0 ascii value
>>+++[>++++[<<++++>>-]<-]<
[-<+>]<

[-<-<->>]remove it

<<<++++++++++ prepare the 10 multiplicator

[>[<<+<+>>>-]<<[>>+<<-]>-]>[-]<<[-]< do the multiplication and go on result

>>>>[-<<<<+>>>>]<<<< add the units to the result to get the total time

go to current copy current to new
<<<<<

copy result to new cleaning first
>[-]<
[->+<]

copy new to current
>>>>>[-<<<<<+>>>>>]<<<<<

do subtraction far enough for the divmod with conservation
[->>>>>>+>+<<<<<<<]>>>>>>[-<<<<<<+>>>>>>]
<<<<<
[->>>>+>+<<<<<]>>>>[-<<<<+>>>>]>

[->-<]

<---------------- prepare memory for division 240 bpm division

[->+>-[>+>>]>[+[-<+>]>+>>]<<<<<<] divide result: 0 n d minus n%d n%d n/d

[-]>[-]>[-]>[-]<<<<< clean a bit then organize rate current previous at the begining of the mem
going back to stdout and open
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
~~
moving to stdin
>>>>>>>>>>>>
moving to uptime
>>>>>>>>>>>
moving to memory space value and print it (still need ascii conversion)
>>>>>>>>>>>>>

>>>>>>>>>>

to print it need modulos 10 and 100
prepare the 100 div

check further if it s useful first of all copy
[->>>>>>>>+>+<<<<<<<<<]>>>>>>>>[-<<<<<<<<+>>>>>>>>]
create the 100
>>
>+++++
[>+++++
[<<++++>>-]<-]<
<<

check if the value is bigger than 100 put the 0 or 1 on the current position
z x y temp0 temp1
^
>>>[-]>[-]<<<<[-]
>[>>+
<[->[-]>+<<]
>[-<<<+>>>]
>[-<<+>>]
<<-<-]
clean
>[-]>[-]<<<
do it only if is not 0
[
<<<<<<

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

[->+>-[>+>>]>[+[-<+>]>+>>]<<<<<<] divide result: 0 n d minus n%d n%d n/d

>>>>>>

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

[-<+>]<

. print it

clean
[-]<<[-]<[-]

copy the modulo

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

>>>>>

[-]

]

do the same for 10
<<<<<<<
<[->>>>>>>+>+<<<<<<<<]>>>>>>>[-<<<<<<<+>>>>>>>]
create the 10
>>++++++++++<<

check if the value is bigger than 10 put the 0 or 1 on the current position
z x y temp0 temp1
^

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

clean
>[-]>[-]<<<
do it only if is not 0
[
[-]
<<<<<

++++++++++<<

[->+>-[>+>>]>[+[-<+>]>+>>]<<<<<<] divide result: 0 n d minus n%d n%d n/d

>>>>>>

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

[-<+>]<

. print it

clean
[-]<<[-]<[-]

copy the modulo
>>[-<<<+>>>]

>>>>>

]

change the modulo to ascii
<<<<<<
+++[>++++[<<++++>>-]<-]<
[-<+>]<
. print it
[-]

clean
[-]

write BMP
++++++++[>++++<-]>.[-]#++++++[>+++++++++++<-]>.[-]+++++++[>+++++++++++<-]>.[-]++++++++[>++++++++++<-]>.[-]
new line
#
<<<<<<<<<<<<<<.
#

return to the begining never at 0 infinite loop
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

]
  • # Ce qui fait bizarre...

    Posté par  . Évalué à 10.

    …c'est de commenter du brainfuck.

    • [^] # Re: Ce qui fait bizarre...

      Posté par  . Évalué à 3.

      C'est vrai, ça s'oppose un peu au coté "offuscation" du langage, mais étant donné qu'il s'agit du tout premier programme, j'ai fait une exception… ;)

      • [^] # Re: Ce qui fait bizarre...

        Posté par  . Évalué à 4.

        Oui, surtout que comme bcp j'ai une profonde admiration pour le brainfuck, sans forcément avoir pris le temps de regarder de près et de "choper le truc". Ce style de commentaire (ainsi que tout ton texte d'introduction) aide bcp, merci !!!

        En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.

        • [^] # Re: Ce qui fait bizarre...

          Posté par  . Évalué à 3.

          Le brainfuck est admirable de part sa simplicité. On peut difficilement faire plus simple (voire simpliste) comme langage de programmation. Ça me fait penser à un boulier (mais encore plus simple…).

          "choper le truc"

          C’est un peu comme faire des mots croisés ou du sudoku… C’est distrayant de réussir à trouver un algorithme en brainfuck pour faire tel ou tel calcul, mais ça encore c’est que le début. Les fondus de brainfuck font ce qu’on appelle du “code golf” en brainfuck, c’est à dire chercher à rendre le code source le plus court possible, là je dois avouer, pour avoir lu quelques programmes, que je suis largué, c’est vraiment pas évident à suivre. Ça nécessite à mon avis un don particulier que je n’ai pas.

          Il y a même des langages conçus spécialement pour le code golf. Comme Jelly, qui est inspiré du langage J. Mais là on perd la simplicité du Brainfuck.

          Par exemple, en Jelly :

          ċЀ“PNDQ”µæ.“¢¦½ı‘ṭ
          

          correspond au Python2 :

          C=map(input().count,'QDNP')
          print C+[sum(a*b for a,b in zip(C,[25,10,5,1]))]
          

          d’après https://codegolf.stackexchange.com/questions/160678/electronic-piggy-bank

      • [^] # Re: Ce qui fait bizarre...

        Posté par  . Évalué à 4.

        Non mais c'est très bien que tu l'aies fait, c'est juste tellement décalé ;-)

        • [^] # Re: Ce qui fait bizarre...

          Posté par  . Évalué à 1.

          D'ailleurs ça m'a aidé à comprendre comment on peut faire toutes les opérations avec uniquement des additions et des adresses, ce qui est basiquement ce qu'on fait dans un cpu.

  • # MetaTapTempo

    Posté par  (site Web personnel) . Évalué à 10. Dernière modification le 28/03/18 à 15:15.

    Je me suis rendu compte que tu es en perte de vitesse sur TapTempo, que la fréquence de nouveaux portages diminue significativement.

    Il faudrait un outil, MetaTapTempo, pour mesurer tout ça.

    Les utilisateurs postent un journal LinuxFR en cadence régulière et le programme en déduit le tempo correspondant. Il est affiché en nombre de journaux LinuxFR équivalent par semaine (ou JPW en anglais).

    Ou pas.

    blog.rom1v.com

  • # Nouvelle dimension

    Posté par  (site Web personnel) . Évalué à 10.

    Bravo, tu fais rentrer TapTempo dans une nouvelle dimension en créant un nouveau langage pour ce besoin !

    C'est TapTempo qui crée la technologie et non plus l'inverse :-)

    • [^] # Re: Nouvelle dimension

      Posté par  . Évalué à 4.

      Oui, c'est exactement ce que je m'étais dit! Malheureusement j'ai peur que cette technologie ait du mal à percer au delà de taptempo…

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n’en sommes pas responsables.