Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Programme spreadsheet Java

5 réponses
Avatar
henryd
Bonjour,

Dans le cadre du projet, je dois réaliser un petit tableur 10 lignes x 6 colonnes en Java avec un menu permettant de demander à l’utilisateur les actions à réaliser : afficher le tableur, ajouter une valeur à une cellule, effacer la valeur dans une cellule, importer un fichier et insérer ses valeurs dans les cellules, enregistrer le tableur dans un fichier.

J’ai créé différentes classes : Programme (celle qui exécute le programme), Grid (représente le tableur), Node (la cellule), Value (la valeur d’une cellule), Tests (permet de tester le programme en fonction de différentes valeur de cellule), UseCalcGUI et CalcGUI permettant de créer une interface graphique à partie de JFrame pour afficher le tableur.

J’ai mis les différents fichiers de code, la consigne plus détaillée et autres informations du projet sur mon repository Github : https://github.com/henryd02/spreadsheet_java

J’ai actuellement plusieurs points bloquants :

- Le programme n’accepte pas que l’utilisateur rentre du texte, exemple des références de cellules, ex : (1,1) et des formules du type Moy((1,1), (2,3)). Pour le moment, mon programme n’accepte que des valeur numérique pour le moment, c’est surement du à ma gestion de l’erreur mais je n’arrive pas à trouver comment le résoudre et qu’il accepte du texte :
catch(NumberFormatException e){
System.out.println("e;e;Error: Not a number"e;e;);
}

- Écrire le code pour importer les valeurs d’un fichier dans le tableur. La méthode loadFile permet d’importer un fichier table.txt dont Chaque valeur de cellule est séparée par un & et chaque ligne du fichier correspond à une ligne du tableur. Je pense que je vais parser le fichier ligne par ligne, faire un slip sur le caractère & et enregistrer les valeurs dans un array list. Puis insérer ces valeurs dans les cellules du tableur à la ligne correspondante. Je pense créer une méthode assignCells( array list) dans la classe Grid afin de réaliser ces opérations, est ce que cela vous semble correcte ?

- Calculer le résultat des formules dans les cellules. Exemple, si la valeur de la cellule (2,2) est (1,1) + 2, il faut calculer le résultat en remplaçant (1,1) avec sa valeur numérique. Idem pour les autres opérations arithmétiques : +, -, *, /, Somme, Moy. Pour le déclenchement des opérations, je pense faire une loop dans la classe Program qui va parcourir toutes les cellules du tableur et pour chaque cellule, parser le contenu et détecter s’il y a s’agit d’un opération avec un opérateur (+, -, *, /, Somme, Moy) et si c’est le cas, réaliser le calcul. Pour le calcul, je pense créer les méthodes add, substract, multiply, divide, Sum, Mean dans la classe Grid. Est ce que cela vous semble judicieux ?

- Représentation graphique de la table. Comment connecter le tableur avec l’interface graphique UseCalcGUI et CalcGUI afin d’afficher les valeurs dans le layout de la fenêtre. Je ne suis pas encore très à l’aise avec JFrame et donc j’ai un peu de mal à comprendre comment avoir accès aux parties du Layout. Est ce que vous auriez des idées ?

La suite du projet demande de gérer les dépendances entre cellules (point 4.2 de la consigne) en créant un cycle dans les références de cellules lorsqu’une cellule est modifiée et également de désigner les références de cellules de manière relative (point 5 de la consigne, le point 3 n’est pas demandé). Je ne suis pas encore à ces étapes.

Je vous invite à aller faire un tour sur mon repository Github (https://github.com/henryd02/spreadsheet_java) afin de comprendre plus en détail le projet, regarder la structure du code et me dire ce qui pourrait être amélioré,

Je reste à disposition si vous avez besoin d’information complémentaire,

Bien cordialement,

Henry

5 réponses

Avatar
Yliur
Le Mon, 14 Jun 2021 04:26:15 -0500, henryd a écrit :
Bonjour
Pour commencer, je dirais que ce projet est sensiblement plus complexe
que le précédent, d'un point de vue algorithmique, modélisation ou
utilisation de bibliothèques (swing, pour l'interface graphique). Mieux
vaut sans doute être Í  l'aise avec le précédent avant de se lancer dedans.
Es-tu plutÍ´t débutant en programmation ? Est-ce un projet qu'on t'a donné
ou bien un projet que tu as choisi de réaliser pour apprendre ?
J’ai créé différentes classes : Programme (celle qui exécute le
programme), Grid (représente le tableur), Node (la cellule), Value (la
valeur d’une cellule),

Pourquoi ne stockes-tu pas le tableau gridArray dans un attribut de Grid,
au lieu de construire une structure complexe permettant de lier les
cellules les unes aux autres ? Il est plus simple d'accéder aux cellules
par leurs coordonnées.
J’ai actuellement plusieurs points bloquants :
- Le programme n’accepte pas que l’utilisateur rentre du texte, exemple
des références de cellules, ex : (1,1) et des formules du type
Moy((1,1), (2,3)).
Pour le moment, mon programme n’accepte que des valeur numérique pour le
moment, c’est surement du Í  ma gestion de l’erreur mais je n’arrive pas
Í  trouver comment le résoudre et qu’il accepte du texte :
catch(NumberFormatException e){
System.out.println("e;e;Error: Not a number"e;e;);
}

Comme je l'ai indiqué dans mon message dans l'autre fil de discussion,
laisse courir les exceptions : ne les capture pas comme ça. Le mieux est
de les laisser planter le programme, tu obtiendras une pile d'appels qui
t'indiquera (et nous indiquera, si tu ne sais pas quoi en faire) Í  quel
endroit précis le programme a planté.
- Écrire le code pour importer les valeurs d’un fichier dans le tableur.
La méthode loadFile permet d’importer un fichier table.txt dont Chaque
valeur de cellule est séparée par un & et chaque ligne du fichier
correspond Í  une ligne du tableur. Je pense que je vais parser le
fichier ligne par ligne, faire un slip sur le caractère & et enregistrer
les valeurs dans un array list. Puis insérer ces valeurs dans les
cellules du tableur Í  la ligne correspondante. Je pense créer une
méthode assignCells( array list) dans la classe Grid afin de réaliser
ces opérations, est ce que cela vous semble correcte ?

Suivant comment ton code est agencé, tu n'as pas forcément besoin du
tableau (ArrayList) intermédiaire. Sinon oui, ça me paraÍ®t correct.
- Calculer le résultat des formules dans les cellules. Exemple, si la
valeur de la cellule (2,2) est (1,1) + 2, il faut calculer le résultat
en remplaçant (1,1) avec sa valeur numérique. Idem pour les autres
opérations arithmétiques : +, -,
*, /, Somme, Moy. Pour le déclenchement des opérations, je pense faire
une loop dans la classe Program qui va parcourir toutes les cellules du
tableur et pour chaque cellule, parser le contenu et détecter s’il y a
s’agit d’un opération avec un opérateur (+, -, *, /, Somme, Moy) et si
c’est le cas, réaliser le calcul. Pour le calcul, je pense créer les
méthodes add, substract, multiply, divide, Sum, Mean dans la classe
Grid. Est ce que cela vous semble judicieux ?

Non, a priori.
Mais surtout : si tu débutes en programmation, l'analyse syntaxique des
formules, l'exécution de formules et la modélisation des liens entre
cellules pour détecter les cycles et les mises Í  jour Í  réaliser, ça me
paraͮt un peu tendu : il y a pas mal de travail d'algorithmique et de
modélisation. Et dans tous les cas c'est Í  réaliser (l'analyse syntaxique
et la modélisation des formules au moins) avant de se demander comment
les calculer. Tu n'as jamais eu aucun cours sur ces sujets ?
- Représentation graphique de la table. Comment connecter le tableur
avec l’interface graphique UseCalcGUI et CalcGUI afin d’afficher les
valeurs dans le layout de la fenêtre. Je ne suis pas encore très Í 
l’aise avec JFrame et donc j’ai un peu de mal Í  comprendre comment avoir
accès aux parties du Layout. Est ce que vous auriez des idées ?

Tu devrais avoir un tableau Í  deux dimensions représentant les valeurs de
la grille, et tu as un tableau Í  deux dimensions dans ta fenêtre (nommé
"tft") : quand tu veux mettre Í  jour la cellule (2,1), tu attrapes le
champ de saisie correspondant dans tft et tu modifies sa valeur. Tu n'as
pas besoin d'accéder aux autres éléments de la fenêtre pour cette mise Í 
jour.
Yliur
Avatar
henryd
Le mardi 15 Juin 2021 à 11:49 par Yliur :
Le Mon, 14 Jun 2021 04:26:15 -0500, henryd a écrit :
Bonjour
Pour commencer, je dirais que ce projet est sensiblement plus complexe
que le précédent, d'un point de vue algorithmique,
modélisation ou
utilisation de bibliothèques (swing, pour l'interface graphique). Mieux
vaut sans doute être Í  l'aise avec le
précédent avant de se lancer dedans.
Es-tu plutÍ´t débutant en programmation ? Est-ce un projet
qu'on t'a donné
ou bien un projet que tu as choisi de réaliser pour apprendre ?
J’ai créé différentes classes : Programme (celle
qui exécute le
programme), Grid (représente le tableur), Node (la cellule), Value (la
valeur d’une cellule),
Pourquoi ne stockes-tu pas le tableau gridArray dans un attribut de Grid,
au lieu de construire une structure complexe permettant de lier les
cellules les unes aux autres ? Il est plus simple d'accéder aux cellules
par leurs coordonnées.
J’ai actuellement plusieurs points bloquants :
- Le programme n’accepte pas que l’utilisateur rentre du texte,
exemple
des références de cellules, ex : (1,1) et des formules du type
Moy((1,1), (2,3)).
Pour le moment, mon programme n’accepte que des valeur numérique
pour le
moment, c’est surement du Í  ma gestion de l’erreur
mais je n’arrive pas
Í  trouver comment le résoudre et qu’il accepte du
texte :
catch(NumberFormatException e){
System.out.println("e;e;Error: Not a number"e;e;);
}
Comme je l'ai indiqué dans mon message dans l'autre fil de discussion,
laisse courir les exceptions : ne les capture pas comme ça. Le mieux est
de les laisser planter le programme, tu obtiendras une pile d'appels qui
t'indiquera (et nous indiquera, si tu ne sais pas quoi en faire) Í 
quel
endroit précis le programme a planté.
- Écrire le code pour importer les valeurs d’un fichier dans le
tableur.
La méthode loadFile permet d’importer un fichier table.txt dont
Chaque
valeur de cellule est séparée par un & et chaque ligne du
fichier
correspond Í  une ligne du tableur. Je pense que je vais parser le
fichier ligne par ligne, faire un slip sur le caractère & et
enregistrer
les valeurs dans un array list. Puis insérer ces valeurs dans les
cellules du tableur Í  la ligne correspondante. Je pense
créer une
méthode assignCells( array list) dans la classe Grid afin de
réaliser
ces opérations, est ce que cela vous semble correcte ?
Suivant comment ton code est agencé, tu n'as pas forcément besoin
du
tableau (ArrayList) intermédiaire. Sinon oui, ça me
paraͮt correct.
- Calculer le résultat des formules dans les cellules. Exemple, si la
valeur de la cellule (2,2) est (1,1) + 2, il faut calculer le résultat
en remplaçant (1,1) avec sa valeur numérique. Idem pour les
autres
opérations arithmétiques : +, -,
*, /, Somme, Moy. Pour le déclenchement des opérations, je pense
faire
une loop dans la classe Program qui va parcourir toutes les cellules du
tableur et pour chaque cellule, parser le contenu et détecter
s’il y a
s’agit d’un opération avec un opérateur (+, -, *, /,
Somme, Moy) et si
c’est le cas, réaliser le calcul. Pour le calcul, je pense
créer les
méthodes add, substract, multiply, divide, Sum, Mean dans la classe
Grid. Est ce que cela vous semble judicieux ?
Non, a priori.
Mais surtout : si tu débutes en programmation, l'analyse syntaxique des
formules, l'exécution de formules et la modélisation des liens
entre
cellules pour détecter les cycles et les mises Í  jour
Í  réaliser, ça me
paraͮt un peu tendu : il y a pas mal de travail d'algorithmique et
de
modélisation. Et dans tous les cas c'est Í  réaliser
(l'analyse syntaxique
et la modélisation des formules au moins) avant de se demander comment
les calculer. Tu n'as jamais eu aucun cours sur ces sujets ?
- Représentation graphique de la table. Comment connecter le tableur
avec l’interface graphique UseCalcGUI et CalcGUI afin d’afficher
les
valeurs dans le layout de la fenêtre. Je ne suis pas encore très
Í 
l’aise avec JFrame et donc j’ai un peu de mal Í 
comprendre comment avoir
accès aux parties du Layout. Est ce que vous auriez des idées ?
Tu devrais avoir un tableau Í  deux dimensions représentant
les valeurs de
la grille, et tu as un tableau Í  deux dimensions dans ta
fenêtre (nommé
"tft") : quand tu veux mettre Í  jour la cellule (2,1),
tu attrapes le
champ de saisie correspondant dans tft et tu modifies sa valeur. Tu n'as
pas besoin d'accéder aux autres éléments de la
fenêtre pour cette mise Í 
jour.
Yliur
Hello Yliur,
Merci beaucoup pour ton retour :)
Me concernant, je suis chef de projet technique en système d’information donc pas développeur de formation. L’année dernière j’ai commencé à développer en Python et cette année je me suis mis à Java. Effectivement l’autre projet est plus simple mais j’ai une échéance plus courte pour celui là donc je dois avancer dessus :)
Pour répondre aux différents points dans ton message précédent :
- Pour le tableau gridArray en tant qu’attribut de Grid tu as raison ça m’a l’air beaucoup plus simple. J’étais partie sur une classe Node afin de pratiquer les classes mais bon pas forcément judicieux. Je vais essayer de voir pour faire une modification.
Pour les exceptions, effectivement, je les ai laissé courir (finally {}) et ça m’a permis de voir d’où venait l’erreur et de la corriger, les expressions sont acceptées maintenant !
- Pour l’importation du fichier dans le tableur, j’ai parsé le contenu du fichier et importé les différentes valeurs dans un ArrayList puis je l’ai envoyé à la méthode importFile afin de les transférer dans l’objet Node. Effectivement, comme tu l’as suggéré, peut-être qu’on pourrait juste enregistrer cet ArrayList comme attribut de la classe Grid et aussi remplacer les valeurs de l’ArrayList par l’objet Valeur ayant les attributs : tag, dval, sval utiles par la suite ?
- Pour l’analyse syntaxique des formules dans les cellules, je pensais faire une Regex Pattern.compile("+", Pattern.CASE_INSENSITIVE); afin de détecter les opérations à faire dans les cellules. Une fois l’opération détectée, faire le calcul et stocker le résultat dans l’attribut dval de la classe Value. Est ce que ça te semble une bonne solution ?
- Concernant la modélisation des liens entre les cellules, pour gérer les dépendances, d’après ce qui était conseillé dans le projet, il faudrait créer en attribut de chaque cellule (ou de la classe Value), une liste avec les coordonnées des cellules qui dépendent de C. Pour détecter un cycle, il faut vérifier, à chaque fois que l’utilisateur rentre une valeur, s’il y une référence déjà présente dans la liste des cellules qui dépendent de C. Si c’est le cas, ne pas autoriser à la renseigner. Idem, pour la mise à jour automatique d’une cellule. A chaque fois qu’une cellule est modifier, il faut mettre à jour les cellules qui sont renseignées dans la liste des cellules qui dépendent d’elle et ainsi de suite (la valeur du calcul est stockée dans l’attribut dval de l’objet Value et la valeur texte (formule) dans l’attribut sval ce qui permet de pouvoir recalculer la formule). Est ce que cette algorithme te semble judicieux pour modéliser les liaisons entre les cellules ?
- Merci pour l’information concernant le tableau à 2 dimensions tft afin de mettre à jour les cellules dans la fenêtre. Je vais regarder afin de mettre les valeurs contenues dans la liste ArrayList dans le tableau tft pour qu’elles soient affichées dans l’interface graphique
- Dans le point 5 du projet, il est demandé que le programme prenne en charge les références de cellules relatives avec le signe $. Pour calculer, la position d'une cellule ayant une référence relative $(1,2) dans la cellule (2,3) par exemple est la position absolue : (1,1) (1 ligne plus haute et 2 colonnes vers la gauche), est bien cela ? Car je n’arrive pas à comprendre l’exemple qu’ils donnent dans l’explication. Idem que dans l'affichage du contenu de la cellule référencée de manière absolue, il faut afficher sa valeur dans la cellule de destination pour pouvoir faire le calcul, je ferai donc la même technique que celle utilisée pour les références absolues c’est à dire avec le tableau des références qui dépendent de la cellules
- Je t’invite à me dire s’il y a d’autres points importants que je pourrais améliorer dans mon code ou qu'il pourrait être intéressant d'approfondir dans le projet :)
Merci beaucoup pour ton aide :)
Bien cordialement,
Henry
Avatar
Yliur
Le Tue, 15 Jun 2021 13:25:37 -0500, henryd a écrit :
Pour répondre aux différents points dans ton message précédent :
- Pour le tableau gridArray en tant qu’attribut de Grid tu as raison ça
m’a l’air beaucoup plus simple. J’étais partie sur une classe Node afin
de pratiquer les classes mais bon pas forcément judicieux. Je vais
essayer de voir pour faire une modification.

Tu peux tout Í  fait garder cette classe, simplement il est plus pratique
d'accéder aux cellules par leurs coordonnées que de suivre des liens
entre elles. Au lieu d'une méthode traverse qui parcourt les cellules, tu
aurais une méthode plus simple qui contiendrait
return gridArray[i][j] ;
Par contre tu pourrais peut-être fusionner Node et Value, pour
simplifier. Ce sont bien deux concepts distincts, mais pour chaque
cellule il y a une valeur et réciproquement, donc il est possible de les
fusionner si c'est plus simple.
- Pour l’importation du fichier dans le tableur, j’ai parsé le contenu
du fichier et importé les différentes valeurs dans un ArrayList puis je
l’ai envoyé Í  la méthode importFile afin de les transférer dans l’objet
Node. Effectivement, comme tu l’as suggéré, peut-être qu’on pourrait
juste enregistrer cet ArrayList comme attribut de la classe Grid et
aussi remplacer les valeurs de l’ArrayList par l’objet Valeur ayant les
attributs : tag, dval, sval utiles par la suite ?

Je pensais plutÍ´t Í  mettre tout le code de lecture du fichier dans
importFile et Í  remplir directement gridArray avec des objets Node/
Value : tu fais déjÍ  les deux boucles sur les lignes et sur les éléments
de la ligne quand tu lis le fichier, il te suffirait de remplir les cases
au fur et Í  mesure, au lieu de passer par des structures intermédiaires.
- Pour l’analyse syntaxique des formules dans les cellules, je pensais
faire une Regex Pattern.compile("+", Pattern.CASE_INSENSITIVE); afin
de détecter les opérations Í  faire dans les cellules. Une fois
l’opération détectée, faire le calcul et stocker le résultat dans
l’attribut dval de la classe Value. Est ce que ça te semble une bonne
solution ?

En relisant la consigne, je m'aperçois que les calculs en question ne
consistent qu'en une seule opération, ça ne peut pas être complexe. Ça
rend le projet plus abordable que ce que je pensais.
Je ne sais pas très calé en expressions rationnelles. Si tu sais t'en
servir, c'est bien. Sinon les opérations simples de manipulation des
chaͮnes suffiront.
Il te faut effectivement détecter l'opérateur (opérateur arithmétique ou
fonction Somme/Moy), extraire les opérandes et réaliser l'opération
correspondante.
- Concernant la modélisation des liens entre les cellules, pour gérer
les dépendances, d’après ce qui était conseillé dans le projet, il
faudrait créer en attribut de chaque cellule (ou de la classe Value),
une liste avec les coordonnées des cellules qui dépendent de C. Pour
détecter un cycle, il faut vérifier, Í  chaque fois que l’utilisateur
rentre une valeur, s’il y une référence déjÍ  présente dans la liste des
cellules qui dépendent de C. Si c’est le cas, ne pas autoriser Í  la
renseigner. Idem, pour la mise Í  jour automatique d’une cellule. A
chaque fois qu’une cellule est modifier, il faut mettre Í  jour les
cellules qui sont renseignées dans la liste des cellules qui dépendent
d’elle et ainsi de suite (la valeur du calcul est stockée dans
l’attribut dval de l’objet Value et la valeur texte (formule) dans
l’attribut sval ce qui permet de pouvoir recalculer la formule). Est ce
que cette algorithme te semble judicieux pour modéliser les liaisons
entre les cellules ?

Vois-tu comment fonctionne la récursion ? Parce que le cycle peut
impliquer un paquet de cellules, il faut remonter les cellules pour
vérifier qu'il n'y a aucun cycle d'aucune longueur. Sais-tu comment faire
ça ?
- Dans le point 5 du projet, il est demandé que le programme prenne en
charge les références de cellules relatives avec le signe $. Pour
calculer, la position d'une cellule ayant une référence relative $(1,2)
dans la cellule (2,3) par exemple est la position absolue : (1,1) (1
ligne plus haute et 2 colonnes vers la gauche), est bien cela ? Car je
n’arrive pas Í  comprendre l’exemple qu’ils donnent dans l’explication.

C'est ce que je comprends. C'est bizarre de compter comme ça par contre,
j'aurais plutÍ´t considéré les valeurs positives de décalage vers le bas
et la droite.
Idem que dans l'affichage du contenu de la cellule référencée de manière
absolue, il faut afficher sa valeur dans la cellule de destination pour
pouvoir faire le calcul, je ferai donc la même technique que celle
utilisée pour les références absolues c’est Í  dire avec le tableau des
références qui dépendent de la cellules

Oui.
- Je t’invite Í  me dire s’il y a d’autres points importants que je
pourrais améliorer dans mon code ou qu'il pourrait être intéressant
d'approfondir dans le projet :)

Ça me paraÍ®t déjÍ  beaucoup de travail... :)
Il reste pas mal d'endroits o͹ tu ne laisses pas filer les exceptions,
c'est dommage en cas de bug.
Note que si tu laisses filer les exceptions le try/catch ou try-finally
n'est pas nécessaire (sauf dans le cas o͹ tu utilises la try pour gérer
automatiquement la fermeture de flux, comme InputStream).
Avatar
henryd
Le mardi 15 Juin 2021 à 22:55 par Yliur :
Le Tue, 15 Jun 2021 13:25:37 -0500, henryd a écrit :
Pour répondre aux différents points dans ton message
précédent :
- Pour le tableau gridArray en tant qu’attribut de Grid tu as raison
ça
m’a l’air beaucoup plus simple. J’étais partie sur
une classe Node afin
de pratiquer les classes mais bon pas forcément judicieux. Je vais
essayer de voir pour faire une modification.
Tu peux tout Í  fait garder cette classe, simplement il est plus
pratique
d'accéder aux cellules par leurs coordonnées que de suivre des
liens
entre elles. Au lieu d'une méthode traverse qui parcourt les cellules,
tu
aurais une méthode plus simple qui contiendrait
return gridArray[i][j] ;
Par contre tu pourrais peut-être fusionner Node et Value, pour
simplifier. Ce sont bien deux concepts distincts, mais pour chaque
cellule il y a une valeur et réciproquement, donc il est possible de les
fusionner si c'est plus simple.
- Pour l’importation du fichier dans le tableur, j’ai parsé
le contenu
du fichier et importé les différentes valeurs dans un ArrayList
puis je
l’ai envoyé Í  la méthode importFile afin de
les transférer dans l’objet
Node. Effectivement, comme tu l’as suggéré,
peut-être qu’on pourrait
juste enregistrer cet ArrayList comme attribut de la classe Grid et
aussi remplacer les valeurs de l’ArrayList par l’objet Valeur
ayant les
attributs : tag, dval, sval utiles par la suite ?
Je pensais plutÍ´t Í  mettre tout le code de lecture
du fichier dans
importFile et Í  remplir directement gridArray avec des objets
Node/
Value : tu fais déjÍ  les deux boucles sur les lignes et sur
les éléments
de la ligne quand tu lis le fichier, il te suffirait de remplir les cases
au fur et Í  mesure, au lieu de passer par des structures
intermédiaires.
- Pour l’analyse syntaxique des formules dans les cellules, je pensais
faire une Regex Pattern.compile("+", Pattern.CASE_INSENSITIVE);
afin
de détecter les opérations Í  faire dans les
cellules. Une fois
l’opération détectée, faire le calcul et stocker le
résultat dans
l’attribut dval de la classe Value. Est ce que ça te semble une
bonne
solution ?
En relisant la consigne, je m'aperçois que les calculs en question ne
consistent qu'en une seule opération, ça ne peut pas être
complexe. Ça
rend le projet plus abordable que ce que je pensais.
Je ne sais pas très calé en expressions rationnelles. Si tu sais
t'en
servir, c'est bien. Sinon les opérations simples de manipulation des
chaͮnes suffiront.
Il te faut effectivement détecter l'opérateur (opérateur
arithmétique ou
fonction Somme/Moy), extraire les opérandes et réaliser
l'opération
correspondante.
- Concernant la modélisation des liens entre les cellules, pour
gérer
les dépendances, d’après ce qui était
conseillé dans le projet, il
faudrait créer en attribut de chaque cellule (ou de la classe Value),
une liste avec les coordonnées des cellules qui dépendent de C.
Pour
détecter un cycle, il faut vérifier, Í  chaque fois
que l’utilisateur
rentre une valeur, s’il y une référence
déjÍ  présente dans la liste des
cellules qui dépendent de C. Si c’est le cas, ne pas autoriser
Í  la
renseigner. Idem, pour la mise Í  jour automatique d’une
cellule. A
chaque fois qu’une cellule est modifier, il faut mettre Í 
jour les
cellules qui sont renseignées dans la liste des cellules qui
dépendent
d’elle et ainsi de suite (la valeur du calcul est stockée dans
l’attribut dval de l’objet Value et la valeur texte (formule) dans
l’attribut sval ce qui permet de pouvoir recalculer la formule). Est ce
que cette algorithme te semble judicieux pour modéliser les liaisons
entre les cellules ?
Vois-tu comment fonctionne la récursion ? Parce que le cycle peut
impliquer un paquet de cellules, il faut remonter les cellules pour
vérifier qu'il n'y a aucun cycle d'aucune longueur. Sais-tu comment
faire
ça ?
- Dans le point 5 du projet, il est demandé que le programme prenne en
charge les références de cellules relatives avec le signe $.
Pour
calculer, la position d'une cellule ayant une référence relative
$(1,2)
dans la cellule (2,3) par exemple est la position absolue : (1,1) (1
ligne plus haute et 2 colonnes vers la gauche), est bien cela ? Car je
n’arrive pas Í  comprendre l’exemple qu’ils
donnent dans l’explication.
C'est ce que je comprends. C'est bizarre de compter comme ça par contre,
j'aurais plutÍ´t considéré les valeurs positives de
décalage vers le bas
et la droite.
Idem que dans l'affichage du contenu de la cellule
référencée de manière
absolue, il faut afficher sa valeur dans la cellule de destination pour
pouvoir faire le calcul, je ferai donc la même technique que celle
utilisée pour les références absolues c’est
Í  dire avec le tableau des
références qui dépendent de la cellules
Oui.
- Je t’invite Í  me dire s’il y a d’autres
points importants que je
pourrais améliorer dans mon code ou qu'il pourrait être
intéressant
d'approfondir dans le projet :)
Ça me paraÍ®t déjÍ  beaucoup de travail...
:)
Il reste pas mal d'endroits o͹ tu ne laisses pas filer les
exceptions,
c'est dommage en cas de bug.
Note que si tu laisses filer les exceptions le try/catch ou try-finally
n'est pas nécessaire (sauf dans le cas o͹ tu utilises la
try pour gérer
automatiquement la fermeture de flux, comme InputStream).
Hello Yliur,
Merci beaucoup pour toutes tes explications très claires :)
- Concernant la mise en place d’une méthode return gridArray[i][j] au lieu de la méthode traverse dans la classe Grid effectivement cela simplifierait. Est ce qu’il faut aussi que je mette gridArray[i][j] en tant qu’attribut de la classe Grid car je ne pense pas que ce soit le cas ? Pour la fusion de Node et Value, je pourrais mettre les attributs de Value (dval, sval, tag) dans Node afin d’utiliser uniquement Node. Effectivement pour l’import du fichier, je pourrais remplir la liste gridArray avec les Node/ Value directement dans la fonction loadFile lorsque je parcours la liste. Est ce que ces points te semblent corrects ?
- J’ai implémenté le code avec les expressions rationnelles pour détecter les références, opérandes et les opérations à faire dans une cellule et réaliser les calculs. Je sais que ça ne doit pas être très optimisé ou lisible mais ça m’a l’air de fonctionner. Peut être faire une boucle et une fonction pour éviter de répéter à chaque fois Pattern, Matcher ?
- Pour réaliser le cycle grâce aux fonctions récursives : remonter les cellules pour vérifier qu’il n’y a aucun cycle d’aucune longueur, je ne suis pas encore très à l’aise avec les fonctions récursives, est ce que tu aurais une idée de comment faire s’il te plait ?
f([c]) {
f([c])
}
- Pour les coordonnées relatives, je penses qu’il n’y aura pas beaucoup de difficultés, une fois que la méthode gridArray[i][j] sera implémenté, il faudra retrouver la position relative grâce à la position de cellule d’origine donc peut être créer une méthode convertRelativeToAbsolue.
Merci beaucoup pour ton aide :)
Bien cordialement,
Henry
Avatar
Yliur
Bonjour
- Concernant la mise en place d’une méthode return gridArray[i][j] au
lieu de la méthode traverse dans la classe Grid effectivement cela
simplifierait. Est ce qu’il faut aussi que je mette gridArray[i][j] en
tant qu’attribut de la classe Grid car je ne pense pas que ce soit le
cas ?

Si : il te faut créer un attribut de type Node[][] dans la classe et le
remplir dans le constructeur. Sinon tu ne pourras pas y accéder dans les
autres méthodes. C'est en remplacement de l'attribut head, un moyen plus
simple d'accéder aux cellules.
Et une méthode qui aurait par exemple cette signature :
public Node cellule (int ligne, int colonne)
et qui se contenterait d'aller voir dans le tableau ; Í  la place de
traverse.
Pour la fusion de Node et Value,
je pourrais mettre les attributs de Value (dval, sval, tag) dans Node
afin d’utiliser uniquement Node. Effectivement pour l’import du fichier,
je pourrais remplir la liste gridArray avec les Node/ Value directement
dans la fonction loadFile lorsque je parcours la liste. Est ce que ces
points te semblent corrects ?

Oui. Il te faudra sans doute un autre constructeur pour Grid, qui prend
en paramètre un le tableau de type Node[][] au lieu d'en créer un lui-
même comme dans ton constructeur actuel. Les deux constructeurs peuvent
cohabiter. Ou bien tu remplis les cases d'une grille existante, au choix.
- J’ai implémenté le code avec les expressions rationnelles pour
détecter les références, opérandes et les opérations Í  faire dans une
cellule et réaliser les calculs. Je sais que ça ne doit pas être très
optimisé ou lisible mais ça m’a l’air de fonctionner. Peut être faire
une boucle et une fonction pour éviter de répéter Í  chaque fois Pattern,
Matcher ?

Tu pourrais effectivement avoir une fonction pour éviter de répéter le
code de test de l'expression rationnelle, par contre je ne pense pas
qu'une boucle t'aide tellement.
Une note sur les performances : ce n'est pas important pour ton projet,
mais Pattern.compile ça peut coÍ»ter quelque chose. Donc dans un vrai
projet tu préféreras peut-être stocker le résultat quelque part une fois
au chargement de la classe, avant toutes tes fonctions :
private static Pattern ... = Pattern.compile (...) ;
Avec des noms précis, pour éviter d'exécuter ce traitement Í  chaque appel
de la fonction.
- Pour réaliser le cycle grÍ¢ce aux fonctions récursives : remonter les
cellules pour vérifier qu’il n’y a aucun cycle d’aucune longueur, je ne
suis pas encore très Í  l’aise avec les fonctions récursives, est ce que
tu aurais une idée de comment faire s’il te plait ?
f([c]) {
f([c])
}

En y repensant, je pense qu'on peut faire sans récursion. Tu vas avoir
besoin des classes de type Set (des ensembles de données, sans ordre
particulier et sans doublons en général). Tu peux par exemple utiliser
HashSet.
Tu as besoin de remonter les cellules dépendant de la cellule, et ainsi
de suite, en notant toutes celles qui sont passées et en vérifiant que tu
ne retombes jamais sur celle de départ.
Ça devrait marcher approximativement comme ça :
- Tu initialises l'ensemble des cellules déjÍ  passées, il est vide.
- Tu initialises l'ensemble des cellules Í  traiter en plaçant dedans
la cellule de départ.
- Tu commences une boucle qui se termine quand il n'y a plus aucun
élément dans l'ensemble de cellules Í  traiter.
- Dans la boucle, tu prend un élément de l'ensemble des cellules Í 
traiter (par exemple avec ensemble.iterator().next(), sans
parcourir toutes les valeurs de l'ensemble Í  la suite : tu te
contentes d'en piocher un).
- Si cette cellule se trouve dans les cellules déjÍ  passées, tu
l'ignores.
- Sinon tu considères les cellules qui dépendent de celle que tu
viens de piocher, si l'une d'elle est ta cellule de départ
c'est qu'il y a un cycle, tu peux arrêter tout le processus.
Sinon tu places ces cellules dans les cellules Í  traiter.
- Si Í  un moment il n'y a plus de cellules dans l'ensemble de celles
Í  traiter, c'est qu'il n'y a pas de cycle.
L'idée est de remonter les cellules en vérifiant qu'on ne retombe jamais
sur celle de départ.
C'est une forme d'algorithme assez classique, ça te resservira sans doute.
Dans ton cas il est même possible de le simplifier un peu : en
considérant qu'il n'y a pas de cycle dans le reste des cellules
(puisqu'on vérifie au fur et Í  mesure), on pourrait se dispenser de noter
les cellules déjÍ  passées. Un cas conduirait Í  examiner plus de
cellules : celui o͹ une cellule est, directement ou indirectement, dans
les dépendances de deux cellules : si C0 dépend de C1 et C2, C1 et C2
dépendent chacune de C3 et que C3 dépend de C4, on examinerait deux fois
le cas de C3 et C4. Ce n'est pas forcément très grave dans ton cas, donc
tu peux te dispenser de l'ensemble de cellules déjÍ  examinées si tu veux.
Yliur