Dans les niveaux les plus classiques, le héros du jeu est une boule noire appelé Blackball ou Marble qui est chargé de toucher dans le bon ordre des pierres dites oxydes dont les couleurs sont appariées. Lorsqu'une paire d'oxydes est ouverte (après avoir touché ses deux composantes l'une après l'autre), elle le reste; et lorsque toutes les paires d'oxydes du niveau sont ouvertes, la partie est finie.
Dans les niveaux de méditation, il y a plusieurs billes blanches (en général) à caser chacune dans un trou. Dès que chaque bille est en place, le niveau est terminé.
Dans certains niveaux, il y a deux boules, l'une noire, l'autre blanche. La souris ne commande que l'une des deux, mais un outil appelé yin-yang permet de commuter entre les deux. Issus de vrais jeux à deux joueurs dans Oxyd (avec un câble MIDI branché entre deux ordinateurs Atari), ce genre de jeu présente l'originalité qu'il n'y a pas de compétition entre les joueurs, mais qu'au contraire chacun a besoin de l'autre pour réussir.
Dans les années 1990, un jeu appelé Oxyd(en), initialement diffusé pour Atari était porté sur IBM PC. Le jeu Oxyd était développé par Meinolf Schneider. Il comportait déjà les trois sortes de paysages qu'on trouve dans Enigma. Un fan de ce jeu, Daniel Heck, a créé le [2] une version libre d’Oxyd avec possibilité d'importer les niveaux d'Oxyd (appelés paysages), et basé sur le même principe atextuel (la règle du jeu est à deviner pour chaque paysage). Il a donc décidé de nommer Enigma cette version libre du jeu.
Daniel Heck a d'emblée placé Enigma sous licence libre GPL, ce qui a permis à de nombreux amateurs de contribuer à ce jeu, créant au fil des années une communauté de contributeurs qui est encore active aujourd'hui. Parmi ces développeurs, on notera la présence d'Alex Smith[5].
Développé sous Linux[6], le jeu est régulièrement porté sous Windows et Mac. Le format de fichiers permet d'ailleurs de créer un paysage avec un éditeur de texte sous n'importe quel OS. La licence GPL étant virale, les paysages créés sont automatiquement placés à leur tour sous licence GPL et sont dans les faits, libres.
Un paysage (niveau du jeu) est stocké dans un fichier xml, qui contient, outre des métadonnées (comme le numéro de version, nom de l'auteur, date, référence à la licence GPL, nom du paysage...), du code lua qui décrit le paysage, avec une base de données d'objets Enigma et des actions déclenchées par certains des objets (par exemple, l'action d'un interrupteur ou l'appui sur une dalle sensible appelée trigger).
Pour tester ce jeu, il suffit de copier le texte ci-dessus dans un fichier dont l'extension est xml (par exemple alain32_1.xml qui est son nom original), puis de placer le fichier dans le dossier auto des niveaux d'Enigma.
On y lit d'abord que c'est du xml, puis à la ligne 3, l'adresse internet où on peut chercher la description du format de fichier d'Enigma, puis l'arborescence des éléments. L'élément info indique que c'est un niveau (et non une bibliothèque par exemple); l'élément identity donne le nom du jeu, ainsi qu'un sous-titre et un identifiant; suivent alors le numéro de version du jeu, le fait qu'il est en statut test (c'est-à-dire qu'il ne fait pas partie des niveaux d'Enigma), le nom de l'auteur du niveau, la licence GNU GPL qui rappelle que le jeu est libre... L'élément score donne les records du monde du niveau en mode facile et en mode difficile. Enfin vient le code lua, lui-même dans un élément. Il est décrit ci-dessous. Les derniers éléments décrivent les éléments texte du niveau, avec des indications pour la traduction dans différentes langues.
Code lua
Un niveau d'Enigma est une base de données d'objets qui occupent chacun une position à coordonnées entières. Les objets sont de l'un des types suivants :
dalle de sol (permet de faire un damier en alternant deux couleurs); les dalles d'eau sont à éviter parce que Blackball s'y noie.
pierres (permettent de construire des murs de labyrinthes); certaines de ces pierres peuvent bouger lorsque Blackball les heurte.
objets posés par terre s'il n'y a pas de pierres; Blackball peut les ramasser en passant dessus, et les utiliser en cliquant dessus dans son inventaire
acteurs, dont Blackball lui-même.
Pour définir un jeu, on doit donc commencer par établir une sorte de dictionnaire représentant par un caractère chaque élément du jeu, puis en plaçant les caractères sur une carte du jeu (comme les niveaux de Sokoban), et enfin en écrivant les méthodes de chacun de ces objets en lua.
Définition des dalles
On peut convenir de représenter par des espaces les dalles ayant les propriétés du béton, en écrivant[9]
ti[" "]={"fl_concrete"}
(fl est une abréviation pour floor).
Puis de même, le sol de la chambre peut être représenté par des x (du gravier encadré):
ti["x"]={"fl_gravel_framed"}
Le niveau sera muni de 4 portes numérotées de 1 à 4, qui s'appelleront door1, door2, door3 et door4; elles auront leur battants au nord et au sud, et seront initialement fermées et par-dessus le sol en béton (la concaténation est notée par deux points en lua[10]):
Pour les murs de la chambre et le couloir fermé par les portes, on utilise des pierres ayant elles aussi l'aspect du béton, afin de donner un look « urbain » à ce jeu (st veut dire stone).
ti["#"]={"st_concrete"}
Pour que ce jeu soit jouable, il faut au moins deux pierres oxyd (celles que Blackball devra toucher pour gagner le jeu); elles seront représentées par le caractère o sur la carte:
ti["o"]={"st_oxyd"}
Une seule dalle sera représentée par une arobase, l'acteur Blackball lui-même (précédé par un dièse pour le centrer sur la dalle):
ti["@"]={"#ac_marble"}
Une dernière pierre est représentée par un i: C'est un interrupteur ('switch), paramétré pour qu'à son contact, il lance (callback) la fonction lua appelée "GimmeMoney()":
Ce jeu utilise des pièces de monnaie de valeurs respectives 10, 5 et 2 cents. Elles seront représentées respectivement par les lettres l, m et s (comme large, medium et small):
Enfin, la règle du jeu est dans un document que Blackball peut ramasser en roulant dessus, puis lire en cliquant dessus; sur la carte, ce document est représenté par la lettre d:
ti["d"]={"it_document",text="text1"}
Ainsi constitué, l'objet ti (comme tile) est un tableau associatif, dont les éléments sont des objets du jeu. Constituer le jeu, c'est puiser ces éléments et les placer dans une carte appelée wo (comme world) ci-dessous
Carte du niveau
La construction du jeu ressemble à un jeu de construction: On puise les éléments dans le tableau ti, avec une valeur par défaut pour le sol (le caractère espace) et en suivant les instructions qui figurent dans la carte (une chaîne de caractères elle aussi):
Une fois rendue, cette carte ressemble à ceci dans le jeu Enigma:
Pour finir l'initialisation du jeu, on affecte deux variables wealth (le montant à déposer dans la chambre, initialement trop grand pour que ce soit possible avant d'actionner l'interrupteur) et ndoors qui représente le numéro de la prochaine porte à ouvrir (c'est-à-dire le nombre de portes fermées):
ndoors=4wealth=150-- cannot have that
Algorithmes
Le principe du jeu est le suivant : Chaque fois que Blackball actionne l'interrupteur, on lui apporte un ordre de mission, comportant un montant à déposer dans la chambre, et si le montant correspond à celui qui est demandé, la prochaine action de l'interrupteur ouvrira la porte portant le numéro ndoors. La variable ndoors est alors décrémentée jusqu'à ce que toutes les portes soient ouvertes ce qui permet de gagner le jeu. C'est le rôle de la fonction GimmeMoney() appelée à chaque action de l'interrupteur:
Si ndoors est déjà égal à zéro, cette fonction ne fait rien puisque les portes étant ouvertes, la fonction GimmeMoney() est devenue inutile. Sinon on calcule le montant présent dans la chambre en initialisant une variable somme à zéro, puis en y additionnant 10 fois le nombre de pièces de 10, 5 fois le nombre de pièces de 5 et 2 fois le nombre de pièces de 2 présentes dans la pièce (c'est-à-dire, dont l'abscisse est comprise entre 2 et 8, et l'ordonnée entre 6 et 10 exclus). Par exemple, pour avoir le nombre de pièces de 10, on fait
(On place dans l'objet tens les objets dont le nom commence par large, no étant une abréviation pour named objects; on peut alors boucler sur les éléments de tens); on fait pareil avec les pièces de 5 et de 2, puis si les deux montants coïncident, on adresse à la pierre dont le nom est doors concaténé avec le numéro ndoors, un message (représenté par un double-point) lui demandant de s'ouvrir:
Enfin, on calcule un nouveau montant aléatoire (à placer ensuite dans la chambre) et on l'écrit sur un document suivi du mots cents, avant de placer ce document sur la dalle de coordonnées (18;9):
En fait, malgré l'absence de pièces d'un cent, le jeu n'est pas très difficile puisqu'on peut toujours trouver une manière d'arranger des pièces de 10, 5 et 2 avec l'algorithme glouton.
L'algorithme de Kruskal, qui est pourtant destiné à parcourir des arbres, est utilisé à l'envers par Enigma pour construire aléatoirement des labyrinthes[11].