Jouer pour mieux travailler : Le Quarto
Pour mes premiers pas à Marmelab, mon projet d'intégration se résume en une phrase :
Réaliser un programme en Python permettant de jouer au jeu du Quarto dans un terminal.
Voici donc le récit de cette expérience.
Un projet simple pour un jeu subtil
Le Quarto est un jeu en apparence tout simple :
- Un plateau de 4 cases sur 4
- 16 pions, tous différents, qui possèdent 4 caractéristiques permettant de les identifier (Carrés ou Ronds | Grands ou Petits | Creux ou Lisses | Blancs ou Noirs)
- Et l'objectif est trivial : Réussir à aligner 4 pions possédant une caractéristique en commun.
Il rappelle légèrement le jeu très connu du Puissance 4.
La particularité qui fait tout son charme, c'est qu'on ne choisit pas les pions qu'on place : c'est l'adversaire qui choisit votre pion pour vous. La seule liberté qu'il vous reste est de définir où vous souhaitez le placer sur la grille.
Ce jeu, d'une conception toute récente (inventé par Blaise Muller en 1985), n'a rien à envier à ses ainés à grands plateaux que sont les Dames, l'Othello, etc. Toute la subtilité d'une partie consiste à essayer d'amener l'adversaire à choisir à votre place le pion qui vous conviendra.
Mais il n'est pas encore question ici de chercher à coder un Deep blue capable de battre un humain à ce jeu. Il ne s'agit que d'un premier projet d'intégration, contentons-nous dans un premier temps de réaliser une interface simple à 2 joueurs.
L'environnement technique : Rendez-vous en terre inconnue, mais pas seul au monde
Quant à l'aspect technique du projet, il se résume à deux contraintes : utiliser le langage Python, et s'afficher dans la console.
Ici, le constat est simple : je ne sais rien et j'ai tout à apprendre. C'est un exercice d'apprentissage accéléré, où il faut lire de la documentation, comprendre les principes, expérimenter, mettre en oeuvre et comprendre les bonnes pratiques en quelques heures. Pendant cette semaine, j'ai donc du aborder:
- Apprentissage de Git et GitHub comme contrôle de code source.
- Mise en place de Docker pour encapsuler le projet dans un conteneur indépendant du contexte machine.
- Utilisation de Makefile pour simplifier les commandes.
- Présence de Travis pour automatiser le lancement des tests.
- Découverte du langage Python.
- Utilisation d'un linter pour garantir la syntaxe du code (avec pycodestyle).
Tous ces outils, qui étaient nouveaux pour moi, font partie du quotidien à Marmelab. Et Marmelab a ceci de chaleureux, que quelque-soit la problématique rencontrée, il y a toujours une personne prête à nous guider dans la bonne voie.
Cette première semaine a été une des plus riches de toute ma vie !
L'agilité : Quand on y a gouté, on ne peut plus s'en passer
Au-delà de l'apprentissage technique, il y a la méthodologie. A marmelab, une règle d'or : l'agilité. Et plus précisément la méthode Scrum.
Le projet a été entièrement encadré par cette méthode, avec tous les avantages que cela implique. C'est une première pour moi. Le principe m'est connu, particulièrement apprécié, mais je ne l'ai jamais mis en pratique jusqu'ici.
Le sprint doit durer une semaine et va suivre toutes les étapes suivantes.
Définition
Initialement, le sprint a été découpé en unités simples (user story) facilement compréhensibles. Chaque user story exprime un besoin élémentaire de l'utilisateur final. On utilise Trello pour partager et suivre l'avancement des projets. Chaque user story y est une carte qui peut y être définie et manipulée.
Les 14 cartes étaient placées à gauche au départ, et ont progressivement migré vers la droite avec l'avancement du sprint.
Estimation
On a évalué le temps nécessaire (en points) à la réalisation de chaque user story. On profite de cette étape pour détailler le travail à faire sur chaque carte (les tâches), et pointer les risques envisagés. Il s'agit donc également d'un atelier de conception.
On essaie toujours d'indiquer visuellement le résultat attendu pour rendre la carte le plus limpide possible.
Pour ces deux étapes, le Scrum master (qui garantit et encadre la tenue du sprint) et le product owner (qui fournit l'expression des besoins) et moi-même (le développeur) sont présents.
Réalisation
Progressivement j'ai réalisé les développements répondants aux besoins exprimés par les user stories. En les glissant progressivement de gauche à droite sur Trello, et en indiquant les points consommés au fur et à mesure.
Pour chaque élément, j'ai pu réaliser un jeu de tests unitaires garantissant que la fonction remplit toujours le besoin. Lorsque le code est envoyé sous git, les tests sont automatiquement joués (via Travis) et le code est contrôlé en continu. Cette intégration continue fournit une sécurité et un gain de temps formidable. On sait que les tests seront joués, et qu'un souci sera de fait, détecté automatiquement.
Code review
Avec GitHub, tout est recontrôlé. Chaque portion de code est soumise aux autres développeurs dans une Pull Request (PR). Normalement, les développeurs marmelab travaillent en binôme, et une seule personne s'occupe de la revue d'une pull request. Mais pour les nouveaux arrivants comme moi, chaque personne peut exprimer son avis, pointer les éventuelles erreurs, et proposer des améliorations.
Grace à cette méthode, la qualité du code est ainsi grandement améliorée. Non seulement les petits bugs ne passent pas, mais on converge rapidement vers les bonnes pratiques.
Je développe pour Marmelab, et tout l'équipe de Marmelab me soutient et me guide.
Daily
Chaque matin, un point est réalisé entre le développeur (moi-même), mon tuteur, et le Scrum master, afin de résumer en quelques minutes les tâches réalisées, à réaliser, et les décisions à prendre éventuellement.
Et agilité oblige : ces étapes se répètent en cycle adaptable quotidiennement et en fonction du contexte. On a ainsi rajouté quelques user stories en cours de route, et réorganisé leur ordre de traitement.
Rétrospective
A la fin du sprint, j'ai pu présenter mon travail à l'ensemble de l'équipe lors d'une démo d'une heure. On a fait le bilan non seulement de l'achèvement du projet, mais aussi des choses apprises, des difficultés rencontrées lors du projet, des points à améliorer.
Les points forts
Comme je l'ai écrit plus haut, j'ai beaucoup appris pendant ces 5 jours. J'ai notamment découvert de nouveaux outils formidables pour mon métier de développeur.
Coder en python : Encore une nouveauté
Historiquement, je développais en C# avec un framework ASP.NET MVC. Le langage Python est donc une grosse nouveauté.
Ici, on peut totalement oublier la notion de type, et presque aussi la notion d'objet.
while not game_state.check_draw():
ui.display_game(game_state, players)
if call_api(game_state) == False:
game_state.message += "Error, server didn't respond : Game end"
break
game_state.switch_player()
if game_state.check_winner(players):
break
La syntaxe surprend un peu, mais c'est parfaitement utilisable. Le langage est très souple. Et il permet sans aucun souci la réalisation d'applications complexes, et structurées.
J'ai pu appliquer une approche type MVC en définissant :
- un module définissant le plateau et les actions de jeu (Le modèle)
- un module chargé du rendu graphique de la partie (La vue)
- un module manipulant l'état actuel du jeu, et des joueurs (Le contrôleur)
Structuration de données : La simplicité des pièces de jeu
Un jeu de Quarto contient 16 pièces. Chacune possède 4 caractéristiques pouvant valoir 1 ou 0. (Exemple : Carré = 1 Grand = 0 Blanc = 1 Creux = 0)
La première idée qui vient pour représenter une pièce serait d'utiliser une structure à 4 paramètres du type :
Piece {
carre = True
grand = False
blanc = True
creux = False
}
Et pour valider une victoire il restera à tester les 4 pièces de la ligne en comparant leurs caractéristiques communes :
(piece1.carre == piece2.carre and piece1.carre == piece3.carre and piece1.carre == piece4.carre) or
(piece1.grand == piece2.grand && piece1.grand == piece3.grand && piece1.grand == piece4.grand) or
(piece1.blanc == piece2.blanc && piece1.blanc == piece3.blanc && piece1.blanc == piece4.blanc) or
(piece1.creux == piece2.creux && piece1.creux == piece3.creux && piece1.creux == piece4.creux)
Mais c'est une solution beaucoup plus ingénieuse et rapide qui a été choisie.
Les 16 pièces peuvent être vues tout simplement comme des nombres allant de 0 à 15. Et en considérant la valeur binaire de ces nombres, on obtient, pour chaque pièce, une série de 4 bits pouvant chacun représenter une caractéristique :
piece1 = 0 = #b0000
piece2 = 1 = #b0001
...
piece7 = 6 = #b0110
...
piece16= 15 = #b1111
Le test pour les pièces victorieuses devient alors très rapide en utilisant l'opérateur binaire ET logique. Si la somme des bits de chaque colonne ne vaut pas zéro, alors c'est qu'il n'y a que des 1 à cette position
piece1 & piece2 & piece3 & piece4 != 0
Il faut juste penser à tester également les inversions des bits pour vérifier les caractéristiques à 0:
(piece1 ^ 15) & (piece2 ^ 15) & (piece3 ^ 15) & (piece4 ^ 15) != 0
Réaliser un jeu : Savoir donner envie (ou essayer)
Une autre problématique pour implémenter un Quarto en console, c'est la représentation des pièces et leur manipulation.
Le programme peut être parfaitement fonctionnel techniquement, si la grille de jeu n'est pas facilement lisible pour les joueurs, ils ne s'amuseront pas, s'abimeront les yeux et le cerveau, vont fermer le programme, et jouer à autre chose. Et ils garderont un mauvais souvenir du logiciel, et même du jeu en général.
Il a fallu représenter des pions possédant 4 caractéristiques distinctes en seulement quelques caractères affichables. Le visuel doit non seulement permettre de distinguer toutes les caractéristiques, mais aussi, il doit les présenter de façon agréable à l'utilisateur.
Il est important que la réflexion du joueur soit aussi facile sur l'écran que sur le plateau de jeu. Les points communs et les différences entre les pièces doivent lui sauter aux yeux le plus naturellement possible.
En fait, il faudrait même que la lecture des pièces soit encore plus facile sur l'écran que sur le plateau. Car dans le monde physique, le joueur va manipuler les pièces, les toucher, les observer sous tous les angles, et s'en imprégner fortement. Dans le monde virtuel, le joueur devra se contenter d'une apparence restreinte et sous un seul angle.
Forcément, dans une console, l'affichage est extrêmement limité, raison de plus pour ne pas le négliger.
J'ai utilisé des formes simples, des couleurs nettes, et cherché à me rapprocher le plus des caractéristiques originales des pièces. La hauteur ne peut être représentée en 2 dimensions sans donner une impression de désordre visuel, j'ai utilisé une couleur de police à la place.
La grille est lisible facilement. L'objectif a été plutôt atteint dans le temps court qui était disponible.
L'étape suivante d'amélioration graphique se fera dans une interface plus souple, lors d'un futur sprint.
La seconde difficulté, c'est de permettre à l'utilisateur de manipuler facilement les pièces. Le système choisi initialement est très simple :
- Chaque pièce est identifiée par un numéro (visible à l'écran).
- Chaque case dans la grille de jeu est identifiée par des coordonnées A, B, C, D en abscisse et 1, 2, 3, 4 en ordonnées (visibles également à l'écran).
- Pour jouer, chaque utilisateur est invité à saisir au clavier les coordonnées et numéros de pièces désirées.
Ce système a l'avantage d'être très simple à comprendre, et facile à implémenter dans une console. Malheureusement, cette manipulation est laborieuse pour les joueurs. Elle met en œuvre des notions scolaires et peu ludiques de saisie de texte et de lecture de coordonnées.
C'est ici qu'il restera à ma réalisation la plus grande marge d'amélioration. Un système beaucoup plus fluide de sélection et placement des pièces en utilisant les 4 flèches directionnelles serait bien meilleur.
Cette feature avait été envisagée en cours de sprint mais n'a pas pu être mise en œuvre lors des 4 jours et demi prévus au projet. On essayera donc de faire mieux la prochaine fois en utilisant les leçons apprises ici.
Une expérience enrichissante et motivante
Pour ce premier projet, la partie la plus laborieuse aura été la prise en main de l'environnement de développement. Savoir utiliser Docker, Git, tous ces outils pourtant courants pour beaucoup, mais dont je ne connaissais encore que le nom avant mon arrivée.
Au final, le bilan est très positif pour moi : J'ai réappris à travailler correctement, avec méthode et organisation.
Grace à la pratique de l'agilité dans toutes les approches du développement, la cadre est maîtrisé en permanence. Le travail est facilité, sécurisé. Il serait difficile pour moi de travailler de nouveau sans utiliser ces pratiques.
Le développement de tests systématiques oblige à structurer son code en fonctions et modules les plus simples possibles et le moins dépendants possibles. Cela donne un code plus clair, et plus maintenable.
La revue de code permet au développeur de connaître la vision de la communauté, de proposer la sienne, et de maintenir une qualité de travail continue.
Pour conclure, n'hésitez pas à télécharger ce programme sur GitHub : quarto-python. Vous pouvez vous inspirer de ce projet, l'améliorer, ou simplement vous en servir pour découvrir le jeu du Quarto.
Si surtout, si vous ne travaillez pas encore en méthode agile, mettez vous-y ! ! !