Programmer avec Processing -...

83
Programmer avec Processing

Transcript of Programmer avec Processing -...

Programmer avecProcessing

Table des matières

Objectifs 7

Introduction 9

I - Premier pas avec Processing 11

A. Installer Processing.....................................................................................11

B. L'interface de Processing..............................................................................12

C. Utiliser les exemples de Processing................................................................14

D. Premier Programme....................................................................................14

E. Quelques exercices sur le premier programme................................................18

II - Variables et contrôle de flux 21

A. Les variables dans Processing.......................................................................21

B. Notion de portée des variables......................................................................23

C. Structures de contrôle de flux.......................................................................25 1.Notion de boucle for....................................................................................................26 2.Exercice : La boucle for................................................................................................30 3.La boucle while...........................................................................................................31 4.Structures itératives imbriquées....................................................................................33 5.Exercice.....................................................................................................................34 6.Structures conditionnelles............................................................................................35 7.Jouons avec les boucles et les tests...............................................................................37

D. Un crible d'Eratosthene Visuel.......................................................................39

III - Un crible d'Érathostène dynamique 41

3

A. Présentation du projet.................................................................................41

B. Choix des variables.....................................................................................42

C. La notion de listes.......................................................................................44

D. Les traces de pas........................................................................................46

E. Le programme............................................................................................47

F. Modifier le crible..........................................................................................51

G. Les listes - suite.........................................................................................51

IV - La programmation modulaire 53

A. Réutiliser et clarifier : créer des étoiles..........................................................53

B. Des paramètres pour nos étoiles...................................................................56

C. Rendre modulaire la skyline..........................................................................57

D. Retourner une valeur...................................................................................58

V - Exercice : PUISSANCE 4 ! 59

VI - La programmation objet 61

A. Un chat est un chat.....................................................................................61

B. Définition d'une classe.................................................................................62

C. Définir la classe dans un nouveau fichier........................................................63

D. Utilisation d'un objet...................................................................................65

E. De nouvelles voitures...................................................................................67

VII - La récursion 69

A. Deux exemples mathématiques....................................................................69

B. Mise en œuvre : le flocon de Koch.................................................................70

VIII - Les images, la couleur et la compression 75

A. La numérisation du réel...............................................................................75

B. Les images informatiques.............................................................................79

IX - Du bon usage des tableaux : tris et recherches 83

4 4

A. Comment faire une recherche dans un tableau...............................................83

B. Dichotomie récursive...................................................................................87

C. Comment trier un tableau............................................................................87

D. Implémentation du tri par insertion...............................................................90

5

Objectifs

L'apprentissage de la programmation et de l'informatique est souventrébarbatif. Avant que de voir apparaître un résultat plaisant, il fautpasser par des phases assez complexes d'apprentissages. Processingest un outil assez rapide à prendre en main qui permet d'obtenirrapidement un résultat visuellement satisfaisant. Bien qu'il soit destinéinitialement aux élèves des écoles d'arts, il permet aussi de s'initier à laprogrammation. C'est l'objectif de ce module.

7

Introduction

Processing est une surcouche au langaga JAVA développé à partir de 2001 par des étudiantsdu MIT pour faciliter la création artistique avec l'outil informatique. En plus du langage,Processing est aussi un IDE.Processing est un logiciel libre, adapté à la création d'animation visuelles, animées ou non,sonorisées, en 2D ou 3D. Facile à mettre en œuvre, il peut être utilisé sur des plateformesvariées ( Windows 32 ou 64 bits, Mac OS X, et linux )

9

I - Premier pas avec Processing

I

Installer Processing 11

L'interface de Processing 12

Utiliser les exemples de Processing 14

Premier Programme 14

Quelques exercices sur le premier programme 18

A. Installer Processing

Remarque : Clef ISNSi vous utilisez la Clef ISN du lycée des Eaux Claires, il est inutile d'installerProcessing. Celui ci est préinstallé grâce au module d'extension processing.sqh

InstallationLa dernière version stable de processing peut se télécharger à l'adresse suivante :https://processing.org/download/?processing . Au moment de l'écriture de cedocument, il s'agit de la version 2.1.

Page de téléchargement de Processing

L'installation sous windows se fait en exécutant le fichier téléchargé.L'installation sous linux se fait en décompactant l'archive. Le mieux est de l'installerdans le répertoire /optPour Mac Os X, l'archive zip doit être décompactée puis on obtient une application.app qu'il suffit d'installer dans le dossier Applications.

11

B. L'interface de Processing

La fenêtre principale

IDE de processing

Lorsque vous lancez le programme de processing, vous voyez s'ouvrir la fenêtreprincipale de l'IDE. Outre le menu, cette fenêtre est découpée en 3 zones :

La barre d'icônes qui permet les actions les plus courantes La zone d'édition de texte dans laquelle on rentre le code source du

programme La zone de messages dans laquelle apparaîtront les différents messages liés

aux fonctionnement de Processing

Premier pas avec Processing

12

Premier pas avec Processing

12

Barre d'icônes Processing

La barre d'icône de processing contient les icônes suivantes : Le bouton "run" compile et exécute le programme Le bouton stop arrête l'exécution du programme en cours Le bouton new permet d'ouvrir une fenêtre pour faire un nouveau programme La flèche vers le haut permet d'ouvrir un programme existant (open) La flèche vers le bas permet d'enregistrer le code source ( save) La dernière fleche (vers la droite) est destinée à l'exportation du programme

sous forme d'application ou d'applet Java.

Fenêtre d'exécutionLorsque l'on lance l'application en appuyant sur le bouton "Run", une seconde fenêtres'ouvre où s'effectue les opérations du programme. Voici la fenêtre créée par leprogramme d'exemple sur les tableaux bidimensionnels

Fenêtre d'exécution

13

Premier pas avec Processing

C. Utiliser les exemples de Processing

Processing est fourni avec un grand nombre d'exemple. En informatique comme dansbien d'autres domaines, les exemples sont très utiles pour apprendre. Les exemplessont accessibles par le menu "Files", la ligne "Examples" ou en utilisant lacombinaison de touches Ctrl+Maj+O

Q u e s t i o n Vous allez lancer l''environnement de Processing, ouvrir au minimum trois exemplesfournis avec Processing et les exécuter sur votre ordinateur

D. Premier Programme

Le premier exempleNous allons maintenant fabriquer et étudier notre premier programme en Processing.À cette occasion, nous mettrons en avant un certain nombre de conceptsinformatiques importants. Voici le code source de notre premier exemple, que nousallons analyser ligne par ligne. Vous pouvez télécharger le code source ici.

Code source du premier exemple

Lorsque l'on exécute ce code, une fenêtre de fond noir s'ouvre. La dimension de lapartie noire est de 500 pixels par 500 pixels. Si l'on maintient la souris appuyée enpassant au dessus de la fenêtre, on dessine des cercles blancs de bord noir tant quel'on maintient la souris appuyée et on obtient un résultat comme la fenêtre cidessous.

Premier pas avec Processing

14

Premier pas avec Processing

14

Fenêtre d'exécution du premier exemple

Analysons maintenant cet exemple.

Les variablesLes deux premières lignes du programme contiennent les définitions de variables.Une variable est une donnée que l'ordinateur doit conserver en mémoire et quipourra être modifiée au fur et à mesure de l'exécution du programme. Il fautimaginer qu'une variable n'est rien d'autre qu'une étiquette sur une boite danslaquelle l'ordinateur va pouvoir ranger un contenu. Le contenu peut être de différent type. On peut vouloir stocker des chaines decaractères, des nombres, des types composés complexes, etc ... Dans certainslangages de programmations, le type de la variable est sous-entendu. DansProcessing, il faut déclarer le type de la variable en même temps que la variable,c'est à dire indiquer dans le code source quel type de contenu va aller dans la boite.

15

Premier pas avec Processing

1 int framePerSecond = 200¬†;La première ligne définit une variable de type entier. C'est le mot clef int (pourinteger, entier en anglais) au début de la ligne qui indique le type de la variable. Unevariable de type integer peut stocker des nombres entiers définis entre -2 147 483648 et 2 147 483 647. Cela laisse un peu de marge.framePerSecond est le nom que l'on donne à la variable. C'est le programmeur quichoisi ce nom. C'est en quelque sorte l'étiquette que l'on met sur la boite. Le nomdoit être unique dans le programme et il ne peut pas être identique au nom d'uneinstruction déjà existante.Cette première ligne contient en fait deux choses. La première est la déclaration de lavariable. On aurait pu faire juste la chose suivante :

1 int framePerSecond¬†;Cela aurait créé la variable. Au passage, on remarque le point-virgule

FondamentalEn processing, toute instruction s'achève par un point-virgule.

En plus de la création de la variable, on a utilisé le signe = qui sert à faire uneaffectation. En mathématique, le symbole = indique que deux quantités sontidentiques et il peut se lire de gauche à droite comme de droite à gauche.En informatique, le symbole = indique une affectation. Il n'est pas réversible. Ilindique que l'on met dans la variable qui est à gauche du signe = le résultat del'expression qui se trouve à droite du signe =En clair, la première ligne crée la variable entière framePerSecond puis initialise savaleur à 200.La seconde ligne permet de créer et d'initialiser une variable d'un type pluscomplexe.

1 color couleurFond = color(0,0,0)¬†;Ici, on crée et on affecte une valeur à une variable de type color. Cette variableservira à stocker la couleur de fond. Son affectation se fait à partir du résultat del'appel d'une fonction. Nous en dirons un peu plus après, sur les fonctions et lagestion des couleurs.

Les fonctions - première approcheDans la suite du programme, deux fonctions sont déclarées. Ces deux fonctions sontprésentes dans tout programme processing. Une fonction, c'est un ensembled'instructions regroupées ensemble dans un même espace. Les fonctions ont denombreux usages, et nous en parlerons plus longuement dans de prochainschapitres.Ici, deux fonctions doivent être définies : setup et draw. La syntaxe pour définir unefonction est la suivante :

1 Type_retournom_fonction(parametre1,parametre2,...) {

2    instructions ;3 }

La première partie de la déclaration de la fonction indique le type retourné. Dansnotre exemple, on a le type "void", ce qui signifie en anglais "le néant". Cela signifieque notre fonction n'est pas supposé retourner de valeur particulière. Elle va

Premier pas avec Processing

16

Premier pas avec Processing

16

s'exécuter et ne renverra pas de valeur, contrairement à une fonction au sensmathématique du terme. Dans certains langages de programmations, on utiliserait leterme de procédure plutôt que celui de fonction dans cette situation.On donne ensuite le nom de la fonction. Dans notre cas, les fonctions s'appellentsetup et draw.Ensuite, on met entre parenthèse la liste des paramètres qu'il faut fournir à lafonction. Dans notre cas, il n'y en a pas.Enfin, on met entre accolades les instructions que la fonction doit effectuer.Dans un programme Processing, il y a deux fonctions qui sont à déclarer. La fonctionsetup est exécutée au début du programme. Dans notre cas, au début duprogramme, nous effectuons trois instructions :

1 void setup() {2   size(500,500);3   background(couleurFond);4   frameRate(framePerSecond);5 }

La première instruction appelle la fonction size qui va fixer les dimensions dela fenêtre d'exécution de processing en indiquant la largeur et la hauteur.

La seconde instruction va fixer la couleur du fond. Pour cela elle va utiliser lavariable couleurFond que nous avons défini au début du programme.

Enfin, la troisième fonction va définir la vitesse de rafraîchissement de lafenêtre, c'est à dire le nombre de fois par seconde que la fenêtre seraréécrite. On passe en argument la variable framePerSecond définie au débutdu programme.

La fonction draw quant à elle est exécutée à chaque rafraîchissement de la fenêtred'exécution tant que le programme est en fonctionnement.

1 void draw() {2   if (mousePressed) {3     ellipse(mouseX,mouseY,20,20);4   }5 }

La fonction draw définie ici va d'abord effectuer un test, grace à l'instruction if (si enanglais). La valeur mousePressed est une variable booléenne qui indique si un boutonde la souris est enfoncé ou non. Si un bouton de la souris est enfoncée, alors unellipse va être tracée. mouseX et mouseY sont des variables de type entier (int) quiindiquent la position du pointeur de la souris. La fonction ellipse prend 4 paramètres :la position de l'ellipse, la largeur de l'ellipse et sa hauteur. Ici, l'ellipse sera doncplacée au niveau du pointeur de la souris, et elle fera 20 pixels de large et de haut. Ils'agira donc d'un cercle.Ce tracé sera donc effectué jusqu'à 200 fois par secondes tant qu'un bouton de lasouris est enfoncé.

Complément : Références du langage ProcessingSur le site processing.org, la référence complète du langage est disponible en ligne àl'adresse : http://processing.org/reference/

17

Premier pas avec Processing

E. Quelques exercices sur le premier programme

Lancer le premier programmeVous allez installer Processing sur votre ordinateur si ce n'est pas déjà fait. Vous allezensuite télécharger le fichier zip contenant le premier programme qui se trouve à l'adresse suivante :Vous ouvrirez ce premier exemple dans processing et l'exécuterez

Q u e s t i o n 1Modifiez le programme pour que l'affichage ne se fasse plus dans une fenêtre de 500pixels par 500 pixels mais dans une fenêtre de 800 pixels par 500 pixels.

Q u e s t i o n 2Des ellipses toujours de même dimension, c'est monotone. Nous allons dans unpremier temps modifier légèrement le rayon de l'ellipse de façon aléatoire. Pour cela,on va utiliser la fonction random (dont la référence est ici1 ). Grâce à cette fonction,vous allez modifier le programme pour avoir un cercle dont la taille varie entre 10 et30 pixels au lieu d'avoir systématiquement un cercle de 20 pixels.

Indice :

Pour bien avoir un cercle et pas une ellipse, il faut faire une seule fois le tirage. Ilest sans doute préférable de déclarer une variable que l'on appelle rayon.Attention ! La fonction random retourne une valeur de type "float", c'est à dire unnombre décimal. Il faut convertir le résultat de random en entier, ce qui se faitgrâce à la fonction int().

Q u e s t i o n 3Des cercles toujours blanc, c'est ennuyant. On souhaite modifier la couleur descercles à chaque tracé de cercle. En vous inspirant de ce que l'on vient de faire pourles rayons, changer la couleur des cercles. La fonction qui définit la couleur deremplissage est la fonction fill() dont la référence est ici2.Les deux boutonsJusqu'ici, nous n'avons utilisé que le fait que la souris ait ou non un bouton pressé.Or, la souris a deux voire trois boutons en général.Dans processing, c'est la variablemouseButton3 qui indique quel bouton a été pressé. Elle peut prendre trois valeurs :LEFT, RIGHT ou CENTER.

Q u e s t i o n 4Modifier le programme pour que le comportement soit le suivant :

Si le bouton gauche est maintenu, on effectue un tracé de cercle sans contour. Si le bouton droit est enfoncé, on effectue une modification du rayon et de la

couleur du cercle (mais pas lors des tracés )

Indice :

Pour comparer le contenu d'une variable avec une valeur, il ne faut pas utiliser lesymbole = mais le symbole == qui sert à effectuer un test de comparaison. Ondevra donc avoir des tests de la forme mouseButton == RIGHTOn pourra utiliser la structure if deux fois ou utiliser la structure if ... else ...4

1 - http://processing.org/reference/random_.html2 - http://processing.org/reference/fill_.html3 - http://processing.org/reference/mouseButton.html4 - http://processing.org/reference/else.html

Premier pas avec Processing

18

Premier pas avec Processing

18

(si ... sinon ... )ATTENTION ! l'initialisation du rayon devra être sorti de la fonction draw pour quele rayon devienne une variable globale ...

Pour aller plus loinEn vous aidant de la référence de processing, vous pouvez aller plus loin et modifierle comportement du programme pour créer comme vous le souhaitez. N'hésitez pas.Voici un dernier exemple ou les variations de rayon et de couleur existent toujours,mais sont limitées. Lors du clic droit, elles changent de façon importante. Vouspouvez vous en inspirer.

19

Premier pas avec Processing

II - Variables et contrôle de flux

II

Les variables dans Processing 21

Notion de portée des variables 23

Structures de contrôle de flux 25

Un crible d'Eratosthene Visuel 39

A. Les variables dans Processing

Notion de variableL'informatique est llittéralement la science du traitement automatique del'information. En informatiques, les informations sont appelées les données. Onassocie à chaque donnée un nom (le symbole).Cette association entre un nom et une valeur ou un objet est appelé une variable, carle contenu peut varier au cours du temps.

ExempleVous connaissez déjà dans la vie courante des variables.On peut par exemple associer plusieurs variables à une personne :

son age son poids sa taille son nom de famille savoir s'il porte des lunettes la couleur de ses cheveux

Mis à part le nom de famille qui devrait rester le même tout au long de la vie, toutesces données peuvent varier au cours du temps.

Le typage des variablesUne variable peut contenir des données de différente nature. Reprenons l'exempleprécédent. Pour une personne, son age est en général un nombre entier d'années(même si les enfants rajoutent volontiers des "et demi"). Son poids ou sa taille sontsouvent des nombres décimaux. Son nom de famille est un ensemble de caractères(on dira une chaîne de caractères). La nature des données stockées dans unevariable est appelé son type. Le type indique quelles données peuvent être stockées

21

dans la variable et quelles opérations peuvent être effectuées.

ExempleOn peut effectuer une addition sur des entiers ou des nombres décimaux. Pas surune chaîne de caractères. À contrario, on peut concaténer (c'est à dire mettre bout à bout) des chaînes decaractères, mais pas des nombres.Si l'on divise un nombre entier par un nombre entier, on fait une division entière dontle résultat est un nombre entier. Si l'on divise un nombre décimal par un nombre décimal, le résultat est décimal.Ainsi, informatiquement parlant, les divisions 10/4 et 10.0/4.0 ne donnent pas lemême résultat ( 2 dans le premier cas, 2.5 dans le second cas)

Déclaration de variablesAfin que l'ordinateur puisse utiliser une variable, il faut qu'il lui réserve un espacedans sa mémoire. Dans le cas de processing, cette réservation doit se faire enindiquant le type de la variable. Cette déclaration du type est importante. En effet, laplace à réserver en mémoire n'est pas la même pour les différents types devariables. Voici par exemple la déclaration de variables dans un programmeprocessing qui caractériserait des personnes.

Les types principaux de processing

La déclaration de variable réserve l'espace en mémoire. On peut ensuite affecter desvaleurs à cette variable. Cette procédure s'appelle l'affectation, et on se sert du signed'égalité. Les deux opérations peuvent être effectuées en même temps.

Déclaration et affectation de variables

Les différents types de variable dans ProcessingVoici les principaux types qui existent dans le langage processing

le type int (abréviation de integer ) sert à représenter les nombres entiers.Un nombre entier dans processing est codé sur 32 bits, ce qui donne environ4 milliards de possibilités.

Variables et contrôle de flux

22

Variables et contrôle de flux

22

le type float permet de stocker des nombres décimaux. On parle de nombreà virgule flottante d'où l'abréviation.

Le type boolean permet de stocker un état. Il ne prend que deux valeurs :true ou false. C'est un type important en informatique, car il sert à évaluerdes conditions et permet de faire des opérations logiques.

char est un type de variable qui permet de contenir un caractère. C'est àpartir de ce type qu'est construit le type complexe de chaînes de caractères.

String qui sert à représenter une chaîne de caractères. Il faut bien remarquerla majuscule au début. En processing comme dans la plupart des langages, lasyntaxe est sensible à la casse, et il n'y a pas de type string (sans lamajuscule).

AttentionLorsqu'un nombre est utilisé dans une expression, s'il est entier, il est considéré pardéfaut comme de type int. Cela peut avoir des conséquences sur les calculs dèsqu'une division apparaît. Pour qu'un nombre soit considéré comme un nombredécimal, il suffit de l'écrire avec un point et un 0 derrière, c'est à dire 5.0 au lieu de5. Dans ce cas là, les opérations se feront de façon certaine avec des décimaux.

Complément : Autres types courants Il y a deux autres types qui existent pour représenter les nombres entiers,

mais ils sont moins utilisés : le type byte qui code un octet et qui est stockésur 8 bit (un octet), et le type long qui est un nombre entier stocké sur 64bits ( et présente donc des milliards de milliards de possibilités !). Ces typessont moins utilisés, car ils ne sont pas compatibles avec certaines fonctions deprocessing

Le type double sert à représenter des nombres à virgule flottante avec uneprécision plus importante que le type float. Il n'est cependant pascompatible avec certaines fonctions de processing. L'accroissement de laprécision se paye aussi d'un ralentissement de certaines fonctionnalités.

B. Notion de portée des variables

Les programmes informatiques sont optimisés pour ne pas gaspiller la place enmémoire. Lorsqu'une variable est déclarée, elle ne va être définie que le tempsnécessaire. Nous allons le voir sur des exemples simples.Considérons le code source suivant

1 void setup() {2   size (400,400);  3   background(0,0,0) ;4   int rouge=25;5   int vert=60;6   int bleu=200;7 }8 void draw() {9   fill(rouge,vert,bleu);10   rect(20,20,60,60);

23

Variables et contrôle de flux

11 }On sait que dans le langage Processing, la fonction setup est appelée au début duprogramme et correspond à l'initialisation. La fonction draw est quand à elle appeléede façon répétitive tant que le programme n'est pas terminé.

Q u e s t i o n 1Quel résultat attend on de ce programme ? Essayez d’exécuter le programme. Que sepasse t'il ?On va essayer une correction de ce code. On veut avoir un carré qui va changer decouleur de façon répétée et cyclique. On va utiliser les variables rouge, vert, bleu, lesfaire démarrer à une valeur donnée, puis ajouter un à chaque occurence de draw.Pour ne pas dépasser 255 et opérer de façon cyclique, on va utiliser l'opérateurmodulo5 qui donne le reste de la division entière.Voici le code que l'on se propose d'utiliser

1 void setup() {2   size (400,400);3   background(0,0,0);4   frameRate(50);5 }6 void draw() {7   int rouge=25;8   int vert=60;9   int bleu=200;10   fill(rouge,vert,bleu);11   rect(20,20,60,60);12   rouge = (rouge +1) % 255;13   vert = (vert +1) % 255;14   bleu = (bleu +1) % 255;15 }

Q u e s t i o n 2Que se passe t"il à l'exécution de ce programme ?Dans les codes précédent, les variables rouge, vert et bleu sont déclarées au sein dela fonction setup ou draw. Dans ces conditions, elle n'existent que durant l'exécutionde la fonction setup. On dit que les variables sont locales à la fontion.Lorsque l'on exécute la fonction draw, les variables rouge, vert et bleu n'existent plusdans le cas du premier programme. Elle n'étaient définies que dans la fonction setup.Dans le cas du second programme, elles son détruites et reconstruites lors de chaqueappel à la fonction draw.Une solution serait d'utiliser des variables globales. Des variables globales existentdurant tout le programme. Elles sont définies en dehors des fonctions, généralementau début du programme

Q u e s t i o n 3Corrigez le second programme pour avoir des variables globales. Vérifiez son bonfonctionnement en l'exécutant.Surcharge locale de variableOn considère le code informatique suivant, dans lequel on utilise la fonction text6 quisert à afficher une chaîne de caractères à une position donnée.

5 - http://processing.org/reference/modulo.html6 - http://processing.org/reference/text_.html

Variables et contrôle de flux

24

Variables et contrôle de flux

24

1 String chaine="Un texte";2   3 void setup() {4   size (400,400);5   background(0,0,0);6   frameRate(50);7 }8   9 void draw() {10   text(chaine,20,100);11   affiche();12   text(chaine,20,300);13 }14 void affiche() {15   chaine="locale";16   text(chaine,20,200);17 }

La fonction draw affiche la chaîne de caractère "chaine" puis appelle une fonction quenous avons définie : affiche. Celle ci change la chaîne de caractère chaine et l'afficheen dessous.Enfin, après avoir appelé la fonction affiche, on retourne dans la fonction draw pourla poursuivre et on affiche chaine.

Q u e s t i o n 4Exécuter le programme. Qu'est ce qui s'affiche et pourquoi ?Dans la fonction affiche, modifier la ligne chaine="locale"; en la remplaçant parString chaine="locale"; . Exécutez le programme. Qu'est ce qui s'affiche et pourquoi ?

C. Structures de contrôle de flux

Dans un programme, les instructions s'exécutent les une après les autres. C'est ce que l'onappelle le flux des instructions. Par défaut, le flux des instructions suit le sens usuel de lalecture, allant de gauche à droite puis de haut en bas. Il existe des instructions quipermettent de modifier le flux des instructions pour prendre en compte les données et réagiren fonction des données. On parle d'instructions de contrôle de flux. Elles ont normalementdéjà été abordées lors des cours d'algorithmique en classe de seconde et de premièrescientifique du lycée. Ces instructions de contrôle de flux sont regroupées selon deux familles :les structures conditionnelles et les structures itératives.

25

Variables et contrôle de flux

1. Notion de boucle for

Un exemple de figure simpleUn ordinateur est un objet électronique qui ne se lasse pas. Il est capable de répéterdes opérations de façon continu sans soupirer. Mieux, on peut faire en sorte qu'ileffectue des taches répétitives sans avoir besoin d'être derrière son dos.Imaginons que je veuille tracer 2 carrées centrés dans une fenêtre processing. Mafenêtre fait 400 pixels de large. Les deux carrés occuperont les 3/4 de la largeur, soit300 pixels. Pour les disposer de façon "uniforme", on fait le petit schema suivant

deux carrés répartis

Pour tracer un rectangle en processing, la fonction à utiliser est la fonction rect()7 .Elle prend 4 paramètres : l'abscisse et l'ordonnée d'origine, ainsi que la largeur et lahauteur des rectangles.

1 rect(abscisse,ordonnee,largeur,hauteur)¬†;Notre premier rectangle a son coin en haut à gauche à 30 pixels de la gauche et à125 du haut. C'est un carré dont la hauteur et la largeur sont de 150 pixels.Le second rectangle lui est à 30+150+40 = 220 pixels de la gauche et à 125 du haut.Le tracé des deux rectangles se fera donc avec les instructions ci dessous.

1 rect(30,125,150 ,150) ;2 rect(220,125,150,150) ;

AttentionNe pas oublier que les coordonnées sont positives, orientées de gauche à droite pourles abscisses et de haut en bas pour les ordonnées. C'est contraire à ce que l'onutilise habituellement en mathématiques.

7 - http://www.processing.org/reference/rect_.html

Variables et contrôle de flux

26

Variables et contrôle de flux

26

Système de coordonnées

Un exemple de figure répétitiveImaginons maintenant que l'objectif n'est plus le même. On ne souhaite pas tracerdeux carrés, mais 10 rectangles, qui auront toujours 150 pixels de hauteur mais neseront plus aussi larges. Il faudra toujours qu'ils occupent les 3/4 de la surface etqu'ils soient répartis uniformément.

MéthodeLorsque l'on doit procéder à des tracés de motifs, pour bien comprendre lescoordonnées à utiliser, il faut utiliser avant toute chose un papier et un crayon !Voici à quoi ressemblera notre figure, avec les cotations.

10 rectangles uniformément répartis

27

Variables et contrôle de flux

Pour déterminer la largeur et l'espace, un petit calcul est nécessaire. Les rectanglesdoivent occuper les 3/4 de la largeur, donc ils doivent faire 300 pixels au total.Chaque rectangle fera donc 30 pixels.Les espaces vont être au nombre de 11. Il reste 100 pixel, chacun fera donc 100/11soit 9 pixels environs (à 1 près)Pour tracer les rectangles, il faut les coordonnées des sommets en haut à gauche.Pour l'ordonnée, ce sera toujours 125. Pour l'abscisse, pour le premier, ce sera 9.Pour le second, 9+30+9 soit 48. Pour le troisième, 9+30+9+30+9 soit 87, et ainsi desuite. On pourrait être tenté d'écrire le code suivant

1 rect(9,125,30 ,150) ; // premier rectangle2 rect(48,125,30,150) ; // second rectangle3 rect(87,125,30 ,150) ; // troisième rectangle4 ..... 5 rect(361,125,30,150) ; // dixième rectangle

Embaucher un mercenaireQuel sale boulot !Cette façon de faire pose plein de problèmes. Le premier problèmeest le suivant. On recopie des lignes et des lignes de code presque identique, maisles êtres humains que nous sommes vont finir par faire une faute de frappe, ou unefaute de calcul. Pire encore, on ne veut plus afficher 10 rectangles mais 12. Il faut toutrecommencer !Et puis, s'il y en avait 60 à afficher ? Vous imaginez l'horreur !Non, vraiment, pour faire ce sale boulot, on va embaucher un mercenaire : leprocesseur de l'ordinateur ! Il n'a qu'à les faire lui tout ces calculs. Il faitconstamment des calculs sans se lasser. C'est son petit côté Rain Man.Pour arriver à nos fins, nous allons utiliser une boucle. En français ordinaire, on diraità l'ordinateur la chose suivante :« Répète 10 fois l'opération suivante : tu traces un rectangle de 150 pixels de haut,décalé de 125 pixels du sommet, et décalé de la gauche d'un montant quis'incrémente à chaque fois de 30 plus 9 . »On pourrait écrire ça en "pseudo langage", c'est à dire un code informatiquegénérique

1 abs_origine = 92 ord_origine = 1253 Pour un compteur allant de 1 à 104   tracer un rectangle partant de abs_origne,

ord_origine, de 150 pixels de haut et de 30 pixels de large5   augmenter abs_origine de 39

L'instruction en processing qui permet de faire ce type de boucle est l'instructionfor()8 dont la syntaxe est la suivante

1 for (instruction d'initialisation ; test de fin ;opération de mise à jour) {

2   instructions3 }

Dans notre exemple, on va prendre une variable de compteur qui va s'incrémenter de

8 - http://www.processing.org/reference/for.html

Variables et contrôle de flux

28

Variables et contrôle de flux

28

1 à 10. Le programme en processing sera donc le suivant

1 float ordonnee= 125 ;2 float abscisse = 9 ;3 for (int compteur = 1 ; compteur <= 10 ;

compteur++) {4   rect(abscisse,ordonnee,30,150) ;5   abscisse += 39 ;6 }

Examinons bien comment fonctionne cette boucle. Lorsqu'il arrive sur la boucle for, l'ordinateur va éxécuter l'instruction

d'initialisation. Ici, il crée une variable entière compteur, et il affecte la valeur1.

Ensuite, il regarde tout de suite le test de fin. Ici, compteur est bien plus petitque 10, donc il va exécuter les instruction de la boucle.

Il trace le premier rectangle Il augmente l'abscisse de 39 ensuite, il est arrivé à la fin des instructions. Il va effectuer l'instruction de

mise à jour, qui consiste à ajouter 1 au compteur Il recommence la boucle. Le compteur vaut 2, il est toujours plus petit que 10.

Il va donc refaire les instructions de la boucle. et ainsi de suite. Lors de la dernière étape, le compteur passe de 10 à 11. 11 est plus grand

que 10, et la boucle va s’arrêter là. Le programme va reprendre le coursnormal des instructions.

Une varianteOn a calculé les coordonnées des points en incrémentant au fur et à mesure de 39 lavaleur des abscisses. On pourrait aussi utiliser le compteur pour placer les points ensachant quel rectangle on est en train de tracer.En effet, pour le rectangle numéro n, l'abscisse du coin à gauche peut être calculécomme suit :

il y a un espace devant chaque rectangle donc n espace il y a n-1 rectangles qui le précèdent

On peut donc écrire le code ainsi

1 float ordonnee= 125 ;2 for (int compteur = 1 ; compteur <= 10 ;

compteur++) {3 ¬ † r e c t ( 9 * c o m p t e u r + 3 0 * ( c o m p t e u r -

1),ordonnee,30,150) ;4 }

On a plus à incrémenter l'abscisse à chaque étape, mais au lieu de cela on fait uncalcul.

Variabiliser et généraliserSi on repense le code ci dessus, on a fait encore pas mal de calcul "à la main" lié auxdonnées. On peut transformer certains éléments en variables. En fait,fondamentalement, on a besoin d'une seule et unique variable qui changera : lenombre de rectangle. Tout le reste pourra se déduire de cela.

la largeur d'un rectangle est 3/4 de la largeur de l'écran divisé par le nombre

29

Variables et contrôle de flux

de rectangle l'espace entre les rectangle est le 1/4 de la largeur de l'écran divisé par le

nombre de rectangle plus unOn peut donc avoir le programme complet suivant

1 /*Exemple de boucle for*/2 /*************************************3 Constantes du programme4 ************************************/5 int N = 12; //nombre de rectangles6 int L = 600; // largeur de la fenêtre7 int H = 400; // hauteur de la fenêtre8   9 void setup() {10   size(L, H);11   background(128);12   noLoop(); // il n'est pas nécessaire de boucler13 }14   15 void draw() {16   float espace = float(width) * 1 / 4 / ( N+1 );17   float largeur = float(width) * 3 / 4 / N ;18   float ordonnee = float(height) * 3 / 10 ;19   float hauteur = float(height) * 2 / 5 ;20   for (int compteur = 1; compteur <= N ;

compteur++) {21     float abscisse = compteur * espace +

(compteur - 1 ) * largeur;22     rect(abscisse, ordonnee, largeur, hauteur);23   }24 }

RemarquePour calculer l'abscisse, on a rajouté une variable abscisse et fait le calcul en dehorsde la création du rectangle. Cela allége le code et permet de comprendre chaqueétape plus facilement.De façon générale, il est bon de présenter un code lisible qui pourra être corrigé plusfacilement.Pour le calcul de l'espace, de la largeur, de l'ordonnée et de la hauteur, on atransformé en float la hauteur et la largeur de l'écran (qui sont des entiers). Si on nele fait pas, les autres nombres étant tous entier, le calcul sera fait en division entièreet donc arrondi. Du coup, les erreurs d'arrondi se cumuleront et on aura un décalagevisible à l'écran dès que N augmente.

Vous pouvez trouver un exemple en ligne de ce programme9 avec un petit ajoutsupplémentaire : appuyer sur la flèche haut augmente le nombre de rectangle,appuyer sur la flèche bas le diminue.

2. Exercice : La boucle for

9 - http://isn.lec.ac-grenoble.fr/exemples/rectangles/

Variables et contrôle de flux

30

Variables et contrôle de flux

30

Exercice

Une boucle for a pour syntaxe for (instruction1 ; expression ; instruction2) ;La première instruction est exécutée une seule fois ?

vrai

faux

Exercice

la boucle est elle effectuée?

Tant que l'expression centrale est vraie

Tant que l'expression centrale est fausse

Exercice

La deuxième instruction (instruction2) de la boucle est elle exécutée

Au début de chaque itération de la boucle

À la fin de chaque itération de la boucle

Exercice

Une boucle for peut ne jamais être exécutée ?

Vrai

Faux, elle est toujours exécutée au moins une fois

3. La boucle while

Nous avons vu une première structure itérative, la boucle for. Elle est très pratique etassez naturelle lorsqu'il s'agit de faire un nombre d'itération défini à l'avance. Parexemple, aller de 1 à 10, ou aller de 50 à 100 par pas de 5.Il peut arriver que l'on doive faire une itération sans connaître à l'avance le nombred'itération. La condition d'arrêt peut être lié à un événement. Prenons par exemplel'exemple suivant : on veut dessiner une "skyline", c'est à dire des buildings les un àcôté des autres. Ces buildings vont avoir des hauteurs aléatoires mais aussi des

31

Variables et contrôle de flux

largeurs aléatoire. On ne sait donc pas à l'avance combien il y en aura.Le cahier des charges est le suivant :

on part de la gauche a chaque étape, on place un immeuble. Il sera séparé du précédent par 5

pixels. L'immeuble touche le sol et a une hauteur aléatoire entre la moitié de la

hauteur de la fenêtre et les 5/6ème de la hauteur

Génération d'une skyline aléatoire

Lorsque l'on est dans ce cas de figure, les itérations sont mieux contrôlées par laseconde structure itérative de processing : while (qui en anglais signifie tant que).La syntaxe de while est simple

1 while (condition) {2   instructions ;3 }

Tant que la condition est satisfaite, on exécute les instructions du bloc.Notre cahier des charges pourra donc être rempli assez facilement avec le codesuivant :

1 void setup() {2   size(600, 400);3   noLoop(); // il n'est pas nécessaire de boucler4 }

Variables et contrôle de flux

32

Variables et contrôle de flux

32

5 ¬† 6 void draw() {7 ¬† background(128);8 ¬† float abscisse=0;9 ¬† while (abscisse < width ) {10 ¬† ¬† float largeur = random(30,100);11 ¬ † ¬ † f l o a t h a u t e u r =

random(height/2.0,height*5/6.0);12     rect(abscisse,height-hauteur,largeur,

hauteur);13     abscisse += largeur+5;14   }15 }

Une version de démonstration de ce script est consultable en ligne10. En prime, unclique de souris relance le dessin.

Remarque : équivalence while et forSi l'on compare les boucles avec while et for, le langage java, sous jacent àprocessing, permet d'arriver aux même résultats. En effet, si l'on considère la bouclefor

1 for (init ; condition ; update) {2   instructions 3 }

On peut construire une structure avec while qui donnera rigoureusement le mêmerésultat

1 init ;2 while (condition) {3   instructions ;4   update ;5 }

Cette équivalence n'est pas vrai dans tous les langages, les syntaxes étant parfoistrès différentes. L'habitude veut qu'en général on utilise les boucles for lorsque l'on aun "compteur" précis, et les boucles avec while lorsque la condition est "complexe".

Attention : Boucles sans finUne boucle est une structure qui répète une suite d'instructions jusqu'à ce qu'unecondition permette de sortir de la boucle.Lorsque l'on programme, il faut s'assurer que l'on va bien pouvoir sortir de la boucle,sans quoi le programme risque de tourner sans fin, sans que l'on puisse prendre lamain.Il faut garantir la terminaison de la boucle

4. Structures itératives imbriquées

Il arrive parfois que l'on doive mettre des boucles dans des boucles. On parle alors deboucle imbriquées.

10 - http://isn.lec.ac-grenoble.fr/exemples/skyline_base/

33

Variables et contrôle de flux

Examinons le bout de code suivant

1 for (int i=0 ; i < 10; i++) {2   for (int j=0; j < 10; j++) {3     rect (10i+5,10j+5,5,5);4   }5 }

La première ligne est une boucle for qui se répétera 10 fois (i valant de 0 à 9). Lebloc d'instruction à l'intérieur de la boucle sera exécuté pour chaque valeur de i.À l'intérieur de cette boucle, il y a une seconde boucle. Elle aussi se répétera 10 fois,j prenant des valeurs de 0 à 9.Au total, on aura 10 valeurs de j pour chacune des 10 valeurs de i. Cela fait donc 100valeurs.Pour comprendre un peu le mécanisme :

dans un premier temps, i vaut 0. On exécute les instructions. Il y a une boucle. j va valoir 0, puis 1 , puis 2

jusqu'à 9. Dans chacune de ces itérations, on trace des carrés. i vaut 0 et j vaut de 0 à

9. On fait donc une colonne descendante de carrés. Puis ensuite, i vaut 1 et on recommence. Ainsi de suite jusqu'à ce que i ait pour valeur 9.

RemarqueOn a imbriqué dans cet exemple deux boucles for. On pourrait tout à fait enimbriquer encore plus, ou imbriquer des boucles while, ou un mélange de while et defor. Il est très important de prendre le temps de comprendre le mécanisme et de voirdans quel ordre les opérations sont effectuées.

5. Exercice

Une skyline à fenêtreOn a donné dans la partie sur les boucles while un exemple de "skyline", c'est à direde pseudo buildings sur un fond uniforme.On va rajouter un peu de décoration à cette skyline.Pour cela, on mettra quelques fenêtres sur les buildings. Une fenêtre sera juste uncarré de 9 pixels de côtés, avec 3 pixels de chaque côté.

Variables et contrôle de flux

34

Variables et contrôle de flux

34

Une skyline avec des fenêtres

Q u e s t i o n 1Réaliser en processing le code qui permet d'avoir une image du type de celle cidessus.

Q u e s t i o n 2Une ligne de fenêtre, c'est bien, mais on peut mettre un nombre aléatoire de lignes,de 1 à 3, superposées les unes aux autres. Réaliser le code qui permet cela.

Q u e s t i o n 3On peut enfin penser à quelques améliorations : placer un fond plutôt bleuté commeun ciel, et mettre aléatoirement un nombre aléatoire d'étoiles représenté par despetits pixels jaunes.Les fenêtre peuvent aussi être de couleur variables.

6. Structures conditionnelles

Les structures conditionnelles sont des structures qui vont exécuter des instructionsde façon différentes en fonction de condition. L'instruction la plus connu estl'instruction if (qui signifie "si" en anglais). Elle peut être combiné à un else (sinonen anglais). La syntaxe est la suivante (la partie else étant facultative)

1 if (condition) {2   instructions ;

35

Variables et contrôle de flux

3 } else {4   instructions ;5 }

La condition est un booléen, qui peut donc prendre les valeurs true ou false. Cebooléen peut être une variable ou le résultat d'un test. Voici un exemple de codesource avec un branchement conditionnel :

Exemple de branchement if/else

On peut combiner l'instruction else avec un if (sinon, si ....) comme dans l'exempleci dessous

Exemple de structure conditionnelle avec else if

ComplémentIl existe une autre structure conditionnelle qui permet de faire de la disjonction decas. On teste une variable, et suivant la valeur on exécute différentes instructions. Ils'agit de l'instruction swicth(). Voici la syntaxe.

1 switch (variable) {2   case valeur1 : instructions ; break ;3   case valeur2 : instructions ; break ;4   case valeur3 : instructions ; break ;5   case valeur4 : instructions ; break ;6 }

Le mot réservé case sert à distinguer les différentes valeurs possibles de la variable.Le mot réservé break sert à dire que l'on sort des instructions d'évaluations. Dans lecas contraire, on continue d'exécuter toutes les instructions.

Variables et contrôle de flux

36

Variables et contrôle de flux

36

7. Jouons avec les boucles et les tests

Des triangles de couleurs variéesVous allez devoir construire un programme en processing avec le cahier des chargessuivants :

Le programme s'affiche dans une fenêtre dont la taille pourra être modifiée.Pour les essais on prendra 500 par 500.

Le programme va afficher des triangles de couleur qui partiront du cotégauche en allant du côté droit. Les triangles auront tous pour base la largeurde la fenêtre et pour hauteur la hauteur de la fenêtre . Ils seront avec "lapointe en bas".

Le nombre de triangle sera donné par une variable. On en prendra 10 pour lesexemples

Le premier triangle aura son sommet à gauche, le dernier son sommet àdroite.

La couleur de chaque triangle sera aléatoire, avec une opacité comprise entre20% et 80%.

L'affichage se fera en une fois et un clic de souris devra déclencher un nouvelaffichage

Q u e s t i o n 1Réalisez ce programme en processing. Voici un exemple de sortie.

37

Variables et contrôle de flux

Exemple de sortie attendue

Indice :

Pour pouvoir créer le programme, il faudra utiliser les fonctions suivantes : Utiliser la fonction noLoop()11 pour ne pas avoir de dessin perpétuel. Utiliser la fonction triangle12

créer une fonciton mousePressed()13 qui permet de faire quelquechosequand on clique avec la souris.

Utiliser la fonction redraw()14 qui redessine avec la fonction draw() lecanevas de travail

Q u e s t i o n 2Une fois ce premier programme réalisé, vous le modifierez pour avoir le

11 - http://processing.org/reference/noLoop_.html12 - http://processing.org/reference/triangle_.html13 - http://processing.org/reference/mousePressed_.html14 - http://processing.org/reference/redraw_.html

Variables et contrôle de flux

38

Variables et contrôle de flux

38

comportement suivant : Le programme utilise deux mode : dans un premier mode, il change une fois

par seconde l'affichage de triangles. Dans un second mode il affiche une seuleimage et ne change l'image qu'avec un clic gauche de la souris

Le passage d'un mode à l'autre se fait en cliquant avec le bouton droit de lasouris.

Vous modifierez le programme puis enverrez le fichier pde au professeur.

Indice :

On utilisera les fonction loop15 et noLoop16.

D. Un crible d'Eratosthene Visuel

Le crible d'Eratosthene est un un moyen de trouver la liste des nombres premiersjusqu'à une certaine limite. Pour l'obtenir, on construit une liste de nombres entiersde 1 à N, puis on va supprimer tous les nombres qui sont multiples d'un autrenombre. On commence par rayer ainsi tous les multiples de 2. Puis, 3 n'étant pasencore rayé, il est premier. On raye tous les multiples de 3. 4 est rayé, il est premier.5 n'est pas rayé, il est premier, on raye tous ses multiples, etc....L'obejctif de cet exercice est de visualiser le résultat d'un crible d'Eratosthène avecles nombres de 1 à 100. Voici le cahier des charges du programme.

La fenêtre d'affichage est de 700 par 700. Le fond de la fenêtre est noir. Le crible est présenté sous forme d'un tableau de 10 cases par 10 case. Les cases représentant les nombres sont réparties uniformément et font une

taille de 60 par 60. Initialement, elles sont blanches. Le nombre est indiqué en noir dedans. On va colorier avec une couleur à opacité 20 les multiples de 2, puis de 3, de

5 , de 7 . Il est d'inutile d'aller plus loin. En effet, tout nombre plus petit que100 qui n'est pas premier est un multiple d'un nombre plus petit que racine de100, i.e. 10. Le nombre premier qui suit 10 est 11. On prendra du bleu pourles multiples de 2, du rouge pour les multiples de 3, du vert pour les multiplesde 5 et du jaune pour les multiples de 7.

Si le nombre est premier, le carré a une bordure rouge Dans une première version, le résultat est affiché directement. Une version

plus aboutie sera de produire le résultat au fur et à mesure sous formed'animation (facultatif)

15 - http://processing.org/reference/loop_.html16 - http://processing.org/reference/noLoop_.html

39

Variables et contrôle de flux

Affichage du crible d'Eratosthene

Q u e s t i o n Coder le programme décrit ci dessus et envoyez le par courriel au professeur.

Variables et contrôle de flux

40

Variables et contrôle de flux

40

III - Un crible d'Érathostène dynamique

III

Présentation du projet 41

Choix des variables 42

La notion de listes 44

Les traces de pas 46

Le programme 47

Modifier le crible 51

Les listes - suite 51

A. Présentation du projet

Rappel : Crible d'érathostèneDans le chapitre sur les variables, on proposait un exercice sur le crible d'Ératosthèneen utilisant des modulos et en effectuant des calculs. On trichait. On faisait unaffichage du "résultat" sans suivre le processus réel de construction du cribled'Ératosthène. Pour rappel, voici la façon dont est créé le crible d'Érathostène.Le crible d'Eratosthene est un un moyen de trouver la liste des nombres premiersjusqu'à une certaine limite. Pour l'obtenir, on construit une liste de nombres entiersde 1 à N, puis on va supprimer tous les nombres qui sont multiples d'un autrenombre. On commence par rayer ainsi tous les multiples de 2. Puis, 3 n'étant pas encore rayé, il est premier. On raye tous les multiples de 3. 4 est rayé, il n'est pas premier.5 n'est pas rayé, il est premier, on raye tous ses multiples, etc....

MéthodePour commencer à élaborer un programme informatique, la première chose à faireest d'établir un cahier des charges. Le cahier des charges doit décrire :

Les informations que le programme s'attend à avoir en entrée, que ce soit

41

initialement ou à certaines étapes de son déroulement Le fonctionnement attendu du programme En particulier les résultats que le programme devra afficher ou enregistrer

Voici notre cahier des charges. Notre programme est chargé de construire et d'afficher la construction du

crible d'Ératosthène pour les entiers de 2 à 100. La valeur limite pourra êtremodifiable dans un second temps.

La fenêtre du programme sera une fenêtre de 800 par 800 pixels, de couleurnoire.

Dans une première phase, le programme affichera les nombres de 2 à 100dans des carrés blancs de 60 pixels par 60 pixels.. Le texte sera en noir.

Dans un second temps, le crible commencera. Pour chaque nombre, s'il estpremier, le nombre verra sa case entouré d'un rectangle rouge de 5 pixels.Tous ses multiples seront barrés d'un trait d'une couleur aléatoire unique,avec une diagonale qui sera à 10 pixels du coin supérieur gauche pour lepremier, 20 pour le suivant, etc ...

S'il n'est pas premier, on passe au suivant. Une fois l'ensemble du tableau parcouru, on s'arrête. Un clic sur le crible en train de se faire accélère le processus. Un clic sur le crible achevé relance tout.

Un exemple en fonctionnement est disponible en ligne17

B. Choix des variables

MéthodeAvant de commencer à concevoir le code, nous allons nous poser la question desvariables dont nous allons avoir besoin.Tout d'abord, nous déclarerons des variables pour certaines valeurs qui serontconstantes au cours du programme mais que nous pouvons vouloir changerfacilement entre deux exécutions. Par exemple, plutôt que de coder l'entier maximumen mettant "100" partout dans le programme, nous allons stocker cela dans unevariable Nmax. C'est plus facile de le modifier ensuite à un seul endroit que derechercher toutes les occurences de 100 dans le programme. De la même façon, onstockera les couleurs dans des variables, afin de pouvoir les modifier facilement.Dans certains langages de programmation, on parle de constantes (c'est à dire desvariables dont la valeur ne sera pas modifiée tout au long du programme)Ensuite, nous allons devoir stocker des variables liées à l'algorithme du programme.Là, on entre dans la "logique" du programme.

17 - http://isn.lec.ac-grenoble.fr/processingjs/crible_dynamique/

Un crible d'Érathostène dynamique

42

Un crible d'Érathostène dynamique

42

Constantes du programme

Voici les variables qui correspondent aux constantes de notre programme. Plutôt quede mettre un entier maximum, on définit la taille de notre affichage, en ligne,colonne et on stocke aussi la taille des cases d'affichage, bordure comprises.

Variables du programme de crible

Il nous faut stocker la liste des nombres de 2 à N, avec l'indication pour chacun deson caractère premier ou non. Nous détaillerons un peu plus loin ce concept de liste.La variable etape est un nombre qui sert à indiquer l'état dans lequel se trouve notreprogramme. En effet, il y a différentes phases dans le programme et il faut stockerquelque part la phase dans laquelle nous sommes. Nous allons adopter la conventionsuivante :

0 sera l'état d'initialisation 1 sera l'état ou nous parcourons la liste des nombres 2 sera l'état ou nous sommes en train de cocher les multiples d'un nombre 3 sera l'état final, ou nous attendons le signal pour recommencer

43

Un crible d'Érathostène dynamique

États possibles du programme

Ensuite, nous avons besoin d'un entier qui indique le nombre entier dont noussommes en train de nous occuper. Nous l'appellerons entier.Lorsque nous parcourons les multiples d'un entier, nous avons besoin de savoir à quelmultiple nous nous trouvons. Cela sera stocké dans une variable de type entier quenous appellerons multiple.A chaque fois que nous surlignons les multiples d'un nombre premier, nousaugmentons le décalage. Pour connaître la position de ce décalage, nous utiliseronsune valeur entière stockée dans decalage

C. La notion de listes

DéfinitionUne liste, appelée aussi tableau dans certaine circonstance (array en anglais) est, enprocessing, une variable contenant plusieurs variables du même type. Voici ladéfinition des listes dans la documentation de processing18. Chaque élément de laliste a une position qui lui est associée, que l'on appelle son index dans la liste. Leséléments de la liste sont numérotés de façon séquentielle (i.e. sans "trou" dans laliste des nombres)

AttentionDans le monde de l'informatique comme dans les suites numériques, le choix est faitde commencer avec un premier index qui vaut 0. Ainsi, une liste de n éléments a desindex qui vont de 0 à n-1 (et non pas n). Si je stocke les 12 mois de l'année dansune liste, janvier aura l'index 0 et décembre aura l'index 11.

Déclaration de variableOn déclare une liste en indiquant le type de variable que l'on va stocker dedans et en

18 - http://processing.org/reference/Array.html

Un crible d'Érathostène dynamique

44

Un crible d'Érathostène dynamique

44

utilisant les crochets.

1 int[] liste_entiers ;2 String[] listes_mois ;

Instanciation de la listePour pouvoir utiliser une liste, il faut lui donner un espace en mémoire et lui donnerune taille initiale. On utilise un mot clef "new" disant que l'on va créer une nouvelleliste. Ce mot clef est en fait lié à la création de toutes les variables de type "objet"que l'on peut rencontrer dans bien des langages de programmation.

1 liste_entiers = new int[40] ;2 listes_mois = new String[12];

Bien entendu, comme pour les autres variables, la déclaration et l'instanciationpeuvent se faire en une seule ligne.Attention ! la liste des mois ci dessus est bien numérotée de 0 à 11 !On peut aussi remplir une liste automatiquement au moment de l'instanciation enutilisant les accolades et les virgules

1 S t r i n g [ ] a r c _ e n _ c i e l ={"rouge","orange","jaune","vert","bleu","indigo","violet"} ;

taille d'une listeOn peut connaître la taille d'une liste en accédant à la variable length de l'objet

1 nombre_entiers = liste_entiers.length ;2 nombre_mois = liste_mois.length ;

Accès à un élément de la liste.Pour accéder à un élément de la liste, que ce soit pour le lire ou pour l'écrire, onutilise les crochets. Voici par exemple une opération pour indiquer janvier commepremier mois de l'année, et pour calculer la somme des termes d'une liste denombres)

1 listes_mois[0]="janvier" ;2 int resultat = 0 ;3 for (int i=0 ;i<=liste_entiers.length ;i++) {4   resulat += liste_entiers[i] ;5 }

Opérations sur les listesIl y a quelques opérations à connaître sur les listes. La première est la fonctionappend() qui permet de rajouter un élément à la fin de la liste. la fonction shorten()au contraire réduit la liste d'un élément. La fonction concat() permet de coller deuxlistes l'une à la suite de l'autre.

1 m a _ l i s t e = a p p e n d ( m a _ l i s t e , " n o u v e lélément") ;

2 ma_liste = shorten(ma_liste) ;3 ma_liste = concat(liste_1,liste_2);

ComplémentAttention. Une liste est un objet, et à ce titre, la manipulation est parfois délicate. Il

45

Un crible d'Érathostène dynamique

faut faire attention lorsque l'on souhaite recopier une liste. En effet, si je veux avoirrecopier la valeur d'un entier, pas de problème .

1 int a=5 ;2 int b ;3 b=a ; // maintenant, b vaut 54 b=7 ; // maintenant, b vaut 7. Quant à lui, a

vaut toujours 5Le même comportement n'est plus valable avec une liste

1 int[] liste_1 = {0,1,2} ;2 int[] liste_2 ;3 liste_2 = liste_1 ; // maintenant, liste_2 est LE

MEME OBJET que liste_14 liste_2[1]=14 ; // le second élément de

liste_2 est 14. Mais le second élément de liste_1 aussi ( ce n'est plus 1)C'est pour cela que si l'on veut faire une copie d'une liste, on doit utiliser la fonctionarrayCopy()

1 int[] liste_1 = {0,1,2};2 int[] liste_2 =new int[3];3 arrayCopy(liste_1,liste_2);4 liste2[2]=17; // le dernier élément de liste_2

vaut 17, mais celui de liste_1 vaut toujours 2.

D. Les traces de pas

On va faire un petit exercice pour vérifier l'utilisation des listes. On va faire unprogramme qui garde les traces de pas de notre souris. Dans une fenêtre de 800pixels par 800 pixels, on va tracer en représentant par des cercles les dernièrespositions de la souris. On enregistre pour cela les 100 dernières positions dans untableau.Chaque fois que la souris est déplacée, on stockera les coordonnées de la souris dansune liste pour l'abscisse et une liste pour l'ordonnée.Pour chacun des points de la liste, on trace un cercle de rayon croissant (le dernier aun rayon de 50, le premier de 0).Voilà un exemple de rendu19

Pour pouvoir fonctionner, il faudra implémenter une fonction mouseMoved()20

Q u e s t i o n 1Créer un programme processing qui donne ce résultat.

Indice :

Il faut stocker la position de la souris à l'index le plus élevé du tableau et chaquefois, il faut décaler les éléments contenus dans le tableau.

On constate sur le programme proposé un problème. Les cases qui n'étaient pasremplies du tableau contiennent en fait les valeurs "0" et du coup, on a des cerclesqui sont dans le coin en haut à gauche de la fenêtre lorsque le nombre de

19 - http://isn.lec.ac-grenoble.fr/processingjs/trace_souris/20 - http://processing.org/reference/mouseMoved_.html

Un crible d'Érathostène dynamique

46

Un crible d'Érathostène dynamique

46

mouvement n'est pas encore assez élevé.

Q u e s t i o n 2Proposer une solution pour supprimer ces artefacts visuels liés au démarrage

E. Le programme

Nous allons maintenant nous intéresser à la logique du programme et décrire lesdifférentes étapes de l'écriture. Tout d'abord, il faut ouvrir la fenêtre graphique à labonne dimension et initialiser les différents paramètres. C'est le rôle de la fonction desetup.

1 void setup() {2 size(largeur,hauteur);3 background(couleurFond);4 frameRate(5);5 textAlign(CENTER,CENTER);6 }

Ensuite, processing lancera la boucle de la fonction draw. À ce moment là, notreetape est 0, nous devons faire l'initialisation. Pour cela :

on met un fond noir on place les carrés blanc pour les nombres de 2 à Nmax. Il faut bien réfléchir

à l'utilisation de la division entière et du modulo pour placer les carrés. au passage, on va aussi remplir la liste des nombres en indiquant que tous les

nombres sont premiers On passe la variable étape à 1 pour commencer le parcours.

phase d'initialisation

Intéressons nous maintenant à l'étape 1, le parcours du tableau. Là, on a 3 caspossibles :

On a dépassé la limite. On passe en état 3 (fini) On est sur un nombre premier (qui n'a jamais été coché). On va cocher tous

les multiples de ce nombre, donc passer en état 2. On va aussi entourer enrouge la case pour indiquer que c'est un nombre premier.

47

Un crible d'Érathostène dynamique

On est sur un nombre qui n'est pas premier. Il n'y a rien de particulier à faire,sauf passer au suivant.

Étape 1 : Parcours du tableau

Si l'on est tombé sur un nombre premier, on passe l'étape à 2 pour cocher tous sesmultiples. La variable multiple va être incrémenté de 1 à chaque étape, et on va cocher entier *multiple. On aurait pu commencer avec multiple à 1, mais dans l'étape 1, oncommence avec multiple = entier. C'est une légère optimisation car si on a deuxnombre premiers a et b, avec a <b , le multiple de b b*a est déjà coché car c'est unmultiple de a. On est ainsi sur que tous les multiples de b plus petits que b*b sontdéjà cochés dans le tableau.On va incrémenter les multiples jusqu'à dépasser la valeur maximale et à chaqueétape :

indiquer dans la liste que le nombre n'est pas premier le manifester graphiquement en cochant la case

Une fois la valeur maximale dépassée, on retourne à l'état 1 pour parcourir letableau.

Un crible d'Érathostène dynamique

48

Un crible d'Érathostène dynamique

48

Étape 2 : cocher les multiples

En résumé, voici la fonction draw() dans son ensemble. On notera l'usage de lastructure switch21 pour la disjonction de cas.

21 - http://processing.org/reference/switch.html

49

Un crible d'Érathostène dynamique

Fonction draw() dans son ensemble

Un crible d'Érathostène dynamique

50

Un crible d'Érathostène dynamique

50

Il ne reste plus qu'à implémenter le clic de souris. Pour cela, on crée la fonctionmousePressed().

Si on est dans l'étape 3, on recommence tout avec l'étape 0. Si on est dans une autre étape, on augmente le frameRate à 10 000, c'est à

dire le plus rapide possible.

Gestion du clic de souris

Vous pouvez maintenant télécharger le code source du programme et le modifier àvotre convenance.

F. Modifier le crible

Le crible d'Eratosthene est fait. Vous pouvez le téléchargerL'objectif maintenant est de transformer ce programme pour l'adapter à vos souhaits.

Q u e s t i o n Modifiez le programme pour répondre à un questionnement personnel. Voici quelquesexemples

au lieu de cocher les cases, on peut les remplir d'une couleur transparente ensurimpression

on peut cocher absolument tous les multiples d'un nombre entier pour avoirl'intégralité des diviseurs.

on peut au lieu d'une coche placer des pastilles colorées pour chaque nombrepremier

On peut faire en sorte que chaque case ne soit coché qu'une seule fois et plusaprès (comme c'est le cas dans l'exemple proposé sur le web)

etc ....

G. Les listes - suite

Une fonctionnalité revient souvent dans les listes. On a vu qu'on pouvait créer uneliste de n'importe quel type d'objet. On peut donc créer des ... listes de listes. En

51

Un crible d'Érathostène dynamique

pratique, ce sera des tableaux. On peut imagine avoir des tableaux à deuxdimensions, à trois dimension, voire plus. La notation est simple.Définissons par exemple une grille de sudoku. C'est une grille de 9 colonnes par 9rangées.

1 int[][] sudoko = new int[9][9]¬†;Si on veut placer une valeur de 4 dans la case de la sixième colonne, troisièmerangée, on oubliera pas de partir ... de 0

1 sudoku[5][2] = 4 ;

ConseilAttention ! On a ici une représentation qui est visuelle de la grille de sudoku. Ce n'estpas nécessairement la plus adaptée. Avec l'usage des modulos par exemple, et desdivisions entières, on peut parfaitement imaginer définir une liste de 81 éléments. Sion veut placer 4 dans la sixième colonne à la troisième rangée, on aura alors le codesuivant.

1 int[] sudoku = new int[81] ;2 sudoku[ 5 + 2*9 ] = 4;

Dans ce cas là, passer d'une ligne à l'autre revient à ajouter 9. Quand auxdiagonales, on peut ou retrancher 8 ou 10. Cela peut être avantageux.A contrario, on pourrait aussi considérer qu'une grille de sudoku est constituée de 3colonnes et 3 rangées de grilles, qui font chacune 3 colonnes par 3 rangées denombres. La sixième colonne troisième rangée est donc la troisième colonne dans ladeuxième grille en partant de la gauche, et la troisième ligne.

1 int[][][][] sudoku = new int[3][3][3][3]¬†;Chacune de ces conceptions a des avantages et des inconvénients. Il n'y en a pasune plus "vraie" que l'autre. Parfois, tout linéariser peut être un avantage, pour peutque l'on réfléchisse bien

Toutes les fonctions et propriétés des listes vues auparavant restent bien entenduvalables.

Un crible d'Érathostène dynamique

52

Un crible d'Érathostène dynamique

52

IV - La programmationmodulaire

IV

Réutiliser et clarifier : créer des étoiles 53

Des paramètres pour nos étoiles 56

Rendre modulaire la skyline 57

Retourner une valeur 58

Lorsque nous écrivons du code informatique, certaines parties peuvent être répétitives. Nousavons vu avec les structures itératives la possibilité de répéter une même suite d'instructionsun certains nombre de fois, ou jusqu'à réalisation d'une condition. Mais que se passe t'il si onsouhaite réaliser une même suite d'instruction à de multiples reprises, non pas à la suite,mais à des endroits différents du programme ? Pour répondre à ce besoin, on va utiliser la notion de fonction informatique. On parle aussi desous-programme.De plus, les fonctions informatiques permettent de découper le code de façon à le rendre plusclair.

A. Réutiliser et clarifier : créer des étoiles

Fabriquer une étoileReprenons le programme que nous avions utilisé pour créer une "skyline". Nousavions bâti des "immeubles", placé des fenêtres sur les immeubles, puis nous avionsproposé d'étendre le programme en positionnant des étoiles dans le ciel. nos étoilesétaient juste des pointsNous pouvons réfléchir à une création d'étoiles un peu plus avancées. Voici leséléments que l'on peut considérer :

Une étoile peut être considéré comme un ensemble de faisceaux lumineuxpartant d'un centre.

Ces faisceaux, tous de la même couleur pour une étoile donnée. l'angle entre deux faisceaux successifs est variable. Du coup, le nombre total

de faisceaux varie La longueur des faisceaux est variable, certains sont plus longs que d'autres.

Les plus longs sont plus rares.On va traduire tout cela par un code informatique pour produire les étoiles.

53

La première chose à faire est de choisir aléatoirement la position du centre desétoiles

1 float x0 = random(width) ;2 float y0 = random(height) ;

Ensuite, nous devons définir le diamètre maximum de l'étoile, puis la couleur del'étoile

1 float rayon = random (5,50) ;2 stroke (random(55, 255), random(155, 255),

random(155, 255), 25);Ensuite, nous allons faire des traits autour du centre. On aura un angle qui va varierentre 0 et 2π, par pas successifs variables. On le stockera dans un variable angle.À chaque nouvelle valeur de l'angle, on dessinera une ligne partant du centre quiaura une longueur variable. Pour que les lignes courtes soient plus rares, on vamodifier la fonction random. On prendra un nombre aléatoire entre 0 et 1 que l'onélèvera à la puissance 4. En effet, la fonction puissance quatrième a une répartitionou les petites valeurs sont plus nombreuses entre 0 et 1.

1 float angle=0;2 while ( angle < TWO_PI ) {3  float longueur = pow(random(1), 4)*rayon;4  float x=x0+cos(angle)*longueur;5  float y=y0+sin(angle)*longueur;6  line(x0,y0,x,y);7  angle += random(0.03, 0.1);8 }

En utilisant cet algorithme on aura une image du type suivant.

La programmation modulaire

54

La programmation modulaire

54

Un fond étoilé

Isoler cette créationLa création de l'étoile pourrait être insérée dans la fonction draw(). Mis au lieu decela, on peut isoler la création de l'étoile. Cela aura pour effet de rendre leprogramme nettement plus lisible. L'idée est d'isoler les ensembles d'instruction quisont cohérents dès qu'il y a plus de dix à quinze ligne. On a déjà vu un certainnombre de fonctions, fournies avec Processing, que l'on devait créer : la fonctionsetup, la fonction draw, les fonctions qui sont appelées lors d’événements (souriscliqué ou déplacée par exemple).Pour créer une fonction, il suffit d'indiquer :

Le type de valeur que la fonction peut retourner. Si la fonction en retourneaucune valeur, on met le type void.

Le nom de la fonction Les paramètres de la fonction entre des parenthèses.

Dans notre cas, la fonction étoile ne renvoie rien de particulier, elle effectue un tracé.Dans certains langages de programmation, lorsqu'une fonction ne renvoie rien, on neparle pas de fonction mais de procédure. Dans la majorité, on dit que la fonctionretourne une variable de type void (ce qui signifie vide en anglais)On va donc créer la fonction dessineEtoile

1 void dessineEtoile() {2   float x0 = random(width);3   float y0 = random(height);4   float rayon = random(5, 50);5   stroke(random(55, 255), random(155, 255),

55

La programmation modulaire

random(155, 255), 25);6   float angle=0;7   while ( angle < TWO_PI ) {8     float longueur = pow(random(1), 4)*rayon;9     float x=x0+cos(angle)*longueur;10     float y=y0+sin(angle)*longueur;11     line(x0,y0,x,y);12     angle += random(0.03, 0.1);13   }14 }

Pour appeler la fonction, on se contente de l'invoquer par son nom dans le codesource. Voilà par exemple pour la fonction étoile qui remplira aléatoirement le ciel

1 for (int i=0; i<450; i++) {2   dessineEtoile();3 }

B. Des paramètres pour nos étoiles

Dans la partie précédente, nous avons défini une fonction pour tracer des étoiles. Ona ainsi, d'une certaine façon, étendu le langage. Au lieu de créer des rectangles, desellipses, des triangles, des lignes, nous pouvons maintenant créer des étoiles.Imaginons que nous voulons pouvoir réutiliser cette fonction pour tracer des étoiles,un peu comme nous utilisons les fonctions line(), rectangle() ou ellipse().Il y a un problème néanmoins. Les fonctions de processing permettent de placer leséléments graphique de façon précise. Notre fonction dessineEtoile() se contente deplacer des étoiles aléatoirement n'importe où dans la fenêtre graphique.Nous allons donc modifier la fonction pour qu'elle accepte des paramètres. Nousavons trois paramètres que nous voulons donner à notre fonction :

L'abscisse du centre de l'étoile L'ordonnée du centre de l'étoile Le rayon de l'étoile

La syntaxe de notre fonction sera donc modifiée au moment de sa déclaration et deson appel. La déclaration de la fonction sera maintenant la suivante :

1 void dessineEtoile(float x0, float y0, float rayon) {2   stroke(random(55, 255), random(155, 255),

random(155, 255), 25);3   float angle=0;4   while ( angle < TWO_PI ) {5     float longueur = pow(random(1), 4)*rayon;6     float x=x0+cos(angle)*longueur;7     float y=y0+sin(angle)*longueur;8     line(x0,y0,x,y);9     angle += random(0.03, 0.1);10   }11 }

Et on appellera la fonction de la sorte :

La programmation modulaire

56

La programmation modulaire

56

1dessineEtoile(random(width),random(height),random(5,50))

Complément : Des paramètres optionnels ?Mais on peut aller encore plus loin. L'important, dans notre cas, c'est la position del'étoile. Finalement, la taille peut être aléatoire et on peut ne pas s'en soucier. Ilfaudrait donc que le paramètre de la taille soit optionnel, comme c'est le cas pourcertaines fonction de Processing.Processing repose sur le langage Java dans lequel les paramètres optionnels d'unefonction n'existe pas. Cependant, il existe un autre mécanisme qui permet de créerdeux fonctions avec le même nom, pour peu que la liste des paramètres ne soit pasla même. Cela s'appelle la surcharge. Ainsi, nous pouvons définir une fonctiondessineEtoile ou seules les coordonnées du centre sont fournies en paramètre.

1 void dessineEtoile(float x0, float y0, float rayon) {2   stroke(random(55, 255), random(155, 255),

random(155, 255), 25);3   float angle=0;4   while ( angle < TWO_PI ) {5     float longueur = pow(random(1), 4)*rayon;6     float x=x0+cos(angle)*longueur;7     float y=y0+sin(angle)*longueur;8     line(x0,y0,x,y);9     angle += random(0.03, 0.1);10   }11 }12 void dessineEtoile(float x0, float y0) {13   dessineEtoile(x0,y0,random(5,50));14 }

Même si le nom de la fonction est le même, on a en fait deux fonctions différentes :la fonction dessineEtoile avec deux paramètres et la fonction dessineEtoile avec troisparamètres.On pourrait dans le même esprit rajouter la couleur comme paramètre optionnel.

C. Rendre modulaire la skyline

Nous avons vu dans ce chapitre comment faire pour rendre modulaire la création desétoiles. On va maintenant travailler ainsi pour les immeubles

Q u e s t i o n Modifier le programme de la skyline pour que les immeubles soient eux aussi crééspar une fonction. La fonction devra fabriquer des immeubles avec des fenêtreséclairées de haut en bas, et certaines non éclairées. La fonction prendra enparamètre :

les coordonnées du coin en haut à gauche de l'immeuble sa hauteur et sa largeur

57

La programmation modulaire

D. Retourner une valeur

Nos fonctions commencent toute par void, indiquant qu'elle ne retourne rien. Mais onpeut parfaitement imaginer qu'une fonction renvoie une valeur. Elle est alorsconforme à l'idée que l'on se fait d'une fonction au sens mathématique du terme : onfourni des paramètres et elle renvoie une valeur.Le mot clef qui permet de renvoyer une valeur est return. Voici par exemple unefonction qui renverrait le cube de la valeur qu'on lui donne en paramètre.

1 int cube(float x) {2   float valeur = x * x * x ;3   return valeur ;4 }

Le mot clef peut aussi servir dans le cas d'une fonction dont le type de retour estvoid. A ce moment là, il se contente de quitter la fonction. Voici un exemple :

1 void dessineEtoile(float x0, float y0, float rayon) {2   if (rayon < 0) return ; // on arrête là, le

rayon ne peut être négatif3   // sinon, on trace l'étoile ....4 }

La programmation modulaire

58

La programmation modulaire

58

V - Exercice : PUISSANCE 4 !

V

L'objectif de ce mini projet est de créer un jeu de puissance 422. Le cahier descharges sera le suivant :

Le jeu se jouera à deux joueurs, le premier a une couleur, le second une autrecouleur.

Pour jouer, il suffit de cliquer dans une colonne. Le jeton se place au bonendroit

Le programme détecte les configurations gagnantes et indique la fin de lapartie

Le jeu est alors fini et cliquer sur l'interface fait commencer une nouvellepartie.

Le programme détecte aussi le fait que tous les pions aient été joué et indiquele match nul.

Une version fonctionnelle faite en processing est disponible à cette adresse :http://isn.lec.ac-grenoble.fr/processingjs/puissance4/Pour commencer le TP, télécharger le fichier contenant un squelette d'application qu'ilsuffira de compléter.

Q u e s t i o n 1Téléchargez et ouvrez le fichier squelette dans l'éditeur de Processing. Au début duprogramme on trouve les variables que l'on va utiliser. La variable entière joueur indique si c'est au joueur 1 ou 2 de jouer.La variable booléene gagne indique si la partie est gagnée ou non.La variable tour indique le nombre de tours joués. À 42 tours, la partie est achevée.Enfin, la variable plateau va stocker les valeurs des 42 cases : 0 pour vide, 1 ou 2 s'ily a le jeton d'un joueurExpliquer comment, en utilisant les opérateurs mathématiques usuels, on passe dunuméro de la case (entre 0 et 41) à la ligne et la colonne (entre 0 et 5 pour la ligne,0 et 6 pour la colonne), et réciproquement.

Indice :

Il y a deux solutions possibles. Le choix de la solution aura des conséquences surle reste.

Q u e s t i o n 2On va maintenant s'intéresser au squelette fournit. Faites la liste des fonctions etessayez d'expliquer le fonctionnement de chacune des fonctionnes déjà écrite.

22 - http://fr.wikipedia.org/wiki/Puissance_4

59

Q u e s t i o n 3La fonction joue prend en paramètre le numéro de colonne. Elle doit :

si la colonne est pleine retourner -1 si la colonne n'est pas pleine, elle doit retourner le numéro de la ligne la plus

basse qui est libre et mettre à jour la variable plateau pour que la case correspondante soit

attribuée au joueur.Compléter la fonction joue() et testez là (sans vous soucier des conditions devictoire)

Q u e s t i o n 4Il faut maintenant étudier les cas de victoire. L'étude de ces cas est décomposée en 4fonctions, pour étudier la victoire selon les 4 possibilités : horizontale, vertical,diagonale ascendante, diagonale descendante.Remplissez ces 4 fonctions et vérifiez que tout marche.

Indice :

Le mieux est de faire fonction par fonction.

Exercice : PUISSANCE 4 !

60

Exercice : PUISSANCE 4 !

60

VI - La programmationobjet

VI

Un chat est un chat. 61

Définition d'une classe 62

Définir la classe dans un nouveau fichier. 63

Utilisation d'un objet 65

De nouvelles voitures 67

Nous avons vu dans les chapitres précédents comment modulariser notre code informatiqueen créant des fonctions. Lorsque le programme devient de grande taille, séparer les actionsen fonction peut ne plus être suffisant. La programmation objet est faite pour permettre demaintenir un code complexe sur la durée grâce à des notions comme l'encapsulation etl'héritage.

A. Un chat est un chat.

Considérons un chat. Un chat a une certaine taille. Il a aussi un poids. Une couleurdes yeux. Une longueur de queue, une longueur de poil. Tout cela ce sont lescaractéristiques d'un chat. Un chat peut accomplir un certain nombre d'actions.Miauler, ronronner, détaler, vous empêcher de lire, manger, et surtout dormir. Toutesces actions peuvent être accomplies par les chats.Considérons maintenant Félix. Félix est un chat. Il fait ses 3 kilos, il mesure 45 cm delong, il a des yeux verts, et une queue courte, ainsi qu'un poil mi long.Félix peut miauler, et faire toutes les actions qu'un chat peut faire.Simon est un autre chat. Il mesure 50 cm de long, a des yeux jaunes, une queuelongue, un poil court. Il peut lui aussi miauler et faire les actions d'un chat.Lorsque l'on parle de chats, il faut distinguer deux choses : le concept général duchat, qui est une idée abstraite, et les chats "concrets", comme Félix, Simon ou lechat de la voisine.Si nous devions modéliser un chat de façon informatique, nous pourrions utiliser lanotion d'objet.

Définition Une classe est un concept informatique. C'est un modèle abstrait qui indique

61

des caractéristiques et des fonctionnalités. Un objet est ce que l'on appelle une instance de la classe. C'est une variable

informatique qui a les caractéristiques et les fonctionnalités de la classe. Une classe indique des variables qui seront associées au objets. On parle de

propriétés. Une classe définit des fonctions qui seront associées aux objets. On parle de

méthodes.

ExempleÀ titre d'exemple, vous pouvez faire l'exercice suivant : définissez une classe pourune voiture. Pour cela, vous devrez faire la liste de ce qui caractérise une voiture (lespropriétés), puis la liste de ce que peut faire une voiture (les méthodes)

Caractéristique d'une voiture Actions possible pour une voiture

...........

...........

...........

...........

...........

...........

...........

...........

Le fait de relier des variables et des fonctions à un objet s'appelle l'encapsulation.C'est un concept central de la programmation objet, et c'est lui qui nous permettrad'avoir un code maintenable.

B. Définition d'une classe

Nous allons maintenant créer un petit jeu tout simple : une route défile de droite àgauche, le joueur controle une voiture sur la route, il peut accélérer, ralentir, tournerà gauche (ce qui signifie monter vers le haut) ou à droite (descendre vers le bas).Pour cela il utilisera les flèches :

Les flèches de gauche et de droite permettent de touner. La flèche vers le haut fait accélérer La flèche vers le bas fait ralentir

Sur la route, d'autres voitures circulent. Il y en a de plus en plus, et le jeu va aller deplus en plus vite. L'objectif est de rester sur la route sans collision le plus longtempspossible.On pourrait définir la voiture comme une variable globale et définir chacune desfonctions qui la concernent dans le code. Mais plutôt que cela, nous allons définir lavoiture comme l'instance d'une classe voiture, et les voitures rencontrées seront ellesaussi des instances de la classe voiture.Comment fait on en pratique dans processing pour définir une classe ?Passons à la pratique. Les éléments suivants sont à prendre en compte :

Une classe se définit en utilisant le mot clef class. On indique en premier les propriétés de la classe. Ensuite on indique les méthodes, c'est à dire les fonctions qui agissent sur la

classe. Parmi les méthodes, une méthode spéciale existe. Elle porte le même nom

La programmation objet

62

La programmation objet

62

que la classe. C'est le constructeur qui est appelé lorsque l'on crée uneinstance de notre classe.

Voici la définition de notre classe de voiture.

Définition de la classe voiture

C. Définir la classe dans un nouveau fichier.

Créer une classe, c'est créer un nouveau type. L'environnement de processingpermet de séparer les fichiers pour mettre les définitions des classes dans un fichierséparé. Ainsi, on peut organiser ses fichiers pour que le fichier principal ne fasse pasapparaître la mécanique inhérente à la classe. Cela permet d'avoir un programmeplus facile à lire.Imaginons que note projet s'appelle course. Le fichier principal sera course.pde, ilsera dans un répertoire course. L'environnement de développement de processingaura un onglet d'ouvert avec pour nom "course". A droite de cet onglet, on voit uneflèche qui permet d'ouvrir un menu déroulant. C'est le premier qui nous intéresse(nouvel onglet, new tab en anglais). On pourrait aussi utiliser le raccourci

63

La programmation objet

Ctrl+Shift+N (ou sur un mac Cmd+Shift+N)

Ouverture d'un nouvel onglet

Une fois que nous avons sélectionné l'ouverture, il nous demande le nom du nouveaufichier. Comme ce sera un fichier, la règle usuelle de se limiter aux lettres nonaccentuées, aux chiffres, aux tirets et aux soulignés est préférable. On peut choisirn'importe quel nom pour le fichier. En général, pour indiquer que ce fichier décriraune classe, on met le nom de la classe suivi de Class. Ici, on va implémenter laclasse voiture. On peut prendre pour nom VoitureClass.

Nommage du nouveau fichier

Un nouvel onglet VoitureCLass est créé et il sera enregistré dans le fichierVoitureClass.pde du répertoire course. On peut maintenant y mettre la définition dela classe.

La programmation objet

64

La programmation objet

64

Duex onglets dans l'IDE processing

D. Utilisation d'un objet

Une fois que notre objet est défini, comment allons nous l'utiliser ?C'est assez simple. Tout d'abord, on va commencer par créer une voiture. Cettevoiture sera stocké dans une variable que l'on appellera bolide. Elle représentera lavoiture du joueur.La classe Voiture que nous avons défini est un nouveau type. La déclaration d'unevariable de ce type se fait comme pour les autres variables

Définition d'une variable contenant un objet

Une fois que nous créé la variable, il faut faire une opération pour réserver l'espacemémoire et initialiser la variable. Cela s'appelle instancier l'objet. Le mot clef que l'onutilise pour instancier est le mot new

65

La programmation objet

Instanciation d'un objet

Maintenant, notre bolide est instancié. C'est donc une voiture "concrète". Nous allonspouvoir utiliser ses fonctionnalités. Pour utiliser une fonction qui s'applique à un objet(on a vu que cela s'appelait une méthode), il suffit d'utiliser le point. Voici parexemple la fonction qui va agir en fonction de la touche qui est pressée.

Utilisation de méthodes

Si on voulait accéder à une propriété de l'objet, on procéderait de la même façon. Parexemple, l'abscisse de la voiture est stocké dans dans une variable abscisse. Pourfixer l'abscisse à 0, on utiliserait ainsi

La programmation objet

66

La programmation objet

66

1 bolide.abscisse = 0 ;

Fondamental: L'encapsulationL'encapsulation, c'est le fait de stocker les propriétés et les fonctions de l'objet àl'intérieur de l'objet. Lorsque le code devient un peu complexe, l'avantage estévident. Si par exemple, nous avons deux voitures, sans la programmation objet, onpourrait utiliser deux variables pour les abscisses, par exemple abscisseV1 etabscisseV2. Pas très pratique pour s'en souvenir.Là, on aura simplement, si les deux voitures s'appellent bolide et escargot lespropriétés bolide.abscisse e t escargot.abscisse. On peut créer autant devoitures que l'on veut, ce sera toujours simple d'accéder à l'abscisse.Dans le même ordre d'idée, on a une fonction ralentir pour nos voitures. Imaginonsque l'on ait aussi des vélos et des camions, qui ralentissent différemment. Enprogrammation classique, on aurait trois fonctions distinctes : ralentirVoiture,ralentirCamion, et ralentirVelo par exemple. Chacune prendrait un argument

1 ralentirVelo(biclou);2 ralentirVoiture(bolide);

En programmation objet, la méthode est liée à l'objet. Elle peut donc s'appelerralentir pour chacune des classes, ce n'est pas gênant. On sait que dans tous les cas,il faut ralentir. Suivant le type d'objet, la fonction agit différemment, mais c'est bienle même nom pour un comportement de même nature.

1 bolide.ralentir() ;2 biclou.ralentir() ;

Le code est ainsi beaucoup plus simple à lire et à maintenir. En effet, on ne risquepas de faire de doublon sur les noms de fonctions.

E. De nouvelles voitures

Nous allons maintenant nous intéresser aux autres véhicules, les obstacles qui vontse présenter sur notre route. Ce seront des objets de type voiture. Mais dans quellevariable les stocker ? On pourrait utiliser un tableau, mais cela ne serait pas le plussimple. En effet, les voitures vont apparaître au fur et à mesure et on va en avoir unnombre variable.Pour stocker les différents objets voiture, on va utiliser un objet défini dans lelangage de Processing : les ArrayList23

Une ArrayList est un peu comme un tableau mais qui serait de taille dynamique. Siun tableau peut être comparé à une étagère, une ArrayList est une étagère de taillevariable. Pour stocker les voitures qui feront obstacles, c'est donc le bon type. Eneffet, au dépaert, il n'y aura que quelques voitures en obstacle, puis il y en aura deplus en plus. On pourrait utiliser un tableau de taille fixe, mais il est plus intéressantd'utiliser une ArrayList.La déclaration d'une variable de type ArrayList se fait en mettant le type de lavariable entre des signes inférieurs et supérieurs. Ici, on va déclarer une ArrayList quicontiendra des voitures.

23 - http://processing.org/reference/ArrayList.html

67

La programmation objet

Déclaration d'une ArrayList

Les Arraylist sont des ... objets. Il faudra donc instancier notre ArrayList pour pouvoirl'utiliser. on procédera comme avec les autres objets, en utilisant le mot clef new.

Instanciation d'un objet ArrayList

Un objet de type ArrayList a les méthodes suivantes qui vont nous intéresser : add() : permet d'ajouter un élément à la liste get(index) : renvoie l'élément de la liste de numéro index. clear() : supprime tous les éléments de la liste contains(objet) : retourne true si l'objet est dans la liste, false sinon isEmpty() : méthode qui retourne true si la liste est vide, false sinon indexOf(objet) : retourne l'index de la première occurence de l'objet dans la

liste remove(objet) : enlève la première occurence de l'objet dans la liste remove(index) : méthode semblable à la précédente mais prenant un entier

comme argument. Elle retire l'élément de position index de la liste. size() : retourne la taille de la liste. set(index,objet) : remplace l'élément de position index par l'objet.

* *

*

Dans ce chapitre, nous avons vu comment utiliser la programmation objet pourrendre notre code plus modulaire et facile à maintenir. Cela peut être utile dans denombreuses situations.

La programmation objet

68

La programmation objet

68

VII - La récursion VII

Deux exemples mathématiques. 69

Mise en œuvre : le flocon de Koch 70

La récursion est un concept important en programmation, et relativement simple. Ellerecoupe les définitions récursives que l'on trouve en mathématiques sur les suites parexemple.

A. Deux exemples mathématiques.

La fonction factorielleEn mathématiques, la factorielle d'un entier naturel n est le produit des nombresentiers strictement positifs inférieurs ou égaux à n. Autrement dit, factorielle(n) =n*(n-1)*...*2*1.La factorielle s'implémente facilement en utilisant une boucle.

1 int factorielle(int n) {2   int result = 1 ;3   for (int i = 2 ; i<=n ; i++) {4     result *= i ;5   }6   return result ;7 }

On peut aussi utiliser une définition en terme de suite de la factorielle. En effet,factorielle(n) peut être définie comme factorielle(n-1) multipliée par n. On peut seservir de cette propriété pour implémenter la fonction factorielle

1 int factorielle(n) {2   if (n ==1 ) {3     return 1 ;4   } else {5     return n*factorielle(n-1) ;6   }7 }

On peut même écrire de façon encore plus simple la fonction

1 int factorielle(n) {2   if (n ==1 ) return 1 ;3   return n*factorielle(n-1) ;

69

4 }On parle de récursivité car la fonction s'appelle elle même.

DéfinitionEn informatique, une fonction qui contient un appel à elle-même est dite récursive.Deux fonctions peuvent s'appeler l'une l'autre, on parle alors de récursivité croisée.

Voyons maintenant un second exemple, celui de la suite de Fibonnaci. La suite deFibonnaci, intimement liée au nombre d'or, est définie de la façon suivante.

Les deux premiers termes de la suite valent 1. Chacun des autres termes est défini comme la somme des deux termes

précédents.En utilisant une fonction récursive, on peut faire très facilement une implémentationde la suite de fibonnaci

1 int fibonnaci(int n) {2   if (n < 2 ) return 1 ;3   return fibonnaci(n-1)+fibonnaci(n-2);4 }

ComplémentL'écriture des fonctions récursives est souvent assez simple. On voit que l'écriture dela fonction factorielle est beaucoup plus simple et bref de façon récursive que defaçon itérative.Cependant, cette simplicité a un coût. En effet, chaque appel à une fonction estconsommateur de ressources au niveau de l'ordinateur.Les appels au fonctions doivent aller chercher le code de la fonction en mémoire, puisstocker les paramètres de la fonction et les valeurs de retour en mémoire. Lorsd'appels récursifs, les valeurs intermédiaires s'empilent. Pour avoir le terme de rangn de la suite de Fibonnaci, il faudra ainsi empiler puis dépiler 2 puissance n valeursintermédiaires.Il est toujours possible de "dérécursiver" une fonction récursive, ce qui permetsouvent d'améliorer notablement les performances mais peut aussi conduire à uncode moins lisible.

B. Mise en œuvre : le flocon de Koch

Le flocon de Von Koch a été l'une des premières courbes fractale étudiée, en 1906,bien avant que le terme fractale soit défini.On peut le créer à partir d'un triangle équilatéral, en modifiant récursivement chaquesegment de droite de la façon suivante :On divise le segment de droite en trois segments de longueurs égales.On construit un triangle équilatéral ayant pour base le segment médian de lapremière étape.On supprime le segment de droite qui était la base du triangle de la deuxième étape.

La récursion

70

La récursion

70

Le flocon de neige de Von Koch

Nous allons écrire un programme pour créer un flocon de ce type . A cette fin, nousallons utiliser une possibilité offerte par processing : utiliser des changements derepère. On peut modifier le repère utilisé en le translatant ou en effectuant unerotation du repère. On utilise pour ça les fonctions translate()24 et rotate()25. Processing offre aussi la possibilité de "stocker" la position d'un repère et de larappeler, en utilisant les fonctions pushMatrix()26 et popMatrix()27. pushMatrix permetde stocker le repère et popMatrix permet de le rappeler.L'algorithme est le suivant. On se fixe une limite. Si on est sous la limite, on traceune ligne. Si on est au dessus de la limite, on divise en trois le segment, on crée untriangle sur la partie centrale, et on trace la courbe sur chaque partie. Voici lafonction récursive qui trace la courbe.

1 void trace_courbe_koch(float longueur) {2   if (longueur < limite) {3     line(0,0,longueur,0);4   } else {5     trace_courbe_koch(longueur/3.0);6     pushMatrix();7     translate(longueur/3.0,0);8     rotate(-PI/3.0);9     trace_courbe_koch(longueur/3.0);10     popMatrix();

24 - http://processing.org/reference/translate_.html25 - http://processing.org/reference/rotate_.html26 - http://processing.org/reference/pushMatrix_.html27 - http://processing.org/reference/popMatrix_.html

71

La récursion

11     pushMatrix();12     translate(longueur/3.0,0);13     rotate(-PI/3.0);14     translate(longueur/3.0,0);15     rotate(2*PI/3.0);16     trace_courbe_koch(longueur/3.0);17     popMatrix();18     pushMatrix();19     translate(2*longueur/3,0);20     trace_courbe_koch(longueur/3.0);21     popMatrix();22   }23 }

L'initialisation du programme sera la suivante

1 float limite = 300;2 void setup() {3   background(50);4   stroke(250);5   size(500,500);6   noLoop();7 }8 void draw() {9   background(50);10   translate(100,150);11   trace_courbe_koch(300);12   translate(300,0);13   rotate(2*PI/3.0);14   trace_courbe_koch(300);15   translate(300,0);16   rotate(2*PI/3.0);17   trace_courbe_koch(300);18 }

Pour pouvoir affiner le flocon, on va utiliser l'interaction avec la souris et diviser lalimite par 3 à chaque clic de souris.

1 void mouseClicked() {2   if (limite > 12 ) limite = limite / 3.0 ;3   else limite = 300;4   redraw();5 }

Ce programme peut être vu en action sur le site ISN28 où le code source peut êtretéléchargé.

* *

*

On aura vu dans cette partie la notion de récursivité, et sa mise en œuvre sur leflocon de Von Koch aura permis de découvrir la notion de changement de repère dansprocessing.

28 - http://isn.lec.ac-grenoble.fr/exemples/flocon/

La récursion

72

La récursion

72

73

La récursion

VIII - Les images, la couleur et la compression

VIII

La numérisation du réel 75

Les images informatiques 79

Objectifs

Notre univers numérique déborde de représentationsvisuelles. Combien d'images voyons nous dès que nousnous connectons à l'internet ? On peut voir des millions dephotographie sur des sites comme Flick'r ou 500px. Maiscomment procéde t'on pour capturer ces images, lesstocker, les manipuler. Comment passe t'on du monde réelà un monde fait de 0 et de 1 ? Comment effectue-t'on lanumérisation du réel ?

A. La numérisation du réel

Un peu d'histoireLa photographie numérique a fait irruption dans nos vies autour des années 2000.Avant cette époque, la photographie argentique sur pellicule régnait en maître, tantchez les particuliers que chez les professionnels. Aujourd'hui, les pelliculesphotographiques ne sont plus qu'un marché de niche. Kodak, entreprise de la chimiede la photo, incontournable pendant longtemps, et dont le nom est indissociable del'histoire de la photographie, a été mise en faillite en janvier 2012. Une page de laphotographie s'était tournée.En 2003, Canon sort l'EOS 300D, premier appareil photo reflex numérique "grandpublic", qui avait ses 6 millions de pixels permettait de faire des photos de grandequalité jusqu'au tirage A4. Peu à peu, le monde de la photo a basculé dans unnumérique produisant une qualité de plus en plus incroyable, dépassant aujourd'huitrès largement le meilleur de la pellicule argentique. On trouve aujourd'hui desappareils compacts de qualité tout à fait satisfaisante et les progrès ont permis uneminiaturisation rendant les smartphones capables de photos honnêtes dans de bonneconditions.

75

Peu à peu, les particuliers stockent des dizaines de milliers de photos qui constituentleur mémoires dans leurs disques durs et de plus en plus dans le cloud

Canon EOS 300D

le capteur photographique.L a numérisation consiste à transformer un support en données informatiques. Engénéral, tout processus de numérisation commence par la transformation d'unphénomène réel en un signal électrique. Ce signal électrique sera ensuite transforméen données numériques par un convertisseur analogique numérique (ADC enanglais).La conversion en signal électrique du signal lumineux est faite grâce au capteurphotographique, cœur de l'appareil photo numérique.

Les images, la couleur et la compression

76

Les images, la couleur et la compression

76

Capteur photographique

La lumière arrive sur le capteur où elle est concentrée grâce à des micro-lentilles. Elleest ensuite filtrée pour ne retenir que le rouge, le vert ou le bleu suivant la position.La lumière arrive sur des photodiodes qui transforme la lumière en courantélectrique. Ce courant électrique est converti en données numériques par la couchede transistors et de circuits électroniques.Les filtres sont déposé suivant une grille répétitive de case qui porte le nom dematrice de Bayer. Chaque point de l'image sera constitué des valeurs retournées par4 élément de la grille, constituant un carré. Pour faire un point de l'image, on aurades valeurs de rouge, vert et bleu, constitué à partir d'une cellule rouge, d'une bleueet de deux vertes (les photodiodes vertes sont moins sensibles)

77

Les images, la couleur et la compression

Grille de Bayer

Une image en informatiqueOn en vient donc à la façon dont est codée une image dans un système informatique.Pour créer des images sur un écran, on va procéder à de la synthèse additive enmélangeant des composantes rouge, verte et bleue. Voici à quoi ressemble un écranLCD regardé avec un fort grossissement.

Pixels d'un écran LCD

Une image informatique est donc une grille de pixels. Chaque pixel est constitué de 3nombre entier qui représentent l'intensité de rouge, de vert et de bleu sur ce pixel .Une image va être constitué d'un certain nombre de pixels. Le nombre de pixels

Les images, la couleur et la compression

78

Les images, la couleur et la compression

78

d'une image s'appelle la définition de l'image. Une image de 600 pixels de large par400 pixels de haut a une définition de 240 000 pixels. La définition d'une image estlié intrinsèquement à cette image et ne dépend que de cette image.La résolution d'une image, elle, dépend à la fois de l'image et de son affichage. Eneffet, la résolution indique la densité de pixel de l'image. En système international,elle devrait donc être de pixel par mètre, ou à défaut, par centimètre. Mais l'unité laplus souvent utilisée est le pixel par pouce. On parle de nombre de points parpouces, ce qui en anglais se notera dpi (dot per inch). Autant la définition de l'imagene dépend que de la structure de l'image, autant sa résolution n'existe que lorsquel'image est affichée ou imprimée.Le tableau suivant vous indique les résolutions utilisées actuellement

Support Résolution usuelle en DPI

Écran informatique standard 75 à 90

Écran informatique de qualité 130

Écran de type RETINA plus de 250

Impression de qualité presse 150

Impression de qualité photographique 250

capacité de l'oeil humain à distancestandard

250

B. Les images informatiques

Les formats de fichiersUne image en informatique est donc un tableau de pixels contenant des valeurs derouge/vert/bleu. Une fois que l'on a ces valeurs, on doit les stocker sous forme defichiers. Plusieurs formats de fichiers sont disponibles.Le premier format dont on peut parler est le format BMP. C'est un format de fichiertrès simple. Il commence par un en-tête qui indique les dimensions de l'image et lanature des données, et ensuite les données sont stockées de façon linéaire. Ceformat très basique a été rendu populaire par le logiciel PAINT de Microsoft. Il aensuite évolué pour devenir un peu plus performant.Le BMP est un format simple mais il n'est pas du tout optimum. Il a un gros défaut :il génère de gros ou très gros fichiers. Un format voisin est le format TIFF, quifonctionne sur un principe approchant.Face à ce problème de place, on a décidé de compresser les images, c'est à dire decoder les images d'une façon différente qui prendrait moins de place.Il existe deux type de compression :

La compression avec perte. L'exemple le plus notable est le format JPEG. Au prix d'une infime perte dequalité, l'image est fortement compressée. Sur une image de grande taille,avec des couleurs proches, on peut gagner facilement un facteur 10 sansperte visible de qualité. Par contre, les enregistrements successifs dégradentl'image.

79

Les images, la couleur et la compression

La compression sans perteOn distingue deux formats utiles pour la compression sans perte : le formatGIF, limité à une palette de 256 couleurs, utilisé pour son faibleencombrement sur le web et la capacité à être animé. Et le format PNG, quipermet de compresser sans perte des images en vraie couleur, de façonacceptable.

On le voit, les formats d'image sont donc chacun dévolus à des usages différents :

Format d'image Utilisation

BMP plus vraiment utilisé

TIFF traitement photo professionnel. Qualitéoptimale

JPEG Photos d'usage courant

GIF format pour les icônes web et lesimages animées

PNG Compression sans perte optimisée pourles aplats de couleur. A supplanté leGIF pour le web.

Les images dans processingPlusieurs fonctions sont accessibles pour manipuler les images dans PNG

createImage(h,w,mode)29

La fonction createImage crée un objet de type Pimage, de largeur w, dehauteur h. Le mode peut être RGB (Rouge vert Bleu standard), ARGB ouALPHA (voir la documentation)

loadimage("filename")30

La fonction loadimage permet de charger le contenu d'un fichier image dansun objet de type Pimage (Processing Image). Des images de type GIF, PNG ouJPEG peuvent être chargé

image(img,x,y,w,h)31

Affiche une image de type Pimage. x et y sont les coordonnés du coin en hautà gauche, w et h sont la largeur et la hauteur de l'image

copy(src,x,y,w,h,dx,dy,dw,dh)32

Permet de copier tout ou partie d'une image dans une autre. get(x,y)33

Cette méthode appliquée à un objet Pimage permet d'obtenir la couleur d'unpixel quelconque de l'image

set(x,y,c)34

Cette méthode d'un objet Pimage permet de fixer la couleur d'un pixelquelconque de l'image.

pixels[]35

29 - http://processing.org/reference/createImage_.html30 - http://processing.org/reference/loadImage_.html31 - http://processing.org/reference/image_.html32 - http://processing.org/reference/PImage_copy_.html33 - http://processing.org/reference/PImage_get_.html34 - http://processing.org/reference/PImage_set_.html35 - http://processing.org/reference/PImage_pixels.html

Les images, la couleur et la compression

80

Les images, la couleur et la compression

80

Cet attribut d'un objet Pimage contient tous les pixels d'une image. Lecontenu du tableau est des objets de type couleur. La procédure à suivreconsiste à remplir ce tableau en utilisant loadPixels(), à le modifier, puis àmettre à jour l'image en utilisant updatePixels()

save(filename)36

Cette méthode permet de sauvegarder une image dans le fichier de nomfilename.

36 - http://processing.org/reference/PImage_save_.html

81

Les images, la couleur et la compression

IX - Du bon usage des tableaux : tris et recherches

IX

Comment faire une recherche dans un tableau 83

Dichotomie récursive 87

Comment trier un tableau 87

Implémentation du tri par insertion 90

Objectifs

Imaginez une très grande bibliothèque. Cette antre dusavoir ne présente qu'un seul défaut. Rien n'y est classé.Vous savez qu'il y a un livre absolument passionnant sur lareproduction des crevettes dans le golfe du Morbihan qu'ilvous faut pour finir votre mémoire, mais où se trouve t'il ?Ah, si seulement tout cela était classé. Ce serait tellementplus simple.D'ailleurs, les adolescents l'entendent si souvent .... Rangeta chambre ! On s'y retrouve mieux après, c'est tellementplus facile.En informatique, c'est pareil. Pour pouvoir accélérer lesrecherches, il est souvent très intéressant d'avoir untableau trié. Mais comment s'y prendre pour trierefficacement un tableau (efficacement, tout est là...)Au cours de cette activité, nous allons voir comment trier,comment faire une recherche dans un tableau, et nousinterroger sur l'efficacité des algorithmes.

A. Comment faire une recherche dans un tableau

ExemplePrenons un premier exempleConsidérons une liste d'étudiants participant à un examen. Les étudiants sont classéspar ordre alphabétique. Un surveillant doit absolument parler à l'un des étudiants : il

83

y a une fuite d'eau chez lui et la canalisation a lâché. Il faut qu'il rappelle lespropriétaires.Prenons un autre exempleOn cherche dans un dictionnaire la page à laquelle se trouve un mot. Un dictionnairepeut être considéré comme un tableau trié. Comment faire pour trouver le mot leplus rapidement possible ?

Ces deux situations se modélisent de la même façon en informatique. On a untableau trié d'éléments et on doit trouver l'index d'un élément dans le tableau. Ondoit aussi éventuellement pouvoir vérifier qu'il ne figure pas dans le tableau. Ceproblème de la recherche en table est un problème de base de l'informatiquethéorique. Il est intéressant par ce qu'il permet d'entrevoir la notion d'efficacité d'unalgorithme. En résumé, le problème est le suivant :On considère un tableau T trié de N éléments. Comment montrer qu'un objetO se trouve dans le tableau, en précisant son index, ou ne s'y trouve pas.

Un algorithme naïfOn peut procéder de façon assez naïve pour résoudre ce problème. Il suffit deparcourir le tableau en commençant par le premier élément, et de le parcourirjusqu'à ce que l'on ait trouvé O. Pour rechercher notre aiguille dans la meule de foin,on la parcoure de façon exhaustive. En Processing, l'algorithme serait donc le suivant

1 int recherche_naive(int aiguille,int[] meule) {2 for (int i=0;i<meule.length;i++) {3 if (aiguille == meule[i]) return i; 4 }5 return -1;6 }

Cet algorithme est très simple, pour ne pas dire simpliste. On parcoure le tableautant que l'on a pas trouvé l'élément. Si on le trouve, on renvoie l'entier qui indique saposition dans le tableau. Si il n'est pas dans le tableau, on renverra -1. Cetalgorithme marche pour n'importe quel tableau, qu'il soit trié ou non. Notre tableauétant trié, on doit pouvoir faire un peu mieux.

Une amélioration de l'algorithme ?Notre tableau est trié. On peut donc le parcourir, mais dès que l'on constate que l'ona dépassé notre valeur recherché, on arrête la recherche. En Processing, celadonnerait donc

1 int recherche_naive(int aiguille,int[] meule) {2 for (int i=0;i<meule.length;i++) {3 if (aiguille == meule[i]) return i; 4 else if (aiguille < meule[i]) return -1; 5 }6 return -1;7 }

Puisque l'on s'arrête dès que possible, on doit avoir amélioré la situation. Vraiment ?L'intuition est parfois trompeuse.Imaginons que nos données, bien que triées, soit réparties de façon uniforme.Considérons que notre tableau est de taille N, et que nous le parcourons pour trouverdes valeurs. En excluant les cas où la valeur ne figure pas dans le tableau, on a unparcours qui sera de N/2 éléments avant de trouver le bon.

Du bon usage des tableaux : tris et recherches

84

Du bon usage des tableaux : tris et recherches

84

Si l'on considère que l'on utilise le nombre de comparaison comme critère d'efficacitédes algorithme (une comparaison fait appel à deux cases en mémoire et effectue uneopération), pour le premier algorithme, nous aurons N/2 comparaison. Pour le secondalgorithme, nous avons N/2 itération, mais chaque itération fait 2 comparaison. Notrealgorithme fera donc N comparaison.Maintenant, le premier algorithme fera N comparaison avant de se rendre comptequ'un nombre n'est pas dans le tableau, tandis que le second fera N/2 itération enmoyenne, soit N comparaison pour arriver au même résultat.Pas mieux non plus !En conclusion, on a pensé améliorer les choses avec cet algorithme, mais en fait, onne gagne rien. On a même tendance à ralentir l'exécution !

AttentionIl faut bien réfléchir à la structure d'un algorithme pour savoir combien d'opérations ildoit effectuer. Parfois, en voulant simplifier les choses, on peut les rendre moinsefficaces.

On pourrait essayer d'améliorer l'algorithme de la façon suivante : on vérifie que l'onest toujours en dessous de la valeur, et la première fois ou cela n'est plu vrai, onregarde si c'est égal. Là, il y aurait une légère amélioration. Mais de peu de chose. Enfait, on pourrait pas à N/2 comparaisons en moyenne. Mais le fait est là : Notrealgorithme naïf, même dans sa version amélioré, voit sa complexité croitrede façon linéaire avec N. En clair, le nombre de comparaison estproportionnel au nombre d'élément. Si nous avons dix fois plus d'éléments, celasera 1à fois plus long.

DéfinitionUn algorithme est de complexité linéaire, ou de complexité de l'ordre de N, ou enO(N), si le nombre d'opération est de l'ordre de grandeur du nombre d'élémentsconsidérés.

Améliorer vraiment l'algorithmeEn fait, nous avons en main les éléments pour améliorer clairement cet algorithme.Pour cela, il suffit de se remémorer comment nous avons appris, enfant, à chercherdes mots dans le dictionnaire. Après être allé chercher le lourd ouvrage au fond de laclasse, nous ne commencions pas à la première page pour les parcourir une par une,jusqu'à avoir enfin trouvé le mot recherché. Et fort heureusement compte tenu dunombre de mots dans l'ouvrage. Non. On ouvrait le dictionnaire à peu prêt au milieu,on consultait le premier mot de la page, et on se demandait "le mot cherché est ilavant ou après ?" S'il est avant, on coupait en deux la première moitié dudictionnaire et on se reposait la même question. Et ainsi de suite, en découpant à chaque fois en deux l'intervalle de recherche.L'intérêt ?SI on cherche parmi 1000 valeurs, après une recherche, on cherche parmi 500, puis250, puis 125, puis 63, puis 32, puis 16, 8 , 4 et enfin 2 et on fini par trouver ! On aau maximum effectué 10 comparaison ! Alors que notre algorithme précédentdonnait entre 500 et 1000 comparaisons.Si on augmente et que l'on passe à 100 000, l'algorithme qui consiste à diviser endeux fera 18 comparaisons contre 50 000 pour notre algorithme naïf ! On estclairement dans un autre monde.Mieux encore, en 26 comparaisons, on pourrait retrouver un nom parmi les 60

85

Du bon usage des tableaux : tris et recherches

millions de noms de la population française ! Seulement 26 comparaisons !En divisant à chaque fois le champs de la recherche par 2, en effectuant n étapes, ontrouve un élément parmi 2n éléments. En clair, on doit avoir 2n > N. D'après ladéfinition de la puissance et du logarithme, on a donc n qui est de l'ordre de log2(N).En imaginant qu'une comparaison est de l'ordre de 10 nanosecondes, voilà le tableauqui donnerait les temps d'exécutions pour des comparaisons, arrondis à la dizaine denanosecondes. Ce ne sont que des ordres de grandeur, mais on voit bien que l'on estdans un autre monde.

Nombred'éléme

nts

5 10 20 50 250 1000

10000

1000000

Complexitélogarithmique

10 10 10 20 30 30 40 60

Complexitélineaire

50 100 200 500 2500

10000

100000

10000000

DéfinitionUn algorithme est de complexité logarithmique, ou de complexité de l'ordre delog(N), ou en O(log(N)), si le nombre d'opération est de l'ordre de grandeur dulogarithme du nombre d'éléments considérés.

DéfinitionFaire une recherche en diminuant de moitié à chaque étape la dimension del'intervalle de recherche s'appelle faire une dichotomie. La dichotomie est unetechnique de complexité logarithmique.

Voici notre code source en processing pour faire une recherche par dichotomie

1 int recherche_dichotomique(int aiguille, int[]meule) {

2 int i=0;3 int j=meule.length -1;4 int k;5 while (i < j) { 6 k = (i + j) / 2;7 if (aiguille == meule[k]) {8 i= k;9 j= k;10 }11 else {12 if (aiguille > meule[k]) {13 i = k+1;14 }15 else {16 j = k-1;17 }18 }19 }

Du bon usage des tableaux : tris et recherches

86

Du bon usage des tableaux : tris et recherches

86

20 if (aiguille == meule[i]) {21 return i;22 }23 return -1;24 }

B. Dichotomie récursive

On a donné dans le paragraphe précédent une procédure pour faire une recherchepar dichotomie déclarative. On peut aussi écrire cette procédure de façon récursive.Le but de cet exercice est de le faire. À cette fin, on pourra utiliser pour les tests uncode source qui contient déjà un générateur de tableau aléatoire de N valeurs entre 1et max, ainsi que la recherche dichotomique déclarative. Le code source estdisponible ici37

Q u e s t i o n Écrire l'algorithme de recherche dichotomique de façon récursive. On aura unefonction dont la forme sera :

1 int recherche_dichotomique_recursive(int xmin, intxmax, int aiguille, int[] meule) {

23 }

C. Comment trier un tableau

On va proposer ici une seule méthode pour trier un tableau. Il s'agit du tri que l'onappelle tri par insertion. Le tri par insertion est une méthode que la plupart despersonnes utilisent naturellement pour trier des cartes dans une main. Le principepour trier une liste de N éléments est le suivant :

Au départ, on considère que l'élément le plus à gauche est le trié. La liste esttrié sur 1 élément, et N-1 restent à trier.

On prend un élément parmi ceux restant à trier (souvent le premier). On va leplacer dans la liste des éléments déjà triés, à sa place. Ainsi, on augmenterade 1 la liste des éléments triés, et on diminuera de 1 la partie qui n'est pastriée.

on répète ce processus jusqu'à avoir complétement trié la liste.Voici ce que donne le tri par insertion sur un exemple. Les parties vertesreprésentent les éléments déjà triés, les rouges ceux que l'on va trier, et les jaunesceux que l'on vient de trier.

37 - http://isn.lec.ac-grenoble.fr/exemples/recherche.zip

87

Du bon usage des tableaux : tris et recherches

Du bon usage des tableaux : tris et recherches

88

Du bon usage des tableaux : tris et recherches

88

Tri par insertion

89

Du bon usage des tableaux : tris et recherches

Pour insérer le nombre, il faudra le comparer aux éléments déjà triés pour trouver saposition. On peut montrer que le tri par insertion est d'une complexité en O(n2) ,c'est à dire une complexité quadratique qui dépend du carré du nombre d'éléments àtrier. Ce n'est pas e plus efficace des tris pour un grand nombre d'éléments. Mais sonimplémentation est simple.Par comparaison, le tri rapide (appelé souvent de son nom anglais quick sort) est enO(nlog(n)) , comme le tri fusion ou le tri par tas. Mais ils reposent sur des conceptset des notions plus ardues à comprendre.

ComplémentPour une étude plus complète des algorithmes de tri, on peut se référer à wikipedia38

On trouvera aussi sur youtube une excellent compilation de tris illustrés par desdanses :

Le tri sélection39

le tri à bulle40

Le tri par insertion41

Le tri par fusion42

D. Implémentation du tri par insertion

On souhaite implémenter le tri par insertion et tester sa rapidité. Pour cela, on vafaire le mini projet suivant.

Q u e s t i o n 1Implémenter une fonction qui va remplir de façon aléatoire un tableau de N entiersentre 0 et max.

Q u e s t i o n 2Implémenter une fonction de tri par insertion qui tri un tableau d'entiers

Q u e s t i o n 3On va maintenant réaliser des tests. On va générer au hasard 10 tableau de Nentiers entre 0 et 10 000, N valant successivement 10, 20, 50, 100, 200, 500 puis1000. On va effectuer le tri par insertion en mesurant le temps à chaque fois. On feraune moyenne et on tracera la courbe représentant le temps en fonction du nombred'éléments à trier.

38 - http://fr.wikipedia.org/wiki/Algorithme_de_tri39 - https://www.youtube.com/watch?v=Ns4TPTC8whw40 - https://www.youtube.com/watch?v=lyZQPjUT5B441 - https://www.youtube.com/watch?v=ROalU379l3U42 - https://www.youtube.com/watch?v=XaqR3G_NVoo

Du bon usage des tableaux : tris et recherches

90

Du bon usage des tableaux : tris et recherches

90