Appuyez sur Entrée pour voir vos résultats ou Echap pour annuler.

Ouin, PI ?

Comme à mes habitudes, à l’approche des fêtes, je vous ai préparé un petit article un peu différent que ceux que je fais d’habitude. L’idée m’est venue en regardant une vidéo de la chaîne Numberphile sur YouTube. La vidéo traitait d’un sujet connexe, mais ça m’a aidé à finalement comprendre ce que j’avais vu plus jeune dans le RPG Well of Souls. Ce jeu contenait un cheat qui permettait d’estimer PI en temps réel grâce à une simulation. C’est ce qu’on va essayer de recréer aujourd’hui !

Les sources de cet article sont disponibles ici.

Pourquoi estimer PI ?

En tant que programmeur, estimer PI avec la méthode que je vais vous présenter est non seulement très cool, mais aussi un beau petit défi. De plus, PI est un nombre qu’on retrouve partout, même à des endroits assez étranges, en plus d’être un nombre irrationnel. Je trouve personnellement très intéressant de voir qu’on arrive à calculer PI de plusieurs façons différentes et je crois que cette simulation est très agéable à développer et regarder.

Bref, parfait pour ne pas se casser la tête avant les fêtes! Amusons-nous 🙂

Comment fonctionne la simulation ?

Imaginez-vous une cible pour un jeu de dart. Puis, tracer un carré de la même dimension de côtés que le diamètre de la cible, comme ceci :

Maintenant, il faut lancer une infinité de darts vers cette cible. Notre approximation de PI sera le nombre de lancers sur la cible divisé par le nombre total de lancers multiplié par 4.

Cette simulation s’appelle la méthode de Monte-Carlo.

Le code

L’objectif ici étant de s’amuser, j’ai décidé de faire l’exercice avec HTML et JavaScript. Il y aura donc un canevas sur lequel on dessinera des points aléatoires. Je vais donc avoir besoin de :

  • Une vue, en HTML
  • Un modèle de vue, pour me permettre d’afficher de l’information dans la vue
  • Un moteur pour gérer l’animation
  • Un calculateur pour estimer PI avec la méthode Monte-Carlo
  • Un dépôt pour stocker l’estimation qu’on aura trouvé qui sera la plus près de PI
  • Une classe d’application pour orchestrer tout ça

La vue

Pour la vue, nous avons besoin de quelques <span> pour injecter les valeurs calculées par le calculateur, d’un <canevas> pour dessiner la cible et les points et d’un bouton pour lancer le tout. Avec l’aide de Bootstrap, ça ressemble à ceci :

Voir le code complet de la vue.

Le modèle de vue

Cette classe a la responsabilité d’abstraire le code HTML de la vue. Elle doit donc exposer des mutateurs qui auront la responsabilité d’aller injecter la nouvelle valeur dans les <span>. En procédant de cette façon, tout le reste du code JavaScript ignorera qu’il y a une page HTML. Créons la classe :

Afin d’y aller au plus simple possible, cette classe garde une copie en attributs des éléments HTML suivants :

  • piElement = l’instance du HTMLElement représentant le <span> qui affiche la valeur approximative de PI
  • dotsInCircleElement = l’instance du HTMLElement représentant le <span> qui affiche le nombre de points générés à l’intérieur du cercle
  • totalDotsElement = l’instance du HTMLElement représentant le <span> qui affiche le nombre total de points générés
  • startButtonElement = l’instance du HTMLElement représentant le bouton pour lancer la simulation
  • closestEstimationElement = l’instance du HTMLElement représentant le <span> qui affiche le record d’approximation de PI (persité)
  • dotsInCircleClosestEstimationElement = l’instance du HTMLElement représentant le <span> qui affiche le nombre de points générés à l’intérieur du cercle en lien avec le record persisté
  • totalDotsClosestEstimationElement = l’instance du HTMLElement représentant le <span> qui affiche le nombre total de points générés en lien avec le record persisté
  • piRealValueElement = l’instance du HTMLElement représentant le <span> qui affiche la valeur de Math.PI
  • onclickStartButton = une méthode qui sera appelée lors du clic sur le bouton Start

Puis, dans le constructeur, on récuère ces instances avec getElementById(), en prennant soin de sortir les ID d’éléments dans un fichier de constantes :

Ensuite, on expose des mutateurs pour chacun des éléments html, comme ceci :

Finalement, il reste à attacher la fonction onclickStartButton au véritable bouton dans le DOM à l’aide d’une méthode comme celle-ci :

Voir le code complet du modèle de vue.

Le moteur

Le moteur ici a la responsabilité de s’attacher au cycle de dessin du navigateur pour faire une animation fluide. Il exposera des méthodes pour dessiner sur le canevas ainsi une méthode qui sera appelée à chaque cycle de dessin. Créons la classe :

Le moteur va devoir garder une copie de l’instance de HTMLElement qui représente le <canevas> ainsi que son contexte 2D. Il doit aussi exposer les méthodes de dessin, comme pour dessiner un point d’une certaine couleur sur le canevas :

On termine par une méthode pour lancer l’animation, puis la boucle d’animation en elle-même :

Ici, onloop est une fonction qui sera appelée à chaque cycle.

Voir le code complet du moteur.

Le calculateur Monte-Carlo

Cette classe servira à encapsuler l’algorithme de calcul pour la simulation. Comme expliqué plus haut, on doit générer des points aléatoires. Cette classe sera donc responsable de faire ces calculs et de garder l’estimation la proche de la valeur de Math.PI.

Puis, on expose la méthode qui nous permet de générer un point aléatoire, tout en comptabilisant l’information :

Afin de déterminer si le point est dans le cercle, nous n’avons qu’à mesurer la distance qui le sépare du centre du cercle et de le comparer avec son rayon.

Puis on expose la méthode permettant de faire l’estimation de PI :

Voir le code complet du calculateur.

Le dépôt pour stocker le record

Étant donné que PI va se calculer de plus en plus précisément à mesure qu’on génère des points, il me paraissait intéressant de pouvoir stocker l’estimation de PI qui est la plus près de Math.PI. Le dépôt a donc la responsabilité de stocker l’information dans le localStorage du navigateur.

Voir le code complet du dépôt.

La classe applicative

Cette classe fait office d’orchestrateur pour les autres classes. Elle permet de créer les instances nécessaires, de générer la cible sur laquelle on dessine les points ainsi que d’exécuter la boucle principale via la méthode onloop() du moteur :

Voir le code complet de la classe applicative.

Pour exécuter l’application

Prérequis

Pour lancer :

Puis ouvrir le navigateur à l’adresse indiquée dans la console.

Conclusion

Aujourd’hui, on a laissé de côté les trucs compliqués pour avoir du plasir avec du code. Personnellement, ce genre d’exercice me permet de décrocher du code que j’ai à produire pour mon client. Ça permet d’exercer son côté créatif en utilisant un algorithme amusant.

Si vous avez apprécié, n’hésitez pas à partager avec vos collègues et amis 🙂 @+

Suivez-nous par courriel!

Saisissez votre adresse courriel pour vous abonner au blog d'Ezo et recevoir une notification de chaque nouvel article par email.