Journal TapTempo contest : un peu moins d'octets en Awk

Posté par  (site web personnel) . Licence CC By‑SA.
Étiquettes :
21
14
jan.
2021

Voici une implémentation de TapTempo encore plus compacte que l'indigeste one-liner Perl précédent (https://linuxfr.org/users/zerodeux/journaux/taptempo-en-une-ligne), elle vous est offerte par Loïc Cerf qui me l'a soumise et me propose de vous la partager.

J'ai donc l'honneur de vous transmettre sa solution en 97 caractères :

$ awk '{system("date +%s%N")}'|awk '{t[++k]=$0}k>5{r=k-5}k>1{printf"%i",6e10*(k-r-1)/($0-t[r+1])}'

Le comportement est identique à celui de la ligne Perl de Vincent. Elle considère notamment le temps il y a cinq tapes sur la touche Entrée, moins au début… mais je triche en imprimant %i, le seul tempo (un nombre entier), plutôt que %i bpm qui mènerait à 101 caractères.

La solution n'est pas particulièrement cryptique. Le premier programme AWK appelle date +%s%N, comme dans la solution en Bash de superna, à chaque appui sur la touche Entrée, \n séparant par défaut les "enregistrements" ("record" en anglais) en AWK. Le second programme reçoit donc des nombres de millisecondes depuis l'époque. Il les stocke
dans t[1], t[2], etc., $0 étant l'enregistrement entier en AWK, qui initialise k à 0 la première fois que la variable est utilisée (de façon numérique : ici, un incrément). Au premier enregistrement, rien n'est fait : les tests k>5 et k>1 échouent. Du second au cinquième, seul le test k>1 passe et l'entier imprimé est le tempo calculé en considérant le dernier temps ($0), le premier (t[r+1] est t[1] puisque r vaut 0), le nombre d'intervalle (k-1) et le fait que le temps est en millisecondes plutôt qu'en minutes (facteur 6e10). À partir du sixième enregistrement
(k>5), r est défini comme étant k-5 de sorte que le tempo est calculé en considérant le dernier temps ($0), le temps au k-5+1 = k-4 ème enregistrement et donc k-r-1 = k-(k-5)-1 = 4 intervalles.

J'avais au départ une solution similaire en 103 caractères (107 en écrivant " bpm"). J'ai proposé un défi TapTempo après avoir enseigné AWK ( https://dcc.ufmg.br/~lcerf/slides/mda6.pdf ) à mes étudiants (je suis professeur à l'Université Fédérale du Minas Gerais, au Brésil) : réaliser la même chose en moins de caractères. Une étudiante a économisé trois caractères. J'ai ensuite encore gagné trois caractères.

Si l'un de vous deux veut participer au renouveau d'intérêt pour TapTempo, je n'ai rien contre un journal qui présente cette solution en moins de 100 caractères. Je suis en fait curieux de découvrir si quelqu'un trouvera une solution encore plus brève.

Loïc.

  • # awk '{system("date +%s%N")}' c'est long

    Posté par  . Évalué à 10.

    il est possible de remplacer le premier awk par ts :

    ts "%s"
    Ce qui donne :

    ts "%s"|awk '{t[++k]=$0}k>5{r=k-5}k>1{printf"%i",6e10*(k-r-1)/($0-t[r+1])}'
    Ça fait gagner 20 caractères mais c'est plus du pur awk. En même, date est utilisé, donc c'est déjà plus trop du pur awk.

    • [^] # Re: awk '{system("date +%s%N")}' c'est long

      Posté par  . Évalué à 2.

      Note: les guillemets pour l'expression de la date de ts ne sont pas utile.

    • [^] # Re: awk '{system("date +%s%N")}' c'est long

      Posté par  (site web personnel) . Évalué à 1.

      Je transmet une réponse de Loïc, auteur de la solution Awk originelle :

      ts "%s" donne une seconde de résolution. Cela ne suffit pas.

      Heureusement, ts accepte aussi "%.s" pour une partie fractionnaire (un caractère de plus). Et pas besoin des guillemets : deux caractères de moins. Aussi, avec des secondes plutôt que des nanosecondes, le facteur 6e10 dans le programme AWK devient 60 : encore deux caractères de moins.

      La solution prend alors 72 caractères :

      $ ts %.s|awk '{t[++k]=$0}k>5{r=k-5}k>1{printf"%i",60*(k-r-1)/($0-t[r+1])}'

      Si 100 caractères est la limite, on peut se permettre d'ajouter la remise à zéro après 5 secondes sans taper, comme dans le projet initial de mzf, et utiliser son format de sortie ("Tempo : %i bpm") :

      ts %.s|awk '$0-t[k]>5{k=r=0}{t[++k]=$0}k>5{r=k-5}k>1{printf"Tempo : %i bpm",60*(k-r-1)/($0-t[r+1])}'
      100 caractères. Pile poil. Quelqu'un trouvera-t-il mieux ?

  • # ne marche pas avec mawk

    Posté par  . Évalué à 2.

    Ne marche pas avec mawk pour le coup. Je pense que c'est lié à l'utilisation de comparaison pour les patterns, alors que ça devrais puisque le standard (POSIX-10031-2017) dit:

    An awk program is composed of pairs of the form:
    pattern { action }

    plus loin:

    Patterns
    A pattern is any valid expression, a range specified by two expressions separated by a comma, or one of the two special patterns BEGIN or END.

    Du coup, je me demande si ça ne serait pas un bug de mawk? Ça y ressemble en tout cas beaucoup?
    Peut-être spécifique à debian?

    Pour info:
    ```sh
    % mawk -W version
    mawk 1.3.3 Nov 1996, Copyright (C) Michael D. Brennan

    compiled limits:
    max NF 32767
    sprintf buffer 2040
    ```

Suivre le flux des commentaires

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