Pedantix avec un peu d’aide

Cette semaine, j’ai découvert, dans la grande vague des Wordle et autres Sutom, le jeu parfait pour moi : Pedantix. Pourquoi « parfait » ? Parce que je me pique d’avoir de la culture générale, et qu’un jeu qui me permet de deviner un mot à travers sa définition m’amuse beaucoup. Je m’y suis donc mis … une première fois

Et dès la première fois, je me suis dit que la meilleure façon de deviner les définitions était de choisir un bon ordre pour ajouter des mots dans la définition. Et pour ça, une liste des mots triés par fréquence est utile. J’ai donc utilisé successivement

Cela dit, vus mes scores (entre 200 et 300 mots pour deviner ce mot, loin derrière les meilleurs qu’on trouve sur Twitter, comme par exemple

Imaginez, 9 coups, c’est vraiment très peu.

Donc j’en suis loin. Et tant qu’à faire à être loin, pourquoi ne pas utiliser mes outils, c’est-à-dire … le scripting !

Et comme je voulais aller vite, j’ai évidement choisi de faire … du Python !

Résumons-nous. Il me faut

  • une liste de mots. La dernière fait l’affaire, malgré quelques étrangetés ([[�]] , nbsp, br font partie des mots très courants).
  • Un moyen d’injecter ces mots dans ma page web. Comme je ne voulais pas faire de Selenium, j’avais commencé à regardé du côté de Sikuli, qui est aussi lourd. Et Robot Framework est encore pire. En farfouillant un peu, je suis tombé sur PyAutoGUI, qui est très simple, et qui permet de détecter des éléments graphiques et d’interagir avec eux.

Et donc, c’était parti pour un petit script, qui a assez vite grossi.

import requests
from bs4 import BeautifulSoup
import codecs
import json
import pyautogui
import pyperclip
def main():
words = list()
with codecs.open("words.txt", "r", "utf-8") as f:
words = f.readlines()
for text in words:
# Don't forget this prefix is the pin prefix, not the classical one
text_field_location_prefix = pyautogui.locateOnScreen("pedantix_word_text_field_prefix.png")
if not text_field_location_prefix:
raise Exception("Can't find the pinned prefix. Is the pedantix window unpinned?")
text_field_location_suffix = pyautogui.locateOnScreen("pedantix_word_text_field_suffix.png")
if not text_field_location_prefix:
raise Exception("Unable to locate prefix")
if not text_field_location_suffix:
raise Exception("Unable to locate suffix")
x = (text_field_location_prefix.left+text_field_location_suffix.left+text_field_location_suffix.width)/2
y = (text_field_location_prefix.top+text_field_location_suffix.top+text_field_location_suffix.height)/2
# print("Prefix is at %s\nSuffix is at %s\nSeems like text field should be at (%d, %d)" %
# (text_field_location_prefix, text_field_location_suffix, x, y))
text = text.strip()
pyautogui.click(x, y)
# Mind you, pyautogui only handle keyboard keys, and not french accents
# So I prefer to copy word in clipboard, then paste it
print("Testing \"%s\""%(text))
pyperclip.copy(text)
pyautogui.click()
pyautogui.hotkey("ctrl", "v")
pyautogui.press('enter')
def handle_accents(letter):
if letter in REPLACEMENTS:
REPLACEMENTS[letter]
else:
letter
if __name__ == "__main__":
main()
view raw pedantix.py hosted with ❤ by GitHub

Si vous lisez les commentaires, c’est assez clair. J’essaye de détecter l’image avant la zone de texte (c’est celle-ci ), l’image après la zone de texte (c’est celle-là ). je ne détecte pas la zone de texte, parce que le texte qui est dedans change quand on fait une proposition.

Ensuite, je clique dedans avec PyAutoGUI, et je copie-colle le texte. Pourquoi copier-coller ? C’est écrit dans la doc des fonctions clavier de PyAutoGUI : on ne peut pas écrire les caractères é, è, ê, à avec PyAutoGUI. Heureusement, pyperclip me permet de prendre le mot depuis mon code et de le copier dans le presse-papier, ce que Ditto montre bien

Résultat ?

Et le texte s’est bien éclairci

La grande question étant … est-ce que je peux faire mieux ? Eh bien en fait, je crois bien, parce que Pedantix fournit une information : est-ce que le mot est utilisé ou pas. Et que mon outil de remplissage des mots courants ne me donne pas la réponse, il automatise juste le processus de découverte des mots courants. Si j’ajoute cette information des mots étant utilisés, il me semble possible d’utiliser un graphe d’usage des mots. Mais c’est encore un peu tôt pour ce genre d’optimisation, je pense.

2022, l’année de Linux sur mon bureau?

Depuis 20 ans, les linuxiens le prétendent, tous les ans (je voulais vous mettre plein de liens, mais j’ai eu la flemme), c’est l’année de Linux sur le bureau. Et c’est vrai que, de loin, Linux semble chaque année être un peu plus léché.

Et cet été, pour des raisons très personnelles, j’avais besoin pendant mes vacances d’un ordinateur pour faire quelques recherches d’ordre immobilier pour étudiants.

Je me suis donc dit que, plutôt que d’emmener avec moi mon ordinateur de travail (un terrifiant X1 Extreme avec Windows 10), je pouvais tenter l’aventure au coin de la rue et essayer plutôt d’utiliser sur un ordinateur portable qui traîne chez moi l’une de ces modernes et jolies distributions Linux qui font les beaux jours des sites spécialisés (techradar, tecadmin, et tant d’autres).

Evidement, j’aurais pu prendre la direction la plus simple et lancer Ubuntu. Seulement, je trouve le poli insuffisant.

Evidement, j’aurais pu reprendre une direction déja connue et installer la très belle Elementary OS (dont le plus grand défaut est de copier Mac OS, à mon avis).

Mais comme d’habitude, j’ai choisi le panache, et j’ai installé Pop OS.

Pourquoi ?

J’avais en fait plusieurs prérequis assez simples : je voulais une distribution basée sur Ubuntu, parce que je connais leurs efforts vers l’utilisabilité, et je voulais une distribution qui soit belle. Parce que sans être un esthète, le look désuet de certaines distributions me fait grincer les dents.

Donc paf, une clé USB, pouf une installation par défaut, et c’est parti pour trois semaines (après avoir installé et configuré minimalement Firefox, Thunderbird, Cozy Drive et KeepassXC).

Résultat ?

Mitigé. Le tiling window manager (voir scribe – désolé, il n’y a pas de page dédiée sur le site de System76)) est vraiment agréable et, dans l’ensemble, tout fonctionne. Mais Firefox et Thunderbird n’utilisent pas la police système. Ca n’est pas grave quand on ne fait que du web, mais dès qu’on affiche côte à côte (grâce à ce window manager) Firefox et une application native … Ca heurte les yeux.

J’ai donc fini mes vacances comme ça, et je me suis lancé dans une vague d’installations.

J’y ai fait passer

  • Linux Mint, dont le look vraiment trop daté m’a fait arrêter l’ordinateur au bout de … dix minutes
  • KDE neon, qui était plaisante et assez rapide, mais ne supportait apparemment pas Cozy Drive (je ne doute pas qu’avec un peu de hack dans la config ça marche, mais je ne veux pas faire ça).
  • Deepin Linux qui a un look très affirmé, dans lequel je ne me suis vraiment pas retrouvé, donc je l’ai désinstallée elle aussi en cinq minutes.

Et enfin Zorin OS. Malgré son nom de méchant de James Bond, la distribution est belle, rapide, Cozy Drive fonctionne bien, et Firefox semble utiliser une police proche du système. De ce fait, je pense pousser mon test plus loin. par exemple en vérifiant que KeepassXC supporte bien les fonctionnalités de Keepass dont j’ai besoin (agent SSH et générateur TOTP – oui, c’est écrit dans la doc, mais ça mérite d’être testé).

Il me faudra ensuite vérifier le support de quelques autres particularités de mon usage : comment fonctionne DroidCam for Linux ? Quel est l’équivalent à Spacedesk ? Et comment faire marcher Office ? Et enfin, est-ce que je vais devoir arrêter de jouer à World of Tanks après … quelques années (ou est-ce que Wine fonctionnera correctement) ?

Pour finir, une petite note sur les packages. Je croyais naïvement que dans le monde Debian/Ubuntu on utilisait des .deb qui contenaient ce qui était utile à l’application. Ca semblait bien marcher (suffisamment pour Raspbian en tout cas). Mais le magasin d’applications de ces différentes distributions n’a pas l’air d’accord : il y a du flatpak, de l’AppImage, du Snap. Alors déja que quand on arrive dans le monde Linuxien il faut choisir un environnement de bureau (KDE vs Gnome vs LXDE, vs …), un éditeur de texte (Emacs vs vi vs VSCode vs ….), si il faut en plus s’intéresser à la manière dont sont packagées les applications, ça devient vraiment n’importe quoi ! D’autant plus que certains formats sont moins prédictibles que d’autres. Par exemple, avec Flatpak, vous ne savez vraiment quel espace prend l’application sur le disque. Et pour le coup, ça met Linux (pardon, l’écosystème Ubuntu) en grand gagnant de l’OS pas green. Parce que si je remplace mon keepassxc.deb par un keepassxc.flatpack, et que je passe de 40 Mo à potentiellement 280 mo (je n’ai pas inventé les ordres de grandeur). Et je ne sais même pas comment dire à ma distribution que je ne veux pas de flatpak (parce que je n’ai pas un disque dur infiniment grand).

Il faut chaud, non ?

Nous sommes à la fin de l’été 2022. Et, pour ceux qui liront ce texte dans quelques années, l’été fût chaud. Franchement chaud (voir cet article sur le site de Météo-France).

Pour ma part, au moment de cette vague de chaleur, j’étais dans la région de Poitiers. Et j’ai été frappé, au retour d’une promenade en forêt, par la température affichée par la voiture : 41°C ! Pour ma part étant né dans le Nord de la France dans les années 70 (mais avant la sécheresse de 1976, seule sécheresse dans ma mémoire avant l’an 2000), cette température est … complètement dingue. Parce que dans ma jeunesse, un été chaud, c’était un été à 25-30.

Evidement, en 2003, lors de la première canicule « moderne », comme je travaillais encore à Paris, j’en ai un peu bavé. Ca avait duré moins d’une semaine, mais avait provoqué quelques milliers de morts, ainsi qu’une mesure vraiment crétine de diminution du nombre de jours non-travaillés au nom des personnes âgées (oui, je parle de la journée de solidarité).

Cette année, alors que le GIEC nous dit que nous devons vraiment, vraiment changer d’attitude rapidement et dans tous les domaines, on n’entend aucun politique parler de cette canicule. Forcément, parce qu’ils sont tous en vacances (comme de bons parisiens aoutiens) – à moins que l’information ne m’ait échappé.

Pire encore, au printemps dernier, mes concitoyens ont élu un président dont les actions lors de son quinquennat précédent ne brillaient pas forcément par leur impact sur le sujet le plus important pour la France et pour le monde entier (voir par exemple l’Express ou le Figaro, deux journaux d’écologistes – ou pas).

Et ce même président continue à fermer des lignes de chemin de fer pour les remplacer par des bus et camions, plus lents et plus polluants. Ce même président continue également à défiscaliser le carburant des avions (voir la fiscalité des carburants, et en particulier le paragraphe « Plusieurs secteurs d’activité économique bénéficient de réductions ou d’exonérations »).

Est-ce que cet article est pessimiste ? Sans doute que oui. Je ne sais pas quoi dire de plus. Et pour ceux qui me liront plus tard, je m’en excuse.

Blame

Encore un binge reading ?

Oui !

Cette fois, c’est à cause de cette vidéo d’Alt236

J’avais été intrigué par ce qi était raconté. Je me suis donc embarqué pour un long voyage dans la mégastructure.

Ce voyage m’a rappelé différentes oeuvres (auxquelles Alt236 n’a peut-être pas pensé) : j’y ai vu beaucoup de lien avec les cités obscures de Schuten & Peeters (en particulier La Tour), mais aussi avec cette spécialité de la science-fiction : le Big Dumb Object. On retrouve en effet cette errance dans un environnement inconnu (au moins du lecteur) et peuplé de structures à peine compréhensibles. Je pense évidement à Rama, qui fait partie des standards du genre, mais aussi à L’anneau-monde de Larry Niven, et surtout au Grand Vaisseau de Robert Reed.

Il y a par ailleurs un autre point commun avec ce dernier : l’oeuvre croise ce sous-genre assez particulier avec des aspects « post-cyberpunk » : les humains sont hybridés avec les machines, qui elles-mêmes ont plus d’organique que ce qu’on pourrait croire. Ca se retrouve d’ailleurs beaucoup dans les définitions des intervenants, qu’on voit comme silicates, sauvegardes, ou humains, mais qui tous peuvent se régénérer, semblent se connecter à une forme de réseau, et peuvent produire des membres adaptables.

Mais plus que la famille littéraire, c’est le récit, presque opaque, qui intrigue : le personnage principal est à peu près mutique, et les tomes multiplient à l’envie les scènes spectaculaires dans lesquelles les personnages sont réduits à l’insignifiance. Est-ce une métaphore sociale ? Une volonté de montrer la vanité de nos prétentions ? Un mode de dénonciation de l’hubris ? On n’en sait rien, parce que cette oeuvre ne laisse pas le sens apparaître. Autrement dit, j’ai fermé le dernier tome avec autant de questions que j’en avais au début. Et je trouve ça un peu dommage. Je crois que j’aurais préféré avoir les questions du début remplacées par d’autres, peut-être différentes. Là, j’ai l’impression d’avoir vu des tonnes d’illustrations reliées par une thématique commune, plutôt que d’avoir lu un récit avec une progression narrative.

Ca n’était donc pas inintéressant. En revanche, ça n’était pas du tout touchant. Et ça en fait une oeuvre moins intéressante à mon goût.

Saga

Dans ma série binge reading, après Monstress, un collègue m’avait fortement recommandé Saga.

Il s’agit d’un comics (parce que ce collègue lit beaucoup de comics), qui paraît depuis un moment. Et je dois dire que c’est très bien, à un défaut près.

C’est très bien, d’abord parce que c’est très joliment dessiné, ce qui aide évidement toujours. J’ai l’impression nette qu’il s’agit d’un dessin informatique, mais c’est un moyen, et donc un style, que choisit d’utiliser l’auteur. Dans le même ordre d’idée, les décors sont souvent assez vides, ce qui peut gêner. Mais dans l’ensemble, je trouve que ça souligne bien la personnalité des personnages qui méritent vraiment d’être détaillés.

En parlant de personnages, il faut s’intéresser un peu à l’histoire. C’est l’histoire d’une famille réunissant deux parents venus de camps opposés dans une guerre interstellaire. Les deux camps veulent la mort des parents et, surtout, de leur fille. Il y a donc des tueurs à gage venus des deux camps, des parents, des vaisseaux spatiaux (au look vraiment étonnant), des extra-terrestres (dont un mignonissime bébé phoque gardien de morses/vaches). Et bien sûr, en quelques années d’écriture, cette famille évolue.

Et c’est sans doute le plus gros défaut de cette oeuvre. Parce que la famille évolue en suivant les clichés classiques de la famille américaine : la drogue, le déclassement, le difficile statut de vétéran de guerre (dans une guerre offshorée), la douleur qu’il y a à perdre ceux qu’on aime (et parfois ceux qu’on n’aime pas). Je ne dis pas que c’est mal traité, parce que c’est souvent au contraire très bien pensé. En revanche, les thèmes abordés manquent selon moi d’originalité. Mais ça n’est pas bien grave, je lirai la suite quand même.

agile-architecture-documentation-system 0.1.0

C’est un peu comme supercalifragilisticexpialidocious, c’est vrai que ce nom trop long est parfaitement atroce.

Néanmoins, le projet derrière ce nom commence à fonctionner « assez bien » (d’où le passage à une version 0.1.0).

Il faut dire que, depuis le mois de mars, grâce à mon employeur, je fais travailler un stagiaire sur toutes les idées que j’ai depuis quelques années.

Résultat ? Si vous souhaitez documenter d’une façon assez confortable un projet en utilisant les idées que j’ai décrit il y a quelques temps sur la page Architecturer agilement avec C4/Structurizr, et que vous préférez pouvoir versionner l’architecture comme un artefact de votre produit, vous disposez maintenant d’un plugin maven et d’un archétype qui devraient grandement vous faciliter la vie.

Evidement, il y a encore quelques bugs gênants, au premier lieu desquels le manque de support de Java 17. Mais ça va bientôt changer, et vous aurez alors un outil assez efficace, quoique parfois un peu délicat à utiliser.

Le diagram as code, c’est pas si simple

La semaine dernière, j’ai entamé une présentation sur un sujet pas tout à fait pour débutants : Accelerate. Le sujet est intéressant, mais nécessite à un moment de reprendre le schéma illustrant les capacités des équipes de développement.

Les capacités Accelerate, telles qu’illustrées dans le livre éponyme

Et dans ma présentation, je veux pouvoir manipuler ce schéma (mettre des couleurs, du gras, des trucs comme ça). J’ai bien essayé de créer le diagramme avec PlantUML – parce que j’aime ça. Mais je n’ai jamais obtenu de rendu propre. Au bout d’un moment, j’ai même hésité à franchir le rubicon, c’est-à-dire faire ma présentation dans ces outils de consommation de productivité que peuvent être PowerPoint ou Google Slides.

Et puis au dernier moment je me suis souvenu que j’affichais mes diagrammes grâce à l’incroyable Kroki, qui supporte bien plus que PlantUML. J’ai donc cherché dans les différents formats supportés celui qui me donnerait la liberté que je cherchais … Et en moins d’une heure, je commençai un diagramme pikchr. Vous allez évidement me demander la différence avec PlantUML, et elle est assez évidente. Dans PlantUML, vous faites du diagramme déclaratif : vous déclarez la liste des objets (blocs et connecteurs) et vous laissez au moteur de rendu l’intégralité des décisions de rendu. Dans pikchr, vous dessinez beaucoup plus : vous commencez par poser les blocs avec une syntaxe qui ressemble pas mal au logo (pose un bloc, va vers la gauche, avance d’une case), et vous les reliez ensuite par des connecteurs dont vous pouvez configurer le comportement à l’envie. C’est évidement bien plus fin, et donc bien plus complexe à écrire correctement.

J’ai donc installé l’extension VSCode qui va bien (enfin, pas tant que ça, puisqu’elle échoue la moitié du temps à m’afficher le diagramme sans jamais montrer d’erreur), et j’ai commencé à éditer mon schéma.

Et à un moment, je me suis rendu compte qu’il n’apparaissait pas dans ma présentation asciidoctor-revealjs. Evidement, c’était parce que j’utilisais une version dépassée d’asciidoctor-kroki.

Et là, bienvenue dans le terrier du lapin façon Lewis Carroll

En mettant à jour l’extension, mon build s’est mis à échouer avec un message d’erreur cryptique :

[INFO] --- gem-maven-plugin:2.0.1:initialize (install-gems) @ conferences ---
[WARNING] ERROR:  While executing gem ... (ArgumentError)
    " html, b" is not an octal string

Bon, je vais vous renvoyer directement vers le ticket GitHub et la question Stackoverflow, mais dans l’idée, le proxy façon maven pour les gems ruby n’existe plus (parce que l’équipe JRuby ne paye plus la facture), et il faut changer de mode de téléchargement de ces gems en utilisant le plugin mavengem-wagon qui agit comme un protocole supplémentaire.

Résultat ? Trois jours d’investigations assez tordues, pour une mise à jour de plugin qui fait que heureusement, je peux enfin utiliser correctement des schémas pikchr dans mes présentations ! (merci Kroki !)

Monstress

Après Sex Criminals et Berserk, j’ai entamé une oeuvre à la couverture un peu mystérieuse.

Le comics est assez long et, honnêtement, j’ai beaucoup plus l’impression de lire un manga qu’autre chose. Mais de quoi ça parle ?

Monstress nous raconte l’histoire de Maika Demi-Loup, prise dans une guerre entre humains (et sorcières) et mutants issus d’anciens qu’on pourrait dire anthropomorphique (on trouve parmi ces anciens une louve, un renard, une femme aux bois de cerfs, des oiseaux). Et dans cette guerre, Maika va découvrir qu’elle porte en elle un dieu monstrueux issu d’une ancienne ère, que sa mère lui aurait attaché (les lecteurs me diront tous que chacune de ces phrases une simplification absolument outrancière de la complexité de cette oeuvre, et je serai bien d’accord, c’est toujours beaucoup plus compliqué que ça). En chemin, elle va s’entourer de quelques personnages pour ne pas mener de quête pour sauver le monde, ne pas non plus conduire l’un des camps à la bataille, ne pas non plus changer le monde. Mais ça, ça n’est même pas l’aspect le plus spectaculaire de cette histoire.

L’aspect le plus spectaculaire, c’est qu’à part deux exceptions notables, tous les personnages sont féminins. Ca n’a l’air de rien, mais dans un récit de guerre comme celui-là, voir des personnages féminins prendre les rôles de généraux méprisant la vie de leurs troupes, de scientifiques fous prêts à sacrifier des enfants, est un retournement des plus salutaires. Et pour le coup, ça ne change strictement rien aux enjeux du récit.

C’est tellement spectaculaire que ça cache peut-être les grandes qualités d’un récit qui est joliment dessiné (avec un usage intelligent des flous), dont le scénario est bien pensé pour toujours nous montrer Maika comme un monstre, à la fois à cause de sa cohabitation forcée, mais aussi à cause de son comportement de pur prédateur. Parce que dans cette galerie de femmes dangereuses, elle n’est pas la dernière à tuer des gens simplement parce qu’ils sont sur sa route. En fait, ça en fait peut-être l’un des personnages les plus mortellement dangereux que j’ai vu. Encore plus, sans doute, qu’Elric lui-même.

Autrement dit, lisez cette oeuvre, qui par ailleurs collectionne les prix Eisner. Au passage, l’oeuvre a reçu le prix « pour adolescents ». Mais franchement, à moins que je ne fasse preuve d’une sensiblerie coupable, je ne comprends pas trop cette séparation adolescent/adulte.

Echec … ou pas

Ces derniers temps, pour tout un tas de raison (dont une santé qui ne fait pas rêver), j’ai essayé de limiter ma participation à Codingame, et en particulier aux challenges de programmation. En effet, ceux-ci imposent un rythme de codage qui ne me permet pas d’être bon, ce qui est un peu frustrant. Et pire encore, ça m’enferme dans un comportement de codeur passionné, qui ne laisse que peu de place à la vie de famille. Donc je participe beaucoup moins.

Néanmoins, depuis quelques mois, un collègue me tanne avec un problème particulier, qui n’est pas un contest, mais un simple puzzle. Enfin, un simple puzzle … On parle quand même du jeu des rois. En l’occurence, des parties d’échec avec début de partie aléatoire en deux manches gagnantes. J’avais trouvé toute une série d’excuses de qualité : préparer et participer au Snowcamp, faire avancer mon projet open-source de documentation d’architecture, …

Mais mon collègue est opiniâtre, et plutôt bien classé …

Au bout d’un moment, j’ai donc craqué et lancé un projet, évidement en Rust, pour tenter d’implémenter un bot de qualité qui joue aux échecs. Et, comme d’habitude, j’ai d’abord cherché une source d’information de qualité. J’ai eu la chance de tomber sur une très belle série d’articles, un peu datés, mais très bien conçus : Chess Programming, écrits par François Dominic Laramée. J’ai donc méthodiquement implémenté

  1. Une base de données des mouvements possibles pour chaque pièce sur chaque case de l’échiquier
  2. Le code me permettant de trouver les mouvements réalisables sur un échiquier occupé là aussi pour chaque pièce sur la case qu’elle occupe actuellement.
  3. Et là j’ai commencé à caler …

Je vous explique …

Ou plutôt, je laisse François-Dominic commencer l’explication du MinMax et de l’AphaBeta. Pour résumer, le but de la partie est de permettre à mon bot de capturer le roi (oui, on ne le fait pas, c’est vulgaire) sans lui laisser la possibilité d’y échapper. Comme ça n’est pas immédiatement possible, on considère qu’un bon « proxy » de ce score est d’avoir plus de valeur sur l’échiquier que l’adversaire. Seulement, ça, c’est un peu biaisé, et en plus en début de partie, il faut un autre proxy. On peut par exemple imaginer essayer de gagner les cases près du centre.

Bon, évidement, il y a un bon paquet de positions à évaluer à chaque tour, qui fait qu’un bot ne peut pas faire d’évaluation de tous les coups … Mais ça, c’est assez classique dans les jeux codingame. En revanche, ce dont je n’ai pas l’habitude, c’est de l’évaluation MinMax, qui à mon sens implique qu’une évaluation inclue mon tour de jeu et celui de l’adversaire.

Tout ça, c’est somme toute assez classique …

Donc dans ces cas-là, la méthode « simple » est de sélectionner et scorer les différents coups possibles, et de prendre le meilleur. Et j’en suis là.

Sauf que, comme tout développeur « moderne », j’ai créé des tonnes de structures sophistiquées : des Point, des RealMove, des Turn. Et je passe pas mal de temps à faire des .clone(), ce qui ne me satisfait pas (en Java, je ne les verrai pas, parce que Java est bien plus laxiste sur la gestion de la mémoire).

Et, pire encore, j’ai compris un truc : entre deux tours de jeu, il n’y a que tr_s peu de différence : deux pièces ont bougé. Autrement dit, prédire le futur en recalculant à chaque tour les mouvements possibles de toutes les pièces est sacrément efficace. En fait, en l’écrivant, je me rends compte qu’il me faudrait une structure « à la git ». C’est-à-dire un arbre des positions possibles qui me permette, quand je passe d’un tour au suivant, de bénéficier directement des calculs effectués au tour précédent.

Autrement dit … Autrement dit, j’arrive au moment, classique quand je me lance dans un challenge codingame, où je supprime mon code pour le réécrire de zéro (ou à peu près).

J’ai une chance : les règles des échecs sont peut-être complexe (et par rapport aux autres jeux codingame, elles le sont incroyablement), mais au moins elles ne changent pas d’un niveau au suivant. Donc on repart de zéro avec des coups possibles stockés dans des champs de bits (ça fera plaisir à Nicolas), une arborescence de coups qui s’écrase quand on passe au tour suivant, et peut-être une vision plus claire des heuristiques. Souhaitez-moi bonne chance !

Synchroniser les GitHub Actions de plusieurs projets … avec Maven

Avant que vous paniquiez, je vais vous expliquer.

Je travaille actuellement dans une organisation qui dispose d’un compte GitHub entreprise, et donc de repositories privés. Dans ce cas, la réutilisation d’action est un peu moins simple et, dans tous les cas, nécessite la copie d’un fichier. Que ce fichier soit simple ou complexe n’est en quelque sorte pas si intéressant.

Comme cette organisation vient de mettre en place un Nexus, je me suis dit – après un moment d’hésitation – qu’il pourrait être intelligent de définir un pom d’entreprise (généralement je ne suis pas fan de l’idée, mais là, il y a tant à faire qu’un peut de standardisation ne fera pas de mal) et de lui associer une action qui serait le standard d’entreprise. Et par conséquent le fichier build.yml serait aussi le standard d’entreprise.

Donc, avant tout, il faut être en mesure de livrer les différents workflows GitHub Actions. C’est un usage assez classique de maven-assembly-plugin. Mais, comme mon pom sera utilisé comme pom parent, je préfère créer cet assembly dans un profil finement configuré.

		<profile>
			<id>Attach GitHub workflow file to project for other projects to use</id>
			<activation>
				<file>
					<exists>.github/workflows</exists>
				</file>
			</activation>
			<build>
				<plugins>
					<plugin>
						<artifactId>maven-assembly-plugin</artifactId>
						<executions>
							<execution>
								<id>Include github scripts as artifacts</id>
								<inherited>false</inherited>
								<phase>package</phase>
								<goals>
									<goal>single</goal>
								</goals>
								<configuration>
									<descriptors>
										<descriptor>src/assembly/github.xml</descriptor>
									</descriptors>
								</configuration>
							</execution>
						</executions>
					</plugin>
				</plugins>
			</build>
		</profile>

Avec évidement un fichier assembly assez simple

<assembly
	xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
	<id>github</id>
	<formats>
		<format>zip</format>
	</formats>
	<includeBaseDirectory>false</includeBaseDirectory>
	<fileSets>
		<fileSet>
			<directory>.github/workflows</directory>
			<includes>
				<include>*.yml</include>
			</includes>
		</fileSet>
	</fileSets>
</assembly>

Evidement, dans les pom enfants, il faudra récupérer cette dépendance, ce qui sera facile grâce à cet autre profil

		<profile>
			<!-- If no build workflow file exists, copy the one from java-parent project of the version used in this project -->
			<id>Ensure GitHub Actions exists in this project</id>
			<activation>
				<file>
					<missing>.github/workflows/build.yml</missing>
				</file>
			</activation>
			<build>
				<plugins>
					<plugin>
						<groupId>org.apache.maven.plugins</groupId>
						<artifactId>maven-dependency-plugin</artifactId>
						<executions>
							<execution>
								<id>Copy parent build.yml file as our own build.yml</id>
								<phase>generate-resources</phase>
								<goals>
									<goal>unpack</goal>
								</goals>
								<configuration>
									<artifactItems>
										<artifactItem>
											<groupId>my.org</groupId>
											<artifactId>parent</artifactId>
											<version>${version.parent}</version>
											<type>zip</type>
											<classifier>github</classifier>
											<overWrite>false</overWrite>
											<outputDirectory>${project.basedir}</outputDirectory>
										</artifactItem>
									</artifactItems>
								</configuration>
							</execution>
						</executions>
					</plugin>
				</plugins>
			</build>
		</profile>

Et là, il y a une feinte : on veut le fichier de build correspondant à la version du parent (sinon ça risque d’être le bazar). Mais cette version risque de changer avec le temps, non ? On ne peut donc pas mettre une version fixe, mais une variable. Mais comment faire coller cette variable avec la version du parent sans effort ? On ne peut pas utiliser ${project.version}, pas plus que ${project.parentversion} (qui semble à peu près exister, mais pas vraiment). Eh bien, dans ce cas, comme souvent, un peu de groovy va aider :

			<plugin>
				<groupId>org.codehaus.gmaven</groupId>
				<artifactId>groovy-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>Obtain parent version</id>
						<!-- I seriously tried to put that code fragment in an external script, but it unfortunatly never worked -->
						<phase>validate</phase>
						<goals>
							<goal>execute</goal>
						</goals>
						<configuration>
							<source><![CDATA[
def findRecursively(project) {
	if(project.artifactId.equals("parent") && project.groupId.equals("my.org")) {
		return project.version
	} else {
		return findRecursively(project.parent)
	}
}
project.properties["version.parent"] = findRecursively(project)
log.info "Setting java-parent version to "+project.properties["version.parent"]
							]]></source>
						</configuration>
					</execution>
				</executions>
			</plugin>

Et avec ces trois éléments (grâce aussi à la flexibilité approximative des profils), il est possible de synchroniser « facilement » les workflows GitHub en utilisant Maven (et Nexus, évidement).