En Kotlin 1.2 (cible JVM, nécessite une exécution en local et pas sur l’outil en ligne de JetBrains, nécessite Unicode 6.0) :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | fun main(args: Array<String>) {
println(`🎄`(30))
}
class `🎄`(private val n: Int) {
override fun toString(): String {
return if (line() < n) "${" ".repeat(n - line() - 1)}${"*".repeat(line() * 2 + 1)}\n$this"
else "${" ".repeat(n - 1)}#"
}
private fun line(): Int {
return ((Exception().stackTrace.size - 2) / 3) - 1
}
}
|
L’usage est très simple : il suffit de demander l’affichage du sapin de noël 🎄
avec le nombre de lignes en paramètre.
Ce sapin est un code unicode standard depuis Unicode 6.0 donc est un identificateur valide en Kotlin ; mais son point de code est au-delà de ce qui rentre dans UTF16, donc on doit le protéger par des ` (et accessoirement c’est invalide en Java).
Ensuite, on a toute la logique dans le .toString()
. On y trouve un abus de variables à l’intérieur de chaines de caractères, et surtout cette méthode a été rendue récursive : le $this
à la fin de la ligne 8 correspond à l’objet en cours, donc comme il est rendu dans une chaine de caractères on rappelle cette même méthode.
Enfin, pourquoi se faire chier à maintenir un compteur pour savoir quelle ligne est en cours de dessin, alors que puisqu’on a une fonction récursive, on peut déduire la ligne en cours d’affichage depuis la profondeur de la pile d’appel ?
C’est justement ce que fait la méthode de la ligne 12. Mais comme on a à ma connaissance aucun moyen direct de récupérer la profondeur de la pile d’appel, on crée une exception dont on récupère la pile d’appel donc sa taille.
Edit : Simplification de la méthode de la ligne 12.