:: Enseignements :: Master :: M1 :: 2018-2019 :: Java Avancé ::
[LOGO]

Calc - Representation fonctionnelle de calculs


Ce TP a pour but de modéliser la structure de données sous-jacente à un tableur comme LibreOffice Calc ou Microsoft Excel.
Pour simplifier le problème nous allons supposer que:
  • Toutes les cases non-vides ont des valeurs de même type.
  • Toutes les cases non-vides contiennent une fonction, qui ne prend pas d'argument et renvoie un résultat. L'évaluation de cette fonction est la valeur de la case: si, par exemple, une case doit avoir pour valeur 2, elle contient en fait la fonction () -> 2.
  • Une case est identifiée par une chaîne de caractères comme "A1", "Z350" ou "B5000" par exemple. La lettre indique la valeur de la colonne, le nombre indique la valeur de la ligne.
  • Pour éviter les limitations sur le nombre de lignes et de colonnes, les cases sont stockées dans une table de hachage qui associe au nom de la case la fonction qu'elle contient.

Par exemple, le tableau suivant
       | A | B | C | D |
     1 | 5 |   |   |   |
     2 |   | 3 | 4 |   |
     3 | 8 |   |   |   |
  
sera représenté par les couples A1:() -> 5, B2:() -> 3, C2:() -> 4 et A3:() -> 8 dans la table de hachage.

Exercice 1 - Calc

Les tests JUnit 5 pour toutes les questions du TP sont dans la classe CalcTest.java.

  1. Écrire la classe Calc paramétrée par le type des valeurs des cases avec
    • une méthode set qui prend en paramètre le nom d'une case et la fonction qui permet de calculer sa valeur et définit la case correspondante (ou change la valeur de la case si cette case existe déjà);
    • une méthode eval qui prend en paramètre le nom d'une case et renvoie la valeur de celle-ci sous forme d'un Optional, car la case peut ne pas être définie.
  2. Écrire la méthode toString qui affiche les couples nom=valeur de toutes les cases définies. L'affichage doit être entre accolades et les couples doivent être séparés par une virgule suivie d'un caractère espace. Par exemple, pour le tableau ci-dessus, l'affichage devra être {A1=5, B2=3, C2=4, A3=8} ou une permutation car l'ordre d'affichage des couples n'a pas d'importance.
  3. Écrire une méthode forEach qui applique une méthode à deux arguments (nom et valeur) à chaque case du Calc.
  4. On souhaite maintenant modéliser un groupe de cases, ou un groupe de valeurs de façon générale. Pour cela, on va introduire une interface Group paramétrée par le type des valeurs et ayant une méthode values qui renvoie l'ensemble des valeurs du groupe sous la forme d'un Stream.
    Afin de simplifier la correction, on vous demande de déclarer l'interface Group à l'intérieur de la classe Calc.
    On souhaite écrire dans l'interface Group une méthode of qui prend en paramètre des valeurs séparées par des virgules et renvoie un Group dont la méthode values renvoie les valeurs prises en paramètre.
    Quelle est la restriction sur l’utilisation des varargs de variable de type ?
    Écrire l'interface Group et sa méthode of. Vous ne devez pas avoir de warning et vous devez expliquer ce qui vous autorise à le supprimer.
  5. Écrire une méthode forEach qui permet de parcourir les éléments du groupe (l'ordre des éléments est celui dans lequel ils sont donnés à la méthode of).
  6. Écrire une méthode cellMatrix qui prend 4 paramètres: une ligne de départ, une ligne d'arrivée, une colonne de départ et une colonne d'arrivée et crée un Group contenant le nom des cellules se trouvant dans le rectangle entre la ligne de départ et la ligne d'arrivée (incluses) et la colonne de départ et la colonne d'arrivé (incluses).
    Par exemple cellMatrix(1, 2, 'A', 'B') correspond aux cellules A1, A2, B1 et B2.
    En terme d'implantation, vous n'avez pas besoin de pré-calculer le résultat, vous pouvez le générer à la volée.
    Note: Les colonnes étant représentées par un caractère, vous utiliserez le type char.
  7. Écrire une méthode ignore s'appliquant sur un Group prenant en paramètre un ensemble de valeurs et renvoyant un nouveau Group qui ne devra pas contenir les valeurs ignorées.
    En terme d'implantation, vous n'avez pas besoin de stocker le résultat de l'appel à ignore.
  8. Enfin, écrire une méthode eval de façon à ce qu'il soit, par exemple, possible de calculer la somme des valeurs des cases A1, A2, B1 et B2, grâce au code suivant
           Calc<Integer> calc = ...
           ...
           int sum = cellMatrix(1, 2, 'A', 'B').eval(calc::eval).mapToInt(x -> x).sum();
         

    En terme d'implantation, vous n'avez pas besoin de stocker le résultat des évaluations.
    Note: les cases sans valeur sont ignorées lors du calcul.