GameShell, le retour

Posté par  . Édité par palm123, Benoît Sibaud et bobble bubble. Modéré par Benoît Sibaud. Licence CC By‑SA.
Étiquettes :
52
26
juin
2021
Ligne de commande

Il y a quelques mois, je postais une dépêche décrivant “GameShell”, un jeu que j’avais développé pour enseigner les bases de la ligne de commandes. Cette dépêche avait provoqué discussions, corrections de bugs et suggestions intéressantes.

Trois mois et quelques centaines de commits plus tard, je me permets de faire une petite mise à jour.

Globalement (mais je suis un peu biaisé), le GameShell d’aujourd’hui est nettement mieux que le GameShell d’hier. Ceci a un coût : la taille d’une archive GameShell a été multipliée par 3. On est passé de 44kio à 140kio !
Je ne sais pas comment on traduit “bloat” en français (“boursouflage” ?), mais pour le moment, ça ne m’empêche pas de dormir !

La version précédente avait été testée par plusieurs générations d’étudiants, parfois très inventifs. Alors n’hésitez pas à vous mettre dans la peau d’un étudiant en faisant une partie avant de me faire un retour.
Je suis preneur de toute critique, suggestion, rapport de bug, ticket, contribution et j’en passe.

Si certains veulent créer des missions, je pourrais faire une petite description de l’architecture d’une mission type. Ce n’est pas très compliqué, et une année, j’ai même eu un étudiant qui en a ajouté une comme « question bonus » !

Sommaire

Principe

L’idée derrière GameShell n’a pas changé : il s’agit d’effectuer des « missions » qui correspondent en fait à des opérations usuelles de gestion d’un ordinateur. Par exemple, « Cherchez le diamant dans le labyrinthe. » reviendra à chercher l’unique fichier contenant la chaine diamant dans une arborescence.

Toutes les opérations se font dans un terminal en utilisant le shell (bash en l’occurrence) et les commandes usuelles.

On lance une partie typique avec

$ ./gameshell.sh

  ____                      ____  _          _ _
 / ___| __ _ _ __ ___   ___/ ___|| |__   ___| | |
| |  _ / _` | '_ ` _ \ / _ \___ \| '_ \ / _ \ | |
| |_| | (_| | | | | | |  __/___) | | | |  __/ | |
 \____|\__,_|_| |_| |_|\___|____/|_| |_|\___|_|_|

                             _
                           _/ \
          _               /    \
         / \_   __       /\/\  /\
        /    \ /  \     /    \/  \
       /\/\  /\    `--./.'-    `-.\
      /    \/  ' ^ _    _  _
    /\ ____..      YY  Y     _   |~  _
   /._/  _ \_        Y  Y   [_]--'--[_]
  / / .'/#\_ `-.    Y  YY   |'|""`""|'|
    .-_/#@##\  `\"" ' Y     | | /^\ | |
   " "'"''"'"'''" '         |_|_|I|_|_|

[mission 1] $ 

et on se retrouve dans une session bash quasi normale.

Les seules opérations spécifiques sont celles relatives à la gestion des missions. Elles sont accessibles avec la commande spéciale gsh (anciennement gash, mais ce n’était pas approprié pour la version anglophone).

  • gsh goal pour afficher l’objectif de la mission courante (anciennement, show),
  • gsh check pour vérifier si la mission courante est finie,
  • gsh reset pour ré-initialiser la mission courante. (Pratique quand on a fait une bêtise…)

Il y a d’autres commandes (voir gsh HELP pour une liste complète), mais elles ne devraient pas servir au joueur en temps normal.

[mission 1] $ gsh goal

  ,------------------------------------------------------.
 (_\                                                      \
    |  Objectif                                            |
    |  ========                                            |
    |                                                      |
    |  Allez tout en haut du donjon.                       |
    |                                                      |
    |                                                      |
    |  Commandes utiles                                    |
    |  ================                                    |
    |                                                      |
    |  cd LIEU                                             |
    |    Se déplace vers le lieu donné.                    |
    |    Note : ``cd`` est une abréviation pour "change    |
    |    directory".                                       |
    |                                                      |
    |  ls                                                  |
    |    Liste les lieux accessibles depuis la position    |
    |    actuelle.                                         |
    |    Note : ``ls`` est une abréviation pour "liste".   |
    |                                                      |
    |  pwd                                                 |
    |    Affiche la position actuelle.                     |
    |    Note : ``pwd`` est une abréviation pour "print    |
    |    working directory".                               |
    |                                                      |
    |  gsh reset                                           |
    |    Ré-initialise la mission au début.                |
    |                                                      |
    |                                                      |
    |  Remarque                                            |
    |  --------                                            |
    |                                                      |
    |  Les termes apparaissant en MAJUSCULES dans les      |
    |  commandes sont des méta-variables : vous devez les  |
    |  remplacer par des valeurs (chaines de caractères)   |
    |  appropriées.                                        |
   _|                                                      |
  (_/________________________________________________(*)___/
                                                      \
                                                       ))
                                                       ^

[mission 1] $ ls
Chateau  Echoppe  Foret  Jardin  Montagne
[mission 1] $ cd Chateau
[mission 1] $ ls
Batiment_principal  Cave  Donjon  Grande_salle  Observatoire
[mission 1] $ cd Donjon
[mission 1] $ ls
Premier_etage
[mission 1] $ cd Premier_etage
[mission 1] $ ls
Deuxieme_etage
[mission 1] $ cd Deuxieme_etage
[mission 1] $ ls
Haut_du_donjon
[mission 1] $ cd Haut_du_donjon
[mission 1] $ ls
[mission 1] $ gsh check

Bravo, vous avez réussi la mission 1 !

[mission 2] $

Il y a actuellement 42 missions. Pour vous donner une idée, mes bons étudiants arrivent autour de la mission 35 en 2h30.

Lancement d’une partie

La distribution d’une archive GameShell (c’est-à-dire le code GameShell avec une liste de missions) a été simplifiée. Au lieu d’une archive usuelle au format .tgz (qu’il fallait donc désarchiver avant de pouvoir lancer une partie), j’utilise une « archive auto-extractante » : un fichier unique contenant un entête « script » et l’archive en binaire. L’entête extrait la partie « archive » dans un fichier temporaire, utilise tar -xf et lance le jeu. Lorsqu’on quitte, une archive est régénérée et intégrée au script, permettant de reprendre facilement la partie à la mission courante.

Une telle archive est générée automatiquement par github lors des commits sur la branche master:
https://github.com/phyver/GameShell/releases/download/latest/gameshell.sh
Le code de GameShell contient un script utils/archive.sh pour générer ses propres archives si l’on souhaite supprimer des missions, en changer l’ordre, etc.

Internationalisation

Un ticket ouvert sur github demandait si j’avais l’intention de traduire GameShell.

Ce n’était pas au programme, mais Rodolphe Lepigre (qui avait eu l’idée originale de GameShell) a fait une pull-request en disant : « regarde, c’est facile ».

Résultat, j’ai mis mes corrections de TP en suspens et me suis mis à bosser sur GameShell ! (Ne vous en faites pas, j’ai repris mes corrections par la suite…)

GameShell est donc maintenant officiellement disponible en anglais ou français. La langue dépend de votre locale, plus précisément de la variable LC_MESSAGES. Si c’est autre chose que en_.. ou fr_.., c’est l’anglais qui sera utilisé.

Sur les systèmes GNU, on peut changer la langue simplement en donnant l’option -L fr ou -L en au lancement de GameShell. (On peut même donner plusieurs langues par ordre de préférence, style -L it:fr:en, mais ça ne sert pour le moment à rien vu que les seules langues supportées sont fr et en et que tous les messages sont traduits.)

Pour les systèmes non GNU (comme macOS), il faudra spécifier une locale valide à la main :

$ LC_MESSAGES=fr_FR.utf8 ./gameshell.sh

(Vous pouvez utiliser la commande locale -a pour obtenir la liste des locales supportées par votre système.)

Les messages sont choisis par gettext et les traductions sont donc indépendantes du code de GameShell ou des missions. Pour ceux qui ne connaissent pas, au lieu de

  echo "Error: wrong password."

le code de GameShell contient

  echo "$(gettext "Error: wrong password.")"

La commande gettext va chercher le message correspondant à "Error: wrong password." dans la langue courante. Si aucune traduction n’est trouvée, gettext renverra son entrée et le message sera donc affiché en anglais.
De la même manière,

  mkdir Castle

est remplacé par

  mkdir "$(gettext "Castle")"

etc.

Outre les fichiers texte donnant les descriptions des missions (ou les messages d’aide), les traducteurs doivent gérer des fichiers du style

...

msgid   "Error: wrong password."
msgstr  "Erreur : mauvais mot de passe."

msgid   "Error: you are not allowed to run this command."
msgstr  "Erreur : vous n'avez pas le droit d'exécuter cette commande."

msgid   "Is this information correct? [Y/n]"
msgstr  "Est-ce que ces informations sont correctes ? [O/n]"

...

Aucune connaissance en programmation shell n’est donc nécessaire pour faire ces traductions.

Dépendances

Les versions initiales de GameShell avaient des dépendances surprenantes, notamment

  • Python3
  • gcc
  • x11-utils

gcc et x11-utils étaient en fait des dépendances sur des missions particulières, qu’on pouvait ne pas inclure dans une archive.

Les missions peuvent maintenant vérifier leurs dépendances. S’il manque quelque chose, la mission est simplement annulée.

La dépendance sur Python3 a été entièrement supprimée. Les scripts Python ont été, pour la plupart, ré-écrits en awk. Je ne dis pas que awk est mieux que Python, mais il a l’avantage d’être requis par la norme POSIX et il est installé par défaut sur les plateformes cibles de GameShell. (Linux, BSD, macOS)

Je ne connaissais pas beaucoup (à part l’occasionnel ... | awk '{print $4}'), mais c’est finalement un langage assez marrant.

Au final, la seule dépendance "forte" pour GameShell est bash (mais on pourra bientôt utiliser zsh à la place), et si on veut jouer dans une autre langue que celle de Shakespeare, gettext. Il faut aussi avoir un système POSIX avec les utilitaires standards (ls, cp, tail, grep, etc.)

POSIX

En interne, le code a été modifié pour favoriser les solutions POSIX. La raison est que cela simplifie la gestion des différentes plateformes cibles pour GameShell (Linux, BSD, macOS).

Dans un souci de simplification, la plupart des fonctions utilisées par GameShell sont maintenant externalisées dans des scripts indépendants. (cf dossier bin/)

Cela a été l’occasion d’apprendre pas mal de trucs et de voir les avantages (mais aussi les limites) de la norme POSIX.

Normalement, il n’y a plus beaucoup d’endroits où du code spécifique est nécessaire :

  • sauvegarde de l’environnement (obtenir la liste des variables d’environnement et des fonctions du shell de manière portable) : script bin/save_environment.sh,
  • gestion des processus (la commande ps utilise des options différentes sur les différentes plateformes, et même la partie standardisée n’est pas respectée) : missions du groupe processes,
  • des scripts de tests (auto.sh et test.sh) de missions qui insèrent des commandes dans l’historique à la main (bash sait faire ça).

PS

Pour ceux qui ont lu jusque-là et qui font une partie, les commandes « admin » (voir gsh HELP) ont besoin d’un mot de passe.
Par défaut, c’est « gsh » (comme la commande).
Ça peut servir en cas de bug qui ne permet plus de valider une mission. On peut utiliser gsh skip pour la sauter !

Aller plus loin

  • # Super initiative

    Posté par  (site web personnel, Mastodon) . Évalué à 3.

    Je connaissait pas c est super comme initiation à Linux, pour motiver un jeune 15 ans. Je vais l essayer.

    Sous licence Creative common. Lisez, copiez, modifiez faites en ce que vous voulez.

    • [^] # Re: Super initiative

      Posté par  . Évalué à 4.

      Super !
      N'hésite pas à faire un retour. Les utilisateurs complètement novices ne voient pas du tout les mêmes choses que les utilisateurs plus avancés.

      • [^] # Re: Super initiative

        Posté par  . Évalué à 7.

        Après ta première dépêche j'ai fait faire le jeu à mes gamins (12 et 13). Ils ont eu énormément de mal avec … la casse. Et en effet, dans les instructions de base de la première mission, c'est pas facile de comprendre pour un novice que cd LIEU doit respecter la casse.

        Entre parenthèse, j'ai utilisé ton jeu pour négocier leur temps d'écran. Très efficace.

        • [^] # Re: Super initiative

          Posté par  . Évalué à 3.

          J'ai jamais eu ce problème avec mes étudiants, mais ça mérite une remarque. Je viens d'ajouter une phrase dans le fichier goal de la première mission.

  • # tree

    Posté par  . Évalué à 4.

    Félicitations pour le logiciel. Je suis en train de préparer un pull request avec des corrections pour les erreurs de traduction ou des typo.
    Concernant la mission 20, il propose d'utiliser la commande « tree » qui est en effet très pratique. Sauf que je viens de voir que « tree » n'était pas installé par défaut sur mon système. Du coup, il faudrait peut-être le traiter comme une dépendance. À noter qu'on peut toujours utiliser "ls -R" comme indiqué.

    • [^] # Re: tree

      Posté par  . Évalué à 4.

      Merci, je regarde ta pull-request bientôt.

      Pour tree, je crois que j'ai déjà changé d'avis plusieurs fois. Je trouve effectivement que cette commande est bien pour visualiser l'arborescence et est vraiment utile pour les débutants (mes étudiants).
      D'un autre coté, la mission sert aussi à préparer les missions suivantes, et ça serait dommage de la sauter.

      Pour le moment, je mets tree dans la liste des paquets à installer (dans le README), mais ne considère pas cette commande comme une dépendance stricte. (C'est pour ça que j'ai ajouté ls -R dans le fichier goal.)

      Ton commentaire va peut-être me faire changer d'avis, encore une fois. :)

  • # Mission 28

    Posté par  . Évalué à 4. Dernière modification le 26 juin 2021 à 22:56.

    Je ne suis pas sûr d'être arrivé au bout de la mission 28 correctement. En fait pour réussir, j'ai killé un processus bash. Mais lorsque j'ai fait "gsh check", ça m'a affiché

    [mission 28] $ gsh check
    wc: /home/pamputt/gameshell/.tmp/spell.pids: Aucun fichier ou dossier de ce type
    bash: [:  : nombre entier attendu comme expression
    
    Bravo, vous avez réussi la mission 28 !
    

    Pas sûr que les deux premières lignes soient celle attendues.

    • [^] # Re: Mission 28

      Posté par  . Évalué à 3.

      Ah…
      Ces missions m'en font voir de toutes les couleurs.

      Je regarde ça.

  • # Mission 31

    Posté par  . Évalué à 4.

    Bonjour, voici ce que j'ai obtenu dans la mission 31

    [mission 31] $ gsh check
    79 * 9 = ?? 79*9
    Trop lent ! Il faut donner les réponses en moins de 10 secondes...
    
    Bravo, vous avez réussi la mission 31 !
    
    Pendant que vous attendez, un escargot passe...
    

    J'ai tapé "79*9" juste pour tester. Normalement ça ne fonctionne pas, mais là ça m'a dit que j'avais bon :S

    • [^] # Re: Mission 31

      Posté par  . Évalué à 3.

      Ça, c'est clairement un bug. Il faut normalement répondre à 100 multiplications !
      Je regarde ça cette après-midi.

  • # Suppression de Python

    Posté par  (site web personnel) . Évalué à 2.

    Merci d'avoir travaillé sur ça ! C'est le genre de dépendance qui me fait sortir les yeux des orbites.

    Je n'ai pas testé les nouveautés, mais lors de la précédente dépèche j'avais essayé le jeu et j'avais bien aimé, même si j'ai juste essayé vite fait.

    • [^] # Re: Suppression de Python

      Posté par  . Évalué à 5.

      Tout est une question de point de vue.
      J'utilise Python, et mes étudiants aussi. Cette dépendance ne me choquait donc pas. (Mais je suis content de m'en être débarrassé.)

      Par contre, une dépendance sur Ruby (au hasart) m'aurait choqué, et une dépendance sur nodejs m'aurait carrément convaincu d'aller voir ailleurs !

    • [^] # Re: Suppression de Python

      Posté par  (site web personnel, Mastodon) . Évalué à 2.

      Je fais partir des personnes ayant râlé contre les dépendances, et suis donc ravi que ce soit maintenant de vieux souvenirs.

      “It is seldom that liberty of any kind is lost all at once.” ― David Hume

      • [^] # Re: Suppression de Python

        Posté par  . Évalué à 3.

        Même si les dépendances ne me dérangeaient pas, je suis aussi content de les avoir supprimées.

        Et les supprimer m'a fait découvrir plein de trucs.

  • # Quelques remarques

    Posté par  (site web personnel) . Évalué à 3.

    Salute,

    Excellente initiative et jeu sympa, merci ^

    Quelques remarques :
    - Vous devez trouver ce sortilège et le tenter de le supprimer => et tenter de le supprimer
    - Désolé, la mission 28 a échoué => La tournure est bizarre, "Désolé, vous avez échoué"
    - Un petit bug

    reload
    bash: /home/user/Téléchargements/gameshell/World/gshrc: Aucun fichier ou dossier de ce type
    

    Tcho !

    • [^] # Re: Quelques remarques

      Posté par  . Évalué à 2. Dernière modification le 03 juillet 2021 à 13:07.

      Merci, c'est corrigé.

      Pour le message, tu as effectivement raison, mais je voulais éviter un truc "négatif" pour le joueur. Je vais chercher une autre formulation. :)

      • [^] # Re: Quelques remarques

        Posté par  . Évalué à 3.

        • échec de la mission
        • il faudra refaire cette mission
        • la mission 28 n'est pas validée
        • mission 28 à recommencer
      • [^] # Commentaire supprimé

        Posté par  . Évalué à 3.

        Ce commentaire a été supprimé par l’équipe de modération.

  • # Bravo !

    Posté par  . Évalué à 2.

    Et merci pour ce projet (et cet article qui m'a permis de le découvrir). Les missions sont intéressantes et motivantes pour les débutants. Cela donne à réfléchir pour créer des nouvelles missions :)

    J'ai fait avec plaisir les 42 missions :)

    • [^] # Re: Bravo !

      Posté par  . Évalué à 2.

      Content que tu ais aimé !
      Et n'hésite pas à créer de nouvelles missions. Tu verras, ce n'est pas très compliqué.

  • # Interface graphique nécessaire?

    Posté par  . Évalué à 2.

    Ma seule machine non-Windows est "headless" (contrôlée à distance sans interface graphique)

    Est-ce que GameShell peut être utilisé via uniquement un accès ssh?

    • [^] # Re: Interface graphique nécessaire?

      Posté par  . Évalué à 4.

      Sans problème. Il y a une seule mission qui nécessite X, et elle sera sautée si la variable DISPLAY n'est pas définie.

      Vérifie que tu as les dépendances des autres missions (gettext man-db psmisc nano tree et bsdmainutils), et

      $ wget https://github.com/phyver/GameShell/releases/download/latest/gameshell.sh
      $ bash gameshell.sh

      fonctionnera sans problème à distance.

  • # Nouvelle aventure

    Posté par  . Évalué à 3.

    Je réfléchis à une nouvelle aventure1 (le nom que je donne à un ensemble de missions), et me pose quelques questions :

    • est-ce qu'il y a une ou des directions d'apprentissage (par exemple apprendre tout Bash, aller vers les scripts shells, etc.) ?
    • les aventures doivent-elles s'enchaîner ou peut-on passer d'un maillon à l'autre selon ses envies ?
    • y a-t-il une liste des commandes apprises ? ne l'a trouvant pas je l'ai faite pour les missions basiques.

    Les commandes apprises dans la premières aventures (GameShell Basic) :

    1. cd LIEU, ls, pwd
    2. cd -, cd .., pwd
    3. cd, LIEU1/LIEU2/LIEU3
    4. mkdir REPERTOIRE
    5. rm FICHIER1 FICHIER2 … FICHIERn
    6. mv FICHIER1 FICHIER2 … FICHIERn REPERTOIRE
    7. ls -A, fichiers cachés, Tab, Tab-Tab
    8. motifs * et ?
    9. * et ? plus un point pour voir les cachés
    10. cp FICHIER REPERTOIRE
    11. cp FICHIER1 FICHIER2 … FICHIERn REPERTOIRE, cp *, cp ?
    12. ls -l, cat FICHIER

    1. une sorte de chasse au trésor pour apprendre à mes enfants comment résoudre leurs problèmes d'installation d'extensions et lanceurs Minecraft sans papa. 

    • [^] # Re: Nouvelle aventure

      Posté par  . Évalué à 3. Dernière modification le 17 juillet 2021 à 23:21.

      Il n'y a pas vraiment d'ordre pour les "aventures". L'idée est que basic doit venir en premier pour apprendre à se déplacer dans le monde de GameShell et de manipuler les fichiers.

      Pour la suite, rien n'est imposé, mais les missions d'une aventure doivent a priori être faites dans l'ordre et suivre une progression, alors que les aventures sont indépendantes entre elles.

      L'aventure finding_files_maze par exemple, est découpée en 2 morceaux dans l'archive "officielle" : une première partie où on utilise simplement find (missions 19-21), et une seconde où on combine find avec d'autres trucs (missions 38-39).

      J'ai l'impression qu'il ne manque pas grand chose dans l'aventure basic (commandes et concepts de base).
      Les trucs à faire sont soit des missions "singletons", à mettre dans "misc" (pour des trucs divers, pas forcément standards : par exemple, la commande seq ou factor, ou watch) ou "intermediate" (pour des trucs standards compatibles POSIX : par exemple des motifs avancés avec *.??[!gG], la commande tee).
      Les missions des ces 2 aventures sont essentiellement indépendantes entre elles.

      D'autres concepts méritent une aventure spécifique avec plusieurs missions : liens symboliques, expressions régulières, etc.

      Globalement, GameShell vise plutôt à enseigner l'utilisation interactive du shell. J'aimerais bien ajouter une ou deux missions pour montrer les boucles simples sur les fichiers, mais je n'ai pas l'intention d'aller beaucoup plus loin sur l'écriture de scripts.

      Et même s'il n'y en a pas pour le moment, rien interdit d'avoir des mission qui introduisent des trucs spécifiques à bash ou zsh (les 2 shells supportés).

  • # Lien erroné

    Posté par  . Évalué à 3.

    Lien erroné dans la première phrase «Il y a quelques mois, je postais une dépêche décrivant» il manque le signe deux points après https et il y a http en plus (on peut d'ailleurs supprimer toute la partie avant /news)

  • # gsh_gettext.sh Aucun fichier ou dossier de ce type

    Posté par  . Évalué à 1.

    J'ai une debian 10 buster
    apt install gettext-base man-db psmisc nano tree bsdmainutils x11-apps
    wget https://github.com/phyver/GameShell/releases/download/latest/gameshell.sh
    $ bash gameshell.sh

    bash: gsh_gettext.sh: Aucun fichier ou dossier de ce type
    bash: eval_gettext : commande introuvable
    bash: eval_gettext : commande introuvable
    check, goal, help, reset
    [mission ] $

    • [^] # Re: gsh_gettext.sh Aucun fichier ou dossier de ce type

      Posté par  . Évalué à 2.

      Je n'arrive pas à reproduire ce bug, même à partir d'une installation vraiment minimale.

      Ton bug donne l'impression que les chemins d'accès ne sont pas définis correctement.

      Est-ce que tu peux me donner les résultats des commandes suivantes (lancées depuis GameShell) :

      [mission ] $ echo $GSH_ROOT
      ???
      [mission ] $ echo $PATH
      ???

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.