Comprendre et utiliser le moteur d openESub

De OpenESubWiki.

Le moteur d'openESub est bien séparé du reste, et il est possible de l'utiliser tout seul ou presque. Dans cet article, nous allons voir comment utiliser le moteur pour faire un simulateur (très) rudimentaire.

Cachalot (c'est le petit nom du moteur de base) est écrit en Python, comme une grande partie d'openESub, et est situé dans le répertoire /jeu/commun/cachalot de l'arborescence du jeu.

Sommaire

Pré-requis

Pour suivre cet article, il vous faut :

  • installer Python sur votre machine,
  • télécharger l'arborescence contenant le moteur, pour ce faire, reportez-vous à l'article utiliser le CVS,
  • plaçons-nous dans le répertoire /jeu/commun/cachalot/test où nous allons mettre notre fichier kolga.py (Kolga est une fille d'Aegir dans la mythologie nordique).

Code

Imports

Comme tout programme Python, il faut commencer par importer les modules.

Les modules généraux que nous allons utiliser sont :

import cmd    # gère l'interface de type shell
import sys    # gère certains appels systèmes
import os     # gère les interaction avec le système d'exploitation

Pour importer les modules du moteur, nous allons devoir ajouter les chemins corrects au path :

sys.path.insert(0,os.path.abspath('../src'))
sys.path.insert(0,os.path.abspath('../../../tempsReel/clients/argo/src'))

Les modules d'intérêt concernant le moteur sont :

import openRapport            # gestion des comptes-rendus
import openZdop               # zones d'opération (parties)
import openMoteur             # le moteur lui-même
from openConstantes import *  # les constantes d'openESub

Classe et constructeur

Tout d'abord, on créé une classe qui va définir notre petit simulateur. Cette classe hérite de la classe Cmd qui permet de construire rapidement une interface en mode texte. On met en place deux méthodes de base : une commande d'aide et une commande de sortie.

class Kolga(cmd.Cmd):
  """Simulateur en ligne de commande tout simple"""

  def help_help(self):
      print "Affiche la liste des commandes disposant d'une aide"

  def do_EOF(self, ligne):
      """Commande de sortie du shell : [Ctrl-D] sous Unix, [Ctrl-Z] sous Windows"""
      print '\n'
      sys.exit()

  def removeEmptyItem(self,list):
      """Supprime les items vides d'une liste de strings. Exemple : ['a',,'b'] -> ['a','b']"""
      return filter(None,list[:])

La dernière méthode permet de faciliter le traitement des paramètres passés à certaines commandes.

Ensuite on initialise les différentes variables. Notez qu'on choisit de passer le compte-rendu au format XML en tant que paramètre du constructeur.

  # constructeur (première fonction appelée
  # lors de l'instanciation de la classe)
  def __init__(self,data):

      # initialise le gestionnaire de ligne de commande
      cmd.Cmd.__init__(self)

      # charge le compte-rendu XML pour extraire les données
      self.soums, self.torps = openRapport.LireCompteRendu(data)

      # définit une zone d'op standard
      zdop = openZdop.Zdop(0., 20000., 0., 20000.)

      # crée une instance du moteur
      self.moteur = openMoteur.Moteur(zdop)

      # crée un dictionnaire des sous-marins et des torpilles,
      # associant l'id à l'objet marin
      self.soumi = {}
      for soum in self.soums:
          self.soumi[soum.id] = soum
      self.torpi = {}
      for torp in self.torps:
          self.torpi[torp.id] = torp

On peut noter que notre classe présente les variables d'intérêt suivantes :

  • moteur : une instance du moteur Cachalot,
  • soumi et torpi : des dictionnaires associant un numéro d'id à un objet marin.

Lister

Notre première méthode va lister les objets présents sur la zone d'opération.

  def do_liste(self,line):
      """Affiche la liste des objets"""
      
      # sous-marins
      for soum in self.soums:
          # affichage formaté
          print "(%d) Sub %s \t " % (soum.id, soum.nom), soum.contact('short')

      # torpilles
      for torp in self.torps:
          print "(%d) Torp \t " % (torp.id), torp.contact('short')

Compiler

Cette méthode va servir à compiler un tour.

  def do_compiler(self,line):
      """Effectue une compilation"""

      # utilise le moteur
      faits, contacts, self.soums, self.torps = self.moteur.compiler(self.soums, self.torps)

      # re-crée les dictionnaires
      self.soumi = {}
      for soum in self.soums:
          self.soumi[soum.id] = soum
      self.torpi = {}
      for torp in self.torps:
          self.torpi[torp.id] = torp

      # affiche les évenements du tour
      for fait in faits:
          print fait

Ordres

Cette méthode va donner des ordres à un sous-marin (ami ou ennemi).

  def do_ordonne(self,line):
      """Donne un ordre à un sous-marin : ordonne <id> <vitesse> <cap> <tir> ; avec <tir> valant 0 (pas de tir) ou 1 (tir)"""

      # nettoie la commande
      args = self.removeEmptyItem(line.split(' '))

      # traduit les valeurs en entier
      try:
          id, dv, dcap, tir = map(int, args)
      except:
          print "Erreur de syntaxe"
          # affiche l'aide de la commande
          self.do_help('ordonne')
          return

      # si le sous-marin existe
      if self.soumi.has_key(id):
          # passe les ordres
          self.soumi[id].ordonne(dv = dv, dcap = dcap, tir = tir)
          print "Ordres du sous-marin", self.soumi[id].nom, ": dv", dv,
          print "dcap", dcap, "tir", tir
      else:
          print "Erreur: Le sous-marin", id, "n'existe pas."

Interface

Nous allons maintenant écrire ce qui va permettre au simulateur de se lancer.

if __name__ == '__main__':
 
  # teste si argument présent
  if len(sys.argv) <= 1:
      cr = raw_input("Entrez le nom du comptes-rendu de départ > ")
  else:
      cr = sys.argv[1]

  # ouvre le compte-rendu XML passé en premier argument
  data = openRapport.OuvrirCompteRendu(cr)
 
  # message de bienvenue
  print 'Bienvenu sur la console de Kolga'
  print '    Kolga est un simulateur pour openESub (http://www.openesub.org)'
  print '    tapez "help" pour avoir la liste des commandes'
  print '    '

  # on lance la console interactive
  shell = Kolga(data)
  shell.prompt = "Kolga> "
  shell.cmdloop()

Usage

Pour utiliser Kolga, c'est très simple :

  • soit vous lancez le script avec un CR au format XML en premier argument : python kolga.py monCR.xml,
  • soit vous préférez lancer le script sans argument, auquel cas il vous faudra taper le nom du fichier lorsqu'il vous le demandera.

Kolga est présent dans l'arborescence que vous avez téléchargé au début de l'article, donc pas besoin de faire des copier/coller du code écrit ci-dessus. Il se peut que le fichier soit légèrement différent du code source de cet article, ce n'est pas grave, préférez toujours la version téléchargée via CVS. Notez que Kolga ne va pas évoluer en fonctionnalités, si vous désirez ajouter des fonctionnalités et que vous voulez en faire profitez d'autres joueurs, contactez les mainteneurs du projet, ils créeront une section pour votre simulateur.

Conclusion

Les fonctions importantes du code source d'openESub dont nous nous sommes servies sont les suivantes :

  • Pour charger un CR XML :
data = openRapport.OuvrirCompteRendu( MON_FICHIER_XML )
soums, torps = openRapport.LireCompteRendu(data)
  • Pour compiler un tour :
zdop = openZdop.Zdop(0., 20000., 0., 20000.)
moteur = openMoteur.Moteur(zdop)
faits, contacts, soums, torps = self.moteur.compiler(self.soums, self.torps)
  • Pour passer des ordres à un sous-marin :
soum.ordonne(dv, dcap, tir)

Comme vous pouvez le constater, elles sont simples et intuitives... réaliser un simulateur plus graphique ne devrait donc maintenant plus vous poser de problèmes.

Outils personnels