Gestion du hasard / randomisation

Générateurs de nombres aléatoires

La question du hasard est un casse-tête éternel du monde de la programmation. Sachez qu’un ordinateur n’est pas véritablement capable de générer une suite de nombres purement aléatoires ou de s’en remettre au hasard. L’ordinateur simule ce qui nous apparaît comme du hasard, bien que la suite de nombres générés soit en réalité calculée et existe en mémoire. Pour parler du hasard et de la génération de nombres pseudo-aléatoires, il est plus courant de parler dans ce cas de RNG pour random number generator.

L’ordinateur est un outil idéal pour jouer avec des séries aléatoires de notes, de rythmes, d’évènements. Dès 1957, Iannis Xenakis utilisait un modèle d’ordinateur IBM pour l’assister dans la composition de certaines pièces stochastiques. Sonic-Pi possède de très nombreuses fonctionnalités pour jouer avec les nombres pseudo-aléatoires.


live_loop :hasard do use_synth [:tri, :saw, :sin].choose play rrand(50, 110), amp: rrand(0.5, 1), attack: rrand(0.1, 0.5) sleep 0.25 end

Vous avez déjà eu l’occasion de rencontrer .choose au cours des chapitres précédents. Il nous permet de choisir un élément compris dans une série finie d’éléments. Ici, il s’occupe pour nous de choisir entre trois types d’oscillations, à savoir une oscillation triangulaire (:tri), une oscillation en dent de scie (:saw) et une oscillation sinusoïdale (:sin). Remarquez que le même résultat aurait été possible en utilisant non pas une liste ( [] ) mais un anneau (ring).


rrand(x, x1)

Rrand est notre générateur de nombres aléatoires. Il génère un nombre aléatoire, y compris en usant de décimales, strictement compris entre sa valeur basse et sa valeur haute. rrand(0, 10) sera ravi de vous renvoyer par exemple la valeur 7.27343. Ce type de nombre est généralement appellé float number pour floating point number, nombre à virgule flottante Son équivalent pour les nombres entiers existe.

rrand_i s’occupe de générer des nombres entiers, ou integers. rrand_i(0, 10)  aura pour effet de sélectionner aléatoirement un chiffre dans une liste comprise entre 0 et 10, extrêmes inclus.

Une option permet également de définir une distance minimale entre deux nombres :


rrand(0, 10, step: 5)

Le résultat de cette instruction est un peu déçevant. Sonic-Pi renverra trois valeurs possibles : 0, 5 et 10, seuls nombre possibles possédant l’espacement requis. Si le nombre de pas choisi est un entier, rrand ne pourra ici avoir pour résultat qu’un entier tant que votre nombre minimum et maximum seront du même type. Si vous entrez un pas avec une décimale, comme 1.1 rrand retrouvera sa fonction de floating point number generator .

Un coup de dés jamais n’abolira le hasard

Il existe certaines structures de contrôle permettant de jouer spécifiquement avec le hasard en simulant un lancer de dé :


live_loop :jouer_aux_des do if one_in(8) play :a2 else play :a5 end sleep 0.125 end

one_in a un fonctionnement booléen. Il renvoie True ou False suivant une certaine probabilité : 8 (1/8 de chances), 7 (1/7 de chances), etc… Nous l’avons ici associée à une autre structure de contrôle directement héritée de Ruby : un if statement. Ceux-ci seront abordés ultérieurement dans un article dédié.


live_loop :dé do puts dice(6) ; sleep 0.25 end

Voici un véritable lancer de dé, ou x dans dice(x) indique le nombre de faces. Son fonctionnement est très simple. Bien qu’il ne soit pas très utile en tant que tel, il vous servira dès lors que vous le combinerez avec différentes structures de contrôle. Voici un exemple combiné avec on qui va observer si une condition spécifique est actualisée :


live_loop :dé do a = dice(6) on a == 6 do sample :perc_bell end on a == 2 do sample :perc_impact2 end puts “un cycle passe…” sleep 0.5 end

Observez la console : parfois, quelque chose se passe. Parfois rien ne se passe. Nos sons ne sont joués que dans l’éventualité d’un 6 ou d’un 2 obtenu lors d’un lancer de dé stocké dans la variable a.

La métaphore de la graine

Comme je l’ai expliqué en préambule, il n’existe pas réellement de hasard en informatique. Ce qui peut nous sembler être du hasard est en réalité une suite prédéterminée, sélectionnée avec plus ou moins de talent par l’ordinateur. L’ordinateur est donc tout à fait apte à reproduire ce que la perception nous entraîne à ressentir comme du hasard.

En musique aléatoire, il est des accidents heureux. Certains évènements qui se déclenchent et créent un effet intéressant, un groupe de notes admirables bien qu’accidentelles. Il est tout à fait possible de les reproduire. Sonic-Pi fonctionne avec un système de graines ou seeds, qui servent à stocker une certaine disposition du générateur de nombres aléatoires. Pour vous en convaincre, jouez l’exemple suivant une première fois, arrêtez la lecture puis redémarrez là à nouveau :


live_loop :yes do ; tick a = rrand_i(0, 5) play (scale :c, :major)[a] sleep 0.25 end

Vous remarquerez donc que le hasard n’est ici qu’une illusion. Sonic-Pi vient de rejouer la même série de notes, plusieurs fois à la suite, bien que la sélection paraisse aléatoire. Ajoutez à présent l’instruction suivante :


live_loop :yes do ; tick use_random_seed 1 a = rrand_i(0, 5) play (scale :c, :major)[a] sleep 0.25 end

Changez la graine avant de relancer la lecture à nouveau. Vous devriez entendre quelque chose de différent pour presque chacune des graines. Sonic-Pi génère une nouvelle séquence pour chaque graine. Vous pouvez donc théoriquement stocker et partager une suite pseudo-aléatoire de notes et la conserver en mémoire. Pratique, simple et utile.