Art ASCII
Série 10 – corrigé
Le code du corrigé est disponible sous la forme d'une archive Zip, qui contient également le code de l'énoncé. Les solutions aux différents exercices sont brièvement discutées ci-dessous.
Visibilité des classes
Les classes représentant les images ASCII de base, les décorateurs et les composites n'ont pas été définies comme publiques et sont donc uniquement visibles dans leur paquetage. L'idée est que l'utilisateur de cette bibliothèque ne devrait interagir avec elle qu'au travers de l'interface TextImage
, sans jamais utiliser directement les classes.
Cette approche est utilisée dans certaines parties récentes de la bibliothèque Java, p.ex. l'interface Stream
que nous examinerons prochainement.
Exercice 1 : images de base
La classe FromString
permet d'adapter une chaîne de caractères pour en faire une image ASCII. Sa définition est triviale. Notez toutefois l'utilisation de la méthode singletonList
de Collections
, qui simplifie l'écriture de la méthode drawing
.
La classe Filled
est aussi simple que la classe FromString
. Là aussi, notez que l'utilisation judicieuse des méthode nCopies
de Collections
et Strings
permet de simplifier l'écriture du code.
Exercice 2 : transformations
La classe FlippedHorizontally
transforme une image par symétrie horizontale. Cette symétrie se fait simplement en inversant chacune des chaînes composant le dessin de l'image à transformer.
La classe Transposed
transforme une image par transposition. Cette transposition se fait en créant un bâtisseur de chaîne par ligne de l'image transposée, puis en parcourant les lignes de l'image à tranposer, ajoutant chaque caractère au bâtisseur correpondant. Cela fait, les chaînes des bâtisseurs sont obtenues au moyen de la méthode toString
de chacun des bâtisseurs.
Exercice 3 : compositions
La classe LeftOf
compose deux images en plaçant la première à gauche de la seconde. La largeur d'une telle image composite est bien entendu la somme des largeurs des deux images composées, sa hauteur celle de la plus haute d'entre-elles. Le dessin se fait relativement facilement puisqu'il suffit de concaténer deux à deux les lignes des images à composer, en prenant soin de bien traiter le cas où une image est moins haute que l'autre. Dans ce cas, il faut remplacer ses lignes manquantes par des lignes vides (composées d'espaces) de la bonne largeur.
La classe Above
compose deux images en plaçant la première au sommet de la seconde. Elle est symétrique par rapport à LeftOf
, c'est-à-dire que sa largeur est celle de la plus large des images composées, sa hauteur leur somme. Le dessin consiste en les lignes de la première image suivies de celles de la seconde, chaque ligne étant au besoin remplie avec des espaces pour avoir la largeur requise.
Exercice 4 : dessin d'un échiquier
Le dessin d'un échiquier peut se faire de manière relativement simple en exploitant sa symétrie. Dans un premier temps, on définit deux images rectangulaires représentant respectivement une case noire et une case blanche :
TextImage black = TextImage.filled(CELL_WIDTH, CELL_HEIGHT, '#'); TextImage white = TextImage.filled(CELL_WIDTH, CELL_HEIGHT, ' ');
Cela fait, on place côte à côte ces deux cases pour obtenir une paire noir/blanche et, par symétrie horizontale, une paire blanche/noire :
TextImage bw = black.leftOf(white); TextImage wb = bw.flippedHorizontally();
Au moyen de ces deux paires symétriques, il est possible de définir un échiquier de deux cases de côté :
TextImage board2 = bw.above(wb);
En combinant quatre de ces échiquiers, on en obtient un de quatre cases de côté. Finalement, en combinant quatre échiquiers de quatre cases de côté, on obtient l'échiquier de huit cases de côté, que l'on encadre au moyen de la méthode framed
(définie plus bas) puis imprime :
TextImage board4 = (board2.leftOf(board2)).above(board2.leftOf(board2)); TextImage board8 = (board4.leftOf(board4)).above(board4.leftOf(board4)); board8.framed().printOn(System.out);
Encadrer une image peut se faire très facilement en combinant les cinq images suivantes : les deux images de la ligne du haut et du bas (identiques, nommées tb
ci-dessous), les deux images des colonnes de gauche et de droite (identiques, nommées lr
ci-dessous) et l'image à encadrer.
default public TextImage framed() { TextImage tb = fromString('+' + Strings.nCopies(width(), '-') + '+'); TextImage lr = fromString(Strings.nCopies(height(), '|')).transposed(); return tb.above(lr.leftOf(this.leftOf(lr)).above(tb)); }