Comics, un monde "à la Batman"...

Xavier Lacot <xavier@lacot.org>, Mastère IDL, ENST

Introduction

Ce document constitue la présentation du monde virtuel COMICS, programmé en Eiffel dans le cadre du projet SmallWorld. COMICS permet à l'utilisateur d'observer l'évolution du monde et de ses habitants, qui interagissent en fonction de leur rencontres et/ou de leur nature.

Sommaire

  1. L'idée de base
  2. Téléchargement, licence et compilation
  3. Géographie
    1. Cimetière
    2. Prison
  4. Créatures
    1. Créatures de Base
    2. Animaux
    3. Humains
    4. Policiers
    5. Superméchants
    6. Superhéros
  5. Objets
  6. Commandes
    1. Commandes de paramétrage du monde
    2. Commandes d'action
  7. Problèmes
  8. Remarques

L'idée de base

COMICS est un monde mettant en scène les personnages habituels des comics. Pour simplifier, le monde est constitué de méchants et de gentils, dont les actions correspondent globalement à celles que l'on trouve dans toute bande dessinée.

Le programme repose sur un système de jours. Au premier jour, c'est à dire au démarrage du programme, il est demandé à l'utilisateur de rentrer certaines données quantifiées caractérisant le monde à observer : superficie, population, objets disponibles. Chaque jour, les créatures peuvent effectuer un déplacement et une action, sauf si elles sont mortes ou qu'elles se trouvent en prison. Les notions d'age et de vieillissement sont prises en compte dans le jeu, les créatures perdant toutes un point de vie par jour (hormis les créatures détenues en prison, qui en perdent trois).

La monnaie officielle de COMICS est le batdollar, en référence évidemment à Batman

L'utilisation du hasard dans certaines décisions des créatures permet d'assurer une évolution non planifiée du monde.

Téléchargement, licence et compilation

Le code source du logiciel et cette présente documentation sont publiés sous licence Creative Commons Attribution-NonCommercial-ShareAlike 2.0, et peuvent être obtenus dans l'archive se trouvant à l'adresse suivante : http://lacot.org/public/enst/comics-an-eiffel-smallworld.tar.gz.

Par soucis de rapidité et de clarté, cette documentation utilise la feuille de style empoyée par le W3C pour la publication de Recommandations. Les règles de licence suivantes s'appliquent à cette feuille de style : http://www.w3.org/Consortium/Legal/copyright-software

Cette archive peut être employée en effectuant les commandes suivantes :

$ tar xzvf comics-an-eiffel-smallworld.tar.gz
$ cd comics-an-eiffel-smallworld
$ make

Le Makefile fournit dans l'archive prévoit l'emploi de la commande "compile" du compilateur Smarteiffel.

Géographie

Afin de définir une notion de proximité entre les êtres présents dans COMICS, une géographie simpliste a été définie, sous forme de grille rectangulaire dont l'utilisateur définit les dimensions au démarrage du système. Dans cette grille, les objets et les êtres sont repérés par leurs coordonnées (x, y)

Une commande permet à l'utilisateur de visualiser une carte du monde, alors représenté sous forme de cases, dont le contenu indique le nombre de créatures présentes dans la case correspondante. Dans l'exemple ci-dessous, on observe ainsi que la case (3, 0) du monde contient 4 créatures.

(C)ontinuer, (D)etails, (M)Carte, (Q)uitter ? M
   0 1 2 3 4 5 6 7 8 9

0        4 1
1        1     2
2                    1
3      1     1   2 1 1
4  1   1     1       1
5  1             1   1
6    1
7    1         1
8  1   1 1           2
9      1 1 1

Cimetière

Lorsque le niveau de vie d'une créature atteint 0, elle meurt, mais son cadavre encore chaud reste visible dans le monde des créatures. Ce n'est que pendant la nuit, lorsque toutes les créatures sont calmes, que les êtres décédés sont transportés jusqu'au cimetière.

Une créature qui se trouve au cimetière étant morte, elle ne peut ni se déplacer ni effectuer d'action.

Prison

Il peut arriver que des créatures se fassent arrêter par les autorités de COMICS. Dans ce cas, elles sont transférées la nuit venue à la prison.

Une créature qui se trouve en prison ne peut pas se déplacer. Par contre, les gardiens sont assez laxistes et ne placent les détenus en cellule de sécurité qu'après trois tentatives d'évasion consécutives et infructueuses. Un prisonnier en cellule de sécurité ne peut sortir de prison qu'en payant la somme de 1000 batdollars à l'état.

La prison étant un lieu très stressant, un être qui y est détenu perd trois points de vie par jour.

Créatures

Organisation des classes du système
Schéma d'organisation des classes du système. COMICS est la classe générale du système, UTILS ne contient qu'un générateur de nombres aléatoires.

Créatures de Base

Une classe CREATURE a été écrite, afin de représenter les caractéristiques communes à tous les êtres vivants :

Cette classe ne peut pas être instanciée, c'est une classe abstraite. Cependant, elle définit certaines methodes communes à tous les types de créatures du monde : accesseurs, naissance, utilisation d'objet, etc. Les méthodes get_premier_objet(objets: FAST_ARRAY[OBJET]): OBJET et get_premiere_creature(creatures: FAST_ARRAY[CREATURE]; type: STRING): CREATURE ont pour rôle de renvoyer un objet ou une creature présente dans la même case que la créature courante, et répondant à certaines caractéristiques. Ces deux méthodes sont très utilisées, notamment, dans la définition des actions possibles pour chaque type de créature en fonction de son environnement.

La classe CREATURE propose quelques méthodes retardées, dont get_type: STRING. Cette méthode, définie dans toute classe héritée de CREATURE, renvoie sous forme de STRING le type de la créature.

Animaux

Les animaux sont somme toute des créatures relativement basiques. Leur présence dans le monde n'est destinée qu'à fournir une source d'alimentation pour les humains. Les animaux peuvent brouter de l'herbe et se déplacer de 3 cases chaque jour.

Humains

Les humains permettent d'introduire la notion de richesse. Chaque humain naît avec 1000 batdollars en poche, qu'il dépense, gagne ou perd au grès de ses rencontres ou de ses trouvailles.

En plus des actions que peuvent effectuer les créatures basiques, les humains peuvent se faire prendre en photo avec un Superheros présent dans la même case que lui, ou encore manger un animal proche de lui... s'il parvient à attraper celui-ci !

Policiers

Comme dans la réalité, un policier est un humain dont le rôle est de protéger et ordonner le monde. Pour cela, chaque policier est équipé d'un revolver, qu'il doit approvisionner en munitions, et dispose d'actions bien spécifiques :

Lorsqu'un policier parvient à abattre un superméchant, il lui fait généralement les poches et arrondit ainsi ses fins de mois...

Superméchants

C'est des superméchants que vient tout le désordre qui règne dans COMICS. Sans eux, COMICS serait un monde en paix, où les créatures vivraient en harmonie, sans se faire de mal (oui, c'est effectivement un peu naïf...). C'est sans doute la raison pour laquelle le champ d'actions que peut réaliser un superméchant est assez vaste. On distingue deux cas :

Superhéros

Étant à la fois des humains et des animaux, les superhéros peuvent se déplacer à la vitesse des animaux (3 cases/jour), tout en réalisant les actions des humains basiques. Ceci dit, un superhéros n'en serait pas un sans certaines finesses :

Objets

Afin de rendre le monde plus vivant et attractif, il a été décidé d'introduire des objets dont l'utilisateur fixe le nombre au démarrage du programme, et avec lesquels les créatures peuvent interagir. On trouve ainsi :

Il peut y avoir dans le monde plusieurs occurences de chaque type d'objet. Un objet est utilisé instantanément après sa découverte par une créature.

La classe OBJET n'a cependant pas été suffisamment développée pour permettre une utilisation intelligente et cohérente des objets par les créatures. Ainsi, il pourra arriver dans le système qu'un animal trouve de l'argent, et qu'il l'utilise. Afin d'éviter toute incohérence, une méthode vide gagner(somme: INTEGER) a donc été créée dans la classe ANIMAL.

Commandes

Commandes de paramétrage du monde

L'interactivité du système est volontairement limitée, de manière à éviter que l'utilisateur ait trop d'actions à réaliser au cours d'une évolution du monde.

Au démarrage du logiciel, l'utilisateur se voit poser plusieurs questions dont les réponses permettent de définir les caractéristiques principales du monde :

Commandes d'action

A chaque tour de jeu (chaque "jour"), en mode de déroulement non automatique, l'utilisateur a le choix entre quatre actions différentes : (C)ontinuer, (D)etails, (M)Carte, (Q)uitter. Voici le détail de chacune de ces actions :

Problèmes

Plusieurs améliorations possibles pourraient être apportées à ce projet. On peut penser, notamment, à une modélisation plus propre des objets, uniquement matérialisés par un INTEGER dans le projet actuel.

Certaines curiosités du compilateur, observées au cours du développement, ont mené à des modifications "à tâtons" du code, sans qu'aucune explication rationnelle ne puisse expliquer ces dysfonctionnements. Le plus flagrant concerne la classe SUPERHEROS, lignes 56-70, dans lesquelle on souhaite employer deux fois l'appel à Precursor. Avec le code suivant, la compilation se déroule sans problèmes :

56				if creature_presente(creatures, "ANIMAL") then
57					-- soigne un animal s'il est trop faible
58					animal := get_premiere_creature(creatures, "ANIMAL")
59					if animal.get_vie < 10 then
60						soigner_creature(animal)
61					end
62				else
63					-- effectue une des autres 
64					-- actions disponibles
65					Precursor(creatures, objets)
66				end

Avec le code suivant, qui effectue deux appels à Precursor, la production d'un exécutable échoue au niveau du linkage par ld des fichiers compilés :

56				if creature_presente(creatures, "ANIMAL") then
57					-- soigne un animal s'il est trop faible
58					animal := get_premiere_creature(creatures, "ANIMAL")
59					if animal.get_vie < 10 then
60						soigner_creature(animal)
61					else
62						-- effectue une des autres 
63						-- actions disponibles
64						Precursor(creatures, objets)
65					end
66				else
67					-- effectue une des autres 
68					-- actions disponibles
69					Precursor(creatures, objets)
70				end

L'erreur produite a alors la douce allure suivante :

gavroche tp/eiffel/comics_new $ make
compile -o comics comics.e
comics1.c:5137: redefinition of `r79_P_46_action'
comics1.c:5065: `r79_P_46_action' previously defined here
/usr/ccs/bin/as: "<stdin>", line 26268: error: redefinition of symbol "r79_P_46_action"
comics1.c:5179: redefinition of `r79_P_43_action'
comics1.c:5107: `r79_P_43_action' previously defined here
/usr/ccs/bin/as: "<stdin>", line 26609: error: redefinition of symbol "r79_P_43_action"
/usr/ccs/bin/as: "<stdin>", line 26593: warning: size of "r79_P_46_action" redefined
/usr/ccs/bin/as: "<stdin>", line 26711: warning: size of "r79_P_43_action" redefined
Undefined                       first referenced
 symbol                             in file
M44                                 comics4.o
M45                                 comics4.o
M46                                 comics4.o
M47                                 comics4.o
s80_7778127                         comics2.o
s43_425724326                       comics2.o
s22_1941685                         comics3.o
r45get_position_x                   comics4.o
M63                                 comics4.o
r45get_position_y                   comics4.o
M64                                 comics4.o
M65                                 comics4.o
s22_603461234                       comics3.o
M79                                 comics4.o
r79default                          comics4.o
r79details                          comics4.o
M80                                 comics4.o
M82                                 comics4.o
M83                                 comics4.o
M86                                 comics4.o
r79vivante                          comics4.o
se_prinT1                           comics4.o
r45gagner                           comics4.o
se_prinT2                           comics4.o
se_prinT3                           comics4.o
se_prinT5                           comics4.o
se_prinT6                           comics4.o
se_prinT7                           comics4.o
se_prinT8                           comics4.o
se_prinT9                           comics4.o
s46_1616409705                      comics2.o
r79get_random_integer               comics4.o
s80_1848995245                      comics2.o
s80_568530978                       comics2.o
s80_467284159                       comics2.o
s44_33574519                        comics2.o
r79get_position_x                   comics4.o
r79get_position_y                   comics4.o
se_signal_handler                   comics4.o
r79objet_present                    comics4.o
r45get_type                         comics4.o
s47_1331371528                      comics4.o
r79is_default                       comics4.o
s22_473935479                       comics3.o
s22_1313310242                      comics3.o
ci                                  comics2.o
gc_fsoc_get1                        comics4.o
gc_fsoc_get2                        comics4.o
s22_54515690                        comics3.o
r45io                               comics4.o
s44_61410822                        comics2.o
r45inverser_coordonnees             comics4.o
s22_1432086796                      comics3.o
r79get_type                         comics4.o
se_gc_check_id                      comics4.o
r79io                               comics4.o
r79utiliser_objet                   comics4.o
s44_1430963478                      comics2.o
s43_9                               comics2.o
s46_1530702985                      comics2.o
s43_1712820107                      comics2.o
s22_2074145                         comics3.o
s22_992                             comics3.o
s80_1856798732                      comics2.o
r79gagner                           comics4.o
s43_252                             comics2.o
s22_652423121                       comics3.o
r45soigner                          comics4.o
s22_4622985                         comics3.o
gcmt                                comics4.o
s46_845437880                       comics2.o
s80_518931484                       comics2.o
s44_346795607                       comics2.o
s22_1966263839                      comics3.o
r45est_libre                        comics4.o
r79action                           comics4.o
s22_420935003                       comics3.o
s22_2028280921                      comics3.o
ac_civ                              comics3.o
vc                                  comics2.o
garbage_delayed                     comics4.o
s22_1727813738                      comics3.o
r79get_premier_objet                comics4.o
stack_bottom                        comics4.o
s80_1291676919                      comics2.o
s22_775354682                       comics3.o
s46_152855367                       comics2.o
s44_520333618                       comics2.o
s22_1032851696                      comics3.o
s22_1714894                         comics3.o
new_na                              comics4.o
s46_289818                          comics2.o
gc_is_off                           comics4.o
ac_inv                              comics2.o
gcmt_used                           comics4.o
mark_stack_and_registers            comics4.o
s46_1900393285                      comics2.o
s22_0                               comics3.o
s80_1530702986                      comics2.o
s43_1943769311                      comics2.o
r79get_richesse                     comics4.o
s22_420486943                       comics3.o
s46_1488204435                      comics2.o
r45is_default                       comics4.o
s22_557423960                       comics3.o
s22_164116148                       comics3.o
s22_851757497                       comics3.o
s43_1605022196                      comics2.o
r79soigner                          comics4.o
r45details                          comics4.o
s43_588747                          comics2.o
s43_1443750694                      comics2.o
r45mourir                           comics4.o
s22_1441398327                      comics3.o
s80_281171235                       comics2.o
r79standard_streams                 comics4.o
r45objet_present                    comics4.o
s22_1678810106                      comics3.o
r79deplacer                         comics4.o
se_require_last_result              comics2.o
s22_10                              comics2.o
s22_1630336474                      comics3.o
se_require_uppermost_flag           comics2.o
gcmt_max                            comics4.o
s22_1176831237                      comics3.o
s43_599594626                       comics2.o
r79inverser_coordonnees             comics4.o
s80_434133564                       comics2.o
s22_32                              comics3.o
s43_284005346                       comics2.o
r45get_vie                          comics4.o
s80_1349511683                      comics2.o
s22_60                              comics3.o
s22_67                              comics3.o
s22_216663156                       comics3.o
r45get_richesse                     comics4.o
s22_81                              comics3.o
r45morte                            comics4.o
se_dst                              comics2.o
r45deplacer                         comics4.o
r45emprisonner                      comics4.o
s80_945262615                       comics2.o
s80_65735511                        comics2.o
ac_ens                              comics2.o
s22_1405390195                      comics3.o
r79get_vie                          comics4.o
se_malloc                           comics4.o
r45get_premier_objet                comics4.o
r79depenser                         comics4.o
se_prinT34                          comics4.o
s80_175                             comics2.o
se_prinT35                          comics4.o
s80_1049890763                      comics2.o
s22_113                             comics3.o
s22_521538372                       comics3.o
s31_117797837                       comics4.o
se_prinT41                          comics4.o
se_prinT44                          comics4.o
se_prinT45                          comics4.o
se_prinT46                          comics4.o
se_prinT47                          comics4.o
se_prinT10                          comics4.o
se_prinT11                          comics4.o
r45get_random_integer               comics4.o
s47_263326                          comics2.o
se_evobt                            comics2.o
se_prinT22                          comics4.o
se_print_run_time_stack             comics2.o
gc_sweep                            comics4.o
create45naissance                   comics3.o
s45_778926303                       comics2.o
s22_693308564                       comics3.o
r79mourir                           comics4.o
s22_1971954363                      comics3.o
r45blesser                          comics4.o
oBC12standard_streams               comics2.o
fBC12standard_streams               comics2.o
s22_192                             comics3.o
r79est_libre                        comics4.o
fsocfl                              comics4.o
r79get_nom                          comics4.o
s47_1571578954                      comics4.o
r45standard_streams                 comics4.o
r45depenser                         comics4.o
s80_1752698245                      comics2.o
M7                                  comics4.o
r79blesser                          comics4.o
s80_581773460                       comics2.o
se_prinT79                          comics4.o
s22_701318948                       comics3.o
se_prinT80                          comics4.o
se_prinT82                          comics4.o
se_prinT83                          comics4.o
se_prinT84                          comics4.o
se_prinT85                          comics4.o
se_prinT86                          comics4.o
se_prinT87                          comics4.o
s22_882043236                       comics3.o
ac_req                              comics2.o
gc_find_chunk                       comics4.o
r45default                          comics4.o
s80_23046122                        comics2.o
r45vivante                          comics4.o
se_prinT63                          comics4.o
se_prinT64                          comics4.o
se_prinT65                          comics4.o
r45utiliser_objet                   comics4.o
r45action                           comics4.o
s22_486409623                       comics3.o
se_rci                              comics2.o
s44_304769429                       comics2.o
s46_1173507657                      comics2.o
r79morte                            comics4.o
s22_1311456055                      comics3.o
M22                                 comics4.o
r45get_nom                          comics4.o
r79emprisonner                      comics4.o
collector_counter                   comics4.o
M34                                 comics4.o
M35                                 comics4.o
s22_1943246756                      comics3.o
gcmt_tail_addr                      comics4.o
error2                              comics4.o
s79_202953028                       comics2.o
create79naissance                   comics3.o
M41                                 comics4.o
ld: fatal: Symbol referencing errors. No output written to comics
collect2: ld returned 1 exit status

Remarques

Le code fourni contient 13 lignes de code issues de Damien Accorsi <damien.accorsi@enst.fr>, qui a effectué les recherches concernant l'introduction d'évènements aléatoires dans le monde.