Art ASCII

CS-108 — Corrigé de la série 7

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, comme nous l'avons vu.

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 of de List, 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 repeat de String 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 ligne à ligne, en extrayant à chaque itération la colonne correspondante de l'image à transposer.

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 TextImage framed() {
  TextImage tb =
    fromString('+' + "-".repeat(width()) + '+');
  TextImage lr =
    fromString("|".repeat(height())).transposed();
  return tb.above(lr.leftOf(this.leftOf(lr)).above(tb));
}