Programmation Javascript (NFA041)

Feuille 2

Olivier Pons
(pons@cnam.fr)

2022


Conditionnelles


Exercice 1

On veut calculer le poids idéal d'une personne.

Pour cela, on doit avoir trois informations :

  1. sa taille T en cm,
  2. son âge A en années,
  3. son sexe S (qui sera donné par une chaîne "homme" ou "femme").

Les formules (très datées et sans aucun fondement scientifique ;-) sont :

On va écrire une fonction javascript qui renvoie le poids ideal.

Version 1:

Dans le cas ou les paramètre passés ne sont pas ceux attendus
on renvoi un undefined ou Nan ou n'importe quoi... c'est a l'utilisateur de respecter les paramètres (c'est dangereux !!!)

Version 2:

On vérifie la conformité des paramètres et on affichera un message d'erreur expliquant l'éventuel problème.

> poidsIdeal(30,180,"homme")
72.5
> poidsIdeal("trente",180,"homme")
l'age et la taille doivent être des nombres 
undefined
> 

Solution

function poidsIdealv1(a,t,s){
   switch (s) {
    case "homme":return (3*t-250)*(a+270)/1200 
    case "femme":return (t/2 -30 )*(180+a)/200
   }
}

function poidsIdealv2(a,t,s){
   if (typeof a !='number' || typeof t != 'number' ){
    // on peut verifier plus de chose...
    console.log("l'age et la taille doivent être des nombres ")
    return;
   }
   switch (s) {
    case "homme":return (3*t-250)*(a+270)/1200 
    case "femme":return (t/2 -30 )*(180+a)/200
    default: console.log("pour pouvoir calculer entrez homme ou femme")
   }
}

Chaînes de base


Exercice 2

Écrire une fonction qui génère une chaîne contenant la suite ordonnée des lettre minuscules. On demande une solution sans utiliser dans votre code les lettre b et z mais vous pouvez utiliser charCodeAt() ou String.fromCharCode

> genMinuscule()
'abcdefghijklmnopqrstuvwxyz'

Solution

function genMinuscule(){
    let a="a".charCodeAt();
    let res=""
    for(let i=0;i<26;i++){
        res+=String.fromCharCode(a+i);

    }
    return res;
}

Exercice 3 (dure)

Le codage de César est un manière de crypter un message de manière simple : On choisit un nombre (appelé clé de codage) et on décale toutes les lettres de notre message du nombre choisi.

Par exemple : Si on choisit comme clé le nombre 7. Alors la lettre A deviendra H, le B deviendra I ... et le Z deviendra G.

> encode("BON",2)
'DQP'
a=encode("Bonjour ca va !",3)
'Erqmrxu fd yd !'
> a=encode(a,-3)
'Bonjour ca va !'
> 

Solution


function encode(chaine,clef){
    let min=genMinuscule()
    let maj=min.toUpperCase();
    let res="";
    if( clef<0){clef=26+clef}
    
    for(let i=0;i<chaine.length;i++){
        let l=chaine[i];
        if (min.indexOf(l) != -1){
            
            l=String.fromCharCode("a".charCodeAt()+(chaine.charCodeAt(i)+clef-"a".charCodeAt())%26)    

        }
        if (maj.indexOf(l) != -1){    
        l=String.fromCharCode("A".charCodeAt()+(chaine.charCodeAt(i)+clef-"A".charCodeAt())%26)    
       
         }

         res+=l
    }     
    return res;
}

Exercice 4

Écrire une fonction verifierMotDePass qui prend en argument une chaîne de caractère et renvoie true si elle contient au moins un chiffre et une majuscule et false sinon.

On pourra utiliser indexOf

Solution

On parcourt la chaîne et on vérifie chaque caractère. Il y a plus simple en utilisant les « expressions régulières ».

function verifierMotDePass(s){
    let chiffre=false;
    let maj=false;
    for(let i=0;i<s.length;i++){
        if ("1234567890".indexOf(s[i]) != -1) {chiffre=true;}
        if( "ABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf(s[i]) != -1) {maj=true;}    
    }
    return (chiffre && maj);
}

Tableaux


Exercice 5

Écrire une fonction qui crée un tableau de n zéro.

Solution

function tabZeroN(n){
    let res=[]
    while(n>0){
        res.push(0);
        n--;
    }
    return res;
}

ou sans push

function tabZeroNv2(n){
    let res=[]

    while(n>0){
        res[n-1]=0;  // attention on va de n-1 a 0
        n--;
    }
    return res;
}

Exercice 6

Même question mais avec n'importe quel valeur passée en argument au lieu de 0

Solution

function tabInitN(n,val){
    let res=[]
    while(n>0){
        res.push(val);
        n--;
    }
    return res;
}

Exercice 7

Écrire une fonction estCroissante(t) renvoyant un booléen indiquant si les éléments de t sont dans l’ordre croissant.

Solution

function estCroissante(t){
    for (let i=0;i<t.length;i++){
        if (t[i]>t[i+1]) {return false}
    }
return true
}

Exercice 8

Écrire une fonction estPresent(t,x) parcourant le tableau et renvoyant un booléen indiquant si x est présent dans `t``

Remarque :

On peut aussi tester l'appartenance à un tableau directement avec t.indexOf(x)!=-1 ou t.includes(x), mais on ne veux pas les utiliser dans cet exercice.

Solution

function estPresent(t,x){
    for (let i=0;i<t.length;i++){
        if (t[i]===x){
            return true
        }
    }
    return false;
}

Exercice 9

Duplication des éléments d’une tableau

Écrire une fonction qui rend un nouveau tableau où tous les éléments du tableau en argument sont dupliqués. Par exemple à partir de la [1,2,3] on obtient [1,1,2,2,3,3].

Solution

function duplique(t){
    let res=[];
    let i=0;
    while(i<t.length){
        res[2*i]=t[i];
        res[(2*i)+1]=t[i]
        i++; // ne pas l'oublie ou boucle infinie ;-)
    }
    return res;
}

Exercice 10

Reprendre l’exercice precedent en ajoutant à duplique un argument supplémentaire qui donne le nombre de répétition de l'élément

> dupliqueN(["bonjour","ca va"],4);

[
  'bonjour', 'bonjour',
  'bonjour', 'bonjour',
  'ca va',   'ca va',
  'ca va',   'ca va'
]

Solution

function dupliqueN(t,n){
    let res=[];
    let i=0;
    while(i<t.length){
        for(let j=0;j<n;j++){
        res[(n*i)+j]=t[i];
        }
        i++; // ne pas l'oublie ou boucle infinie ;-)
    }
    return res;
}

Exercice 11

Écrire une fonction compose prenant deux tableaux de même longueur en entrée et renvoyant un tableau dont les éléments sont des paires (des tableaux à 2 éléments) des éléments des tableaux en entrée.

> compose([1,2,3],[4,5,6])
[ [ 1, 4 ], [ 2, 5 ], [ 3, 6 ] ]

Solution

function compose(t1,t2){
    let res=[]
    for(let i=0;i<t1.length;i++){
        res[i]=[t1[i],t2[i]];
    }
    return res
}

Exercice 12

Décalage à droite et à gauche. Écrire decalageG et decalageD: deux fonctions effectuant un décalage d’une position vers la gauche (resp. vers la droite) dans un tableau (l’élément sortant faisant sa rentrée du coté opposé, votre fonction modifie le tableau en place).

> decalageD(t)
undefined
> t
[ 5, 1, 2, 3, 4 ]
> decalageD(t)
undefined
> t
[ 4, 5, 1, 2, 3 ]
> decalageG(t)
undefined
> decalageG(t)
undefined
> t
[ 1, 2, 3, 4, 5 ]
> decalageG(t)
undefined
> t
[ 2, 3, 4, 5, 1 ]
> 
function decalageG(t){
    let premier=t[0]
    let indiceDernier=t.length-1;
    for(let i=1;i<= indiceDernier;i++){ //on décale tous sauf le premier vers la gauche
        t[i-1]=t[i]
    }
    t[indiceDernier]= premier; //on met le premier dans la dernière case
}



function decalageD (t){
    let indiceDernier=t.length-1;
    let dernier=t[indiceDernier];
    for(let i=indiceDernier-1;i>=0;i--){ //on décale tous sauf le dernier vers la droite
        t[i+1]=t[i];
    }
    t[0]= dernier; //on met le dernier dans la premiere case
}

Une variante en utilisant shift (qui retire le premier élément et décale les autres) et push (qui ajoute un lement à la fin).

function decalageG2(t){
    let x=t.shift()
     t.push(x)
}

Si on avait demandé de ne pas modifier t mais de produire un nouveau tableau on aurait pu écrire:

// ne modifie pas t
function decalageG3(t){
    let [premier,...reste]=t;  //crée une copie superficielle
    reste[t.length-1]=premier
    return reste;  // on renvoie une copie (au premier niveau)
}

Functions récursives


Exercice 13

Écrire deux fonctions pair et impair mutuellement recursive (ie. pair fait référence à impair et inversement ) permettant de tester si un entier donné en argument est paire ou impaire

Exemple

> pair(8)
true
> pair(9)
false
> impair(8)
false
> impair(9)
true

Solution

function pair (x) {
   if (x === 0) {return true} else {return impair (x-1)}
}
function impair(x){
 if (x === 0) {return false} else {return pair (x-1)}
 }

Exercice 14

Soit un tableau t de n entiers, écrire une fonction récursive simple permettant de déterminer le maximum du tableau On pourra regarder la Recherche_dichotomique.

:::solution ### Solution

// d et f indice de debut et de fin de recherche dans t
function maximum(t,d,f){
    console.log(t,d,f);
    if ((f-d)===0){ 
        return t[d]
    }
    // principe de la recherche dichotomique
    let m = Math.floor((f-d)/2) //milieu de zone chercher
    let max1 = maximum(t,d,d+m)  //on cherche sur la premiere moitié
    let max2 = maximum(t,m+d+1,f)  //on cherche sur seconde moitié
    if (max1 > max2){return max1}
    return max2
}

 

 function max(t){return maximum(t,0,t.length-1)}
:::

------------------------------------------------



# Exercice

Codage de Vigenère

Tout comme le codage de César, pour appliquer un codage de Vigenère il faut décaler les lettres mais pas toutes du même nombre. La clé est cette fois-ci un mot_clé dont chaque lettre nous donne le décalage à effectuer (en prenant A pour un décalage de 0, B pour un décalage de 1 ...).

Prenons un exemple pour expliquer la méthode : Imaginons que le mot_clé soit "MATHS" et le mot à coder "PYTHON".

Pour coder P, je décale du nombre correspondant à M c'est à dire 12 (car on commence à 0 avec A) ce qui me donne B comme codage pour P.
Passons au Y : Je le décale du nombre correspondant au A c'est à dire 0 donc Y est le codage de Y ici.
Passons au T qui se décale du nombre correspondant à T c'est à dire 19 donc T devient une fois décalé M
Ainsi de suite.
Si notre mot_clé est trop court on recommence au début du mot c'est à dire que N sera décalé du nombre correspondant à M.

Le but de cet exercice est de créer un programme qui reçoit en entrée un mot_clé et un mot à coder et qui affiche le mot codé par cette méthode.

Entrée : Un mot_clé et un mot à coder écrits en majuscules et sans accent.

Sortie : Le mot codé par la méthode de Vigenère en majuscule.

# Exercices










[](chaine/split/sort/join)
## Exercice
Deux chaîne de caractère sont des [anagrammes](https://fr.wikipedia.org/wiki/Anagramme) s' ils ont même longueurs sont composés des même lettres, mais dans des ordres potentiellement  différents.

Écrire une fonction qui teste si deux chaines
 sont des anagrammes:


 ```javascript
 > EstAnagramme("romain","manoir")
true
> EstAnagramme("sortie","toiser")
true
> EstAnagramme("posture","poste")
false
> 
function EstAnagramme (str1, str2) {
    //si les longueurs
    //sont différente ce n'est pas des anagram 
    if (str1.length !== str2.length) {
        return false;
    }
    
    //sinon on tri les caractères des deux chaînes.
    var s1 = str1.split('').sort().join('');
    var s2 = str2.split('').sort().join('');
    //on compare les deux chaînes triées.
    return (s1 === s2);
}

Exercice 15 regExp

apres les fonction d'ordre supérieurs

Fonctions avancées sur les tableaux

Les tableaux disposent de fonctionnelles.

– Array.map : (’a -> ’b) -> ’a array -> ’b array

– Array.iter : (’a -> unit) -> ’a array -> unit

– Array.fold_right : (’b -> ’a -> ’a) -> ’b array -> ’a -> ’a

– Array.fold_left : (’a -> ’b -> ’a) -> ’a -> ’b array -> ’a

De plus, certaines fonctionnelles permettent de prendre en compte des fonctions qui agissent différemment selon l’indice d’un élément dans le tableau :

– Array.mapi : (int -> ’a -> ’b) -> ’a array -> ’b array prend en argument une fonction f : [[0; n − 1]] × A −→ B et un tableau [|a0, a1, . . . , an−1|] ∈ An et renvoie le tableau [|f(0, a0), f(1, a1), . . . , f(n − 1, an−1)|].

– La fonction Array.iteri : (int -> ’a -> unit) -> ’a array -> unit prend en argument une fonction f qui renvoie un type unit, c’est-à-dire qui modifie l’environnement, et l’applique sur chaque couple (i, ai) du tableau.

Exercice 1 Implémenter les fonctions map, iteri et fold_left pour les tableaux.

sur les matrices

Les matrices peuvent être vues comme des tableaux à deux dimensions. La première idée qui nous vient à l’esprit pour créer une matrice est d’utiliser deux fois la fonction Array.make :

let m = Array.make 3 (Array.make 4 1);;

val m : int array array = [|[|1; 1; 1; 1|]; [|1; 1; 1; 1|]; [|1; 1; 1; 1|]|] La modification d’un élément se fait alors de la même façon que pour un tableau, en précisant l’indice de la ligne et de la colonne : # m.(1).(2) <- 5;; - : unit = ()

Cependant, après vérification, le résultat obtenu est étonnant : # m;; - : int array array = [|[|1; 1; 5; 1|]; [|1; 1; 5; 1|]; [|1; 1; 5; 1|]|]

Après réflexion, cela semble normale : lors de la création de la matrice, on a écrit que chaque ligne devait être la même, à savoir une colonne contenant quatre 1.

Les lignes sont alors considérées comme le même objet et la modification de l’une entraînera nécessairement la modification des autres. Nous proposons une première solution pour éviter le problème :

let m = Array.make 3 [||];; for i = 0 to 2 do m.(i) <- Array.make 4 1 done;; m.(1).(2) <- 5; m;; - : int array array = [|[|1; 1; 1; 1|]; [|1; 1; 5; 1|]; [|1; 1; 1; 1|]|] Ou plus simplement : let m = Array.make_matrix 3 4 1;; Exercice 2 Écrire une fonction transpose : ’a array array -> unit qui transpose une matrice carrée. Exercice 3 Écrire une fonction mult : int array array -> int array array -> int array array qui calcule le produit de deux matrices. On supposera que les dimensions permettent de faire le calcul. I.3 Files d’attente

ordre sup

Exercice 13. Des fonctionnelles simples. Écrire une fonction (et prévoir son type) qui à deux fonctions f et g associe : — la fonction composée f ◦ g ; — la fonction min(f, g) — la fonction max(f ◦ g, g ◦ f). Corrigé. On utilise la déclaration de fonctions en leur donnant un nom, plutôt que fun ou function. 1. let compose f g x = f (g x) ;; de type ('a -> 'b) -> ('c -> 'b) -> 'c -> 'b. En effet, le type d’entrée de f est le même que celui de sorti de g. 2. La fonction min de Ocaml est une fonction polymorphe à deux arguments. On propose let mini f g x = min (f x) (g x) ;; de type ('a -> 'b) -> ('a -> 'b) -> 'b. En effet les types d’entrée des deux fonctions f et g sont les mêmes, de même que les types de sortie. 3. let maxi_compose f g x = max (f (g x)) (g (f x)) ;; de type ('a -> 'a) -> ('a -> 'a) -> 'a -> 'a. En effet, pour composer g ◦ f et f ◦ g, les types d’entrée et de sortie de f et g doivent tous être identiques.

Exercice 16

## multiplication russe

On peut calculer le produit \(n_1 \times n_2\) de la façon suivante :

Le procédé s’arrête lorsque \(n_1\) tombe à zéro.

Écrire une fonction multRusse implémentant cette idée.

::: Solution



function multRusse(a, b) {
    let res = 0;
    while (a > 0) {
        if (0 === (a % 2)) { //pair
             a = a / 2;
             b = 2 * b;
        }
        else {               //impair
            res = res + b;
            a--;
        }
    }
    return res;

}


// ou si on copie le pseudo code de wxikipedia
function multRusse2(a, b) {
    let res = 0;
    while (a > 0) {

        
        if (0 === (a % 2)) { //pair
            
        }
        else {               //impair
            res = res + b;
            a--;
        }

        a = a / 2;
        b = 2 * b;
    }
    return res;

}

Exercice 17

Il s'agit de définir un objet chronometre avec deux méthodes. - demarrerqui démarre le chronomètre - arreter qui l’arrête et renvoie le nombre de millisecondes écoulées depuis le démarrage.
Si le chronomètre n'est pas démarré elle ne fait rien.

On pourra utiliser Date.now()qui renvoie le nombre de millisecondes depuis le 1er Janvier 1970.

>chronometre.start()
undefined
> chronometre.end() // presque 2 seconde après
1943   
> 

let chronometre={
    started:false,
    current:undefined,
    demarrer : function (){ this.started=true; this.current=Date.now(); },
    arreter : function (){ if(this.started){this.started=false;return Date.now()-this.current; }}

}

Exercice 18

Le problème des pièces de monnaies (plus dure).

On se donne une collection de valeurs de pièces de monnaies, sous forme d’un tableau t (comme [1, 2, 5, 10, 20, 50, 100]). On veut calculer le nombre de façons différentes que l’on a de décomposer une quantité d’argent s avec ces pièces.

Écrire une fonction `decomposition(t,s) résolvant ce problème.

Indication : c’est un problème difficile. On construira une matrice (tableau à deux dimensions) de taille (s + 1) × (p + 1), avec p le nombre de pièces.

On calculera le nombre de façon que l’on a de décomposer k avec les i premières pièces du tableau de pièces, et ce pour tout 0 ≤ k ≤ n et 0 ≤ i ≤ p.

```js
function matrice0(n,m){
    let mat=[]
    for(let i=0;i<n;i++){
        mat[i]=[]
        for(let j=0;j<m;j++){
            mat[i][j]=0;
        }
    }
    return mat
}


function _get_change_making_matrix(pieces, s){
    let m=matrice0(s+1,pieces.length +1);
    
    for(let i=1;i< s + 1;i++){
        m[0][i] = Infinity // By default there is no way of making change
    }
    return m
}

function change_making(coins, n){
    /* This function assumes that all coins are available infinitely"
    n is the number to obtain with the fewest coins.
    coins is a list or tuple with the available denominations.
    */
    m = _get_change_making_matrix(coins, n)
    for(let c=1;c<coins.length;c++){
        for (let r=1;r<n+1;r++){
            // Just use the coin
            if (coins[c] === r){
                m[c][r] = 1
            }    
            // coin cannot be included.
            // Use the previous solution for making r,
            // excluding coin
            else if (coins[c] > r){
                let zz= m[c - 1][r]
                m[c][r] =zz
                console.log("QQ",zz);
            }
            // coin can be used.
            // Decide which one of the following solutions is the best:
            // 1. Using the previous solution for making r (without using coin).
            // 2. Using the previous solution for making r - coin (without
            //      using coin) plus this 1 extra coin.
            else{
                let a=m[c - 1][r];
                let b=1 + m[c][r - coins[c]];
                console.log("AB",a,b)
                m[c][r] = Math.min(a,b);
            }
        }
    }                
    return m;
}

```