Sauver la planùte en C++ 🌍

Ils nous faut ĂȘtre prĂȘts pour le prochain assaut des extraterrestres ! Et pour cela, rien de mieux que de s’entraĂźner sur un simulateur de robot et d’intelligences artificielles en C++ !

A vos claviers et souris, on commence ici !

Prérequis

N’hĂ©sitez pas Ă  me contacter ici pour toutes questions sur les notions de C++. A votre disposition si vous souhaitez aussi des cours particuliers 😉

Installation de l’environnement de dĂ©veloppement

On utilisera Code::Blocks comme environnement avec le compilateur mingw téléchargeable depuis ce lien.

Pour bien comprendre comment installer et utiliser l’IDE, je vous renvoie sur le tutoriel d’openclassroom.

Récupération des sources du simulateur

Entrez votre nom, prénom et mail puis cliquer sur le bouton télécharger pour obtenir les sources.

Compilation du projet

Une fois l’archive .zip tĂ©lĂ©chargĂ©e, dĂ©compressez-la, puis ouvrez le fichier j2l-SimulateurIA.workspace via double-clic.

DĂ©compressions de l’archive zip une fois tĂ©lĂ©chargĂ©e

Ouvrez bien le fichier avec l’extension .workspace (et non le fichier projet .cpb). Si l’extension n’est pas visible, dans l’Explorateur de fichiers -> Affichage -> Afficher/Masquer cocher Extensions de nom de fichiers.

Si le double-clic n’ouvre pas automatiquement Code::Blocks, ouvrez Code::Blocks manuellement, puis glisser-dĂ©poser le fichier j2l-SimulateurIA.workspace dans la fenĂȘtre.

Une fois ouvert, dans la fenĂȘtre « Management » vous devriez voir les sources du projet j2l-SimulateurIA, triĂ©es dans 3 dossiers virtuels :

Arborescence du projet
  • Agent : Contient les sources de vos classes agents, classes qui devront implĂ©menter l’intelligence artificiel dĂ©crivant comment les entitĂ©s du jeu vont agir de maniĂšre autonome
  • Jeu : Contient les variables et fonctions pour interagir avec le jeu ; Vous ne pouvez pas modifier ces sources (les rĂšgles du jeu sont impĂ©nĂ©trables ^^)
  • MoteurRendu : Contient vos classes pour afficher les rendus et animations de vos agents

Pour lancer l’application et voir les agents Ă©voluer dans le jeu, cliquez Build -> Build and run (ou le raccourci clavier F9). Des lignes de commande devraient apparaĂźtre dans la fenĂȘtre « Logs & others », puis l’application devrait dĂ©marrer en plein Ă©cran.

Modifier le comportements des agents

Pour cela, explorons la classe AgentSpecial implémentée dans les fichiers AgentSpecial.cpp et AgentSpecial.hpp.

Dans le fichier header (le fichier d’en-tĂȘte avec l’extension .hpp), vous trouverez les signatures des mĂ©thodes et attributs de la classe AgentSpecial. Tandis que dans le fichier .cpp, vous trouverez l’implĂ©mentation (le code) de chaque fonctions de la classe (les mĂ©thodes).

En général, un header donne les informations aux utilisateurs pour savoir comment utiliser une classe, mais ne livre surtout pas le secret de fabrication caché dans le fichier cpp.

class AgentSpecial:
    public j2l::Agent
{
    public:
        AgentSpecial(int x, int y, int orientation);
        virtual ~AgentSpecial() {}
        const char* nom() const;

    protected:
        void quandActualiser();
        void quandDistanceFrontaleChange(int ancienneValeur, int nouvelleValeur);
        void quandMunitionsChange(int ancienneValeur, int nouvelleValeur);
        void quandVieChange(int ancienneValeur, int nouvelleValeur);
        void quandPoseChange(int ancienX, int ancienY, int ancienneOrientation, int nouvelX, int nouvelY, int nouvelleOrientation);
};

Les deux premiĂšres lignes indiquent que la classe AgentSpecial hĂ©rite des mĂ©thodes et attributs de la classe Agent, implĂ©mentĂ©e dans l’espace de nom j2l. Cela signifie que cette classe fille contient aussi les mĂ©thodes et attributs de la classe parente Agent, dĂ©finis dans le fichier Agent.hpp.

class Agent
	{
		public:
			Agent(int x, int y, int orientation);
			virtual ~Agent() {}
			void actualiser(int x, int y, int orientation, int distance, int vie, int munitions, int& ordreX, int& ordreY, int& ordreOrientation, bool& ordreTir);
			void orienter(int orientation);
			void deplacer(int x, int y);
			void tirer(bool tirerOuNon);
			int munitionsRestantes() const;
			int viesRestantes() const;
			int munitionsInitiales() const;
			int viesInitiales() const;
			int distanceFrontale() const;
			int x() const;
			int y() const;
			int orientation() const;
			virtual const char* nom() const;

		protected:
			virtual void quandActualiser() {}
			virtual void quandDistanceFrontaleChange(int ancienneValeur, int nouvelleValeur) {}
			virtual void quandMunitionsChange(int ancienneValeur, int nouvelleValeur) {}
			virtual void quandVieChange(int ancienneValeur, int nouvelleValeur) {}
			virtual void quandPoseChange(int ancienX, int ancienY, int ancienneOrientation, int nouvelX, int nouvelY, int nouvelleOrientation) {}
	};

Cependant elle ne pourra accĂ©der qu’aux mĂ©thodes et attributs public et protected (private Ă©tant accessible uniquement Ă  l’intĂ©rieur des mĂ©thodes la classe Agent).

ÉlĂ©ments intĂ©ressants, la classe Agent parent dispose de mĂ©thodes virtuelles, ce qui signifie que la classe enfant peut les « surcharger » et redĂ©finir ces propres comportement, par dessus ou Ă  la place des mĂ©thodes parentes :

  • quandDistanceFrontaleChange() : appelĂ©e Ă  chaque tour de jeu, quand l’agent dĂ©tecte un enemi dans son champs de vision
  • quandMunitionsChange() : appelĂ©e Ă  chaque tour de jeu, quand l’agent perd une munition, signifiant qu’un tir a bien Ă©tĂ© effectuĂ©
  • quandVieChange() : appelĂ©e Ă  chaque tour de jeu, quand l’agent est sous le feu ennemi
  • quandPoseChange() : appelĂ©e Ă  chaque tour de jeu, quand l’agent bouge ou change d’orientation
  • quandActualiser() : appelĂ©e en dernier Ă  chaque tour du jeu

Sachant çela, il ne vous reste plus qu’Ă  implĂ©menter le corps des mĂ©thodes suivantes dans le fichier AgentSpecial.cpp, de maniĂšre Ă  dĂ©finir un comportement intelligent !

Maintenant, Ă  vous de jouer !

Les rĂšgles du jeu

Les agents combattent sur un plateau constitué de 15 lignes (y allant de 0 à 14) et 15 colonnes (x allant de 0 à 14).

Plateau du jeu

Chaque tour du jeu, un agent peut effectuer jusqu’Ă  4 actions en mĂȘme temps parmi les suivantes :

Actions possibles par un agent Ă  chaque tour de jeu

Ces ordres d’actions peuvent ĂȘtre effectuĂ©s en appelant les mĂ©thodes suivantes (depuis les mĂ©thodes surchargĂ©es dans la classe AgentSpecial) :

  • tirer() : en passant « true » pour activer tir en rafale, ou false pour dĂ©sactiver
  • dĂ©placer() : en passant les coordonnĂ©es de la case destination (attention de bien choisir une case adjacente dans la limite du plateau)
  • orienter() : en passant un des quatre points cardinaux (Nord, Sud, Est, Ouest)

Chaque tour de jeu, l’agent reçoit 5 variables actualisĂ©es qui l’informe de son Ă©tat dans son environnement :

DonnĂ©es renseignĂ©es Ă  l’agent Ă  chaque tour de jeu

Ces donnĂ©es d’Ă©tat peuvent ĂȘtre rĂ©cupĂ©rĂ©es en appelant les mĂ©thodes suivantes (depuis les mĂ©thodes surchargĂ©es dans la classe AgentSpecial) :

  • viesRestantes() : renvoie un entier compris entre 0 et VIE_MAX (Ă©gal Ă  100)
  • munitionsRestantes() : renvoie un entier compris entre 0 et MUNITIONS_MAX (Ă©gal Ă  10)
  • x(), y(): renvoie un entier compris respectivement entre 0 et X_MAX et 0 et Y_MAX
  • orientation() : renvoie un des quatre points cardinaux (Nord, Sud, Est, Ouest)
  • distanceFrontale() : renvoie la distance Ă  un obstacle devant l’agent (0 si pas d’obstacle en vue)

Modifier le comportement des rendus

Dans MoteurRenduAgentSpecial.hpp et MoteurRenduAgentSpecial.cpp

Initialisation du jeu

Dans main.cpp