Here are some little improvements compared to the patch I
posted last week.

1) Compiles against current CVS (english names)
2) Add check boxes in the option menu in order to choose if
the player is human or not
3) Bug fixes in the AI algorithm
4) files "strategy.h", "strategy.cpp", "computer.h" and
"computer.cpp" are put in a directory "ai".

I am waiting for your comments.

Arnaud.

////////////////////////////////////////////////////////////
// Webmail Oreka : http://www.oreka.com
////////////////////////////////////////////////////////////
Index: Makefile
===================================================================
RCS file: /cvs/wormux/wormux/src/Makefile,v
retrieving revision 1.17
diff -u -r1.17 Makefile
--- Makefile    14 Jul 2004 04:45:01 -0000      1.17
+++ Makefile    14 Jul 2004 16:27:25 -0000
@@ -5,7 +5,7 @@
 CURRENT_SUBDIR=.
 ROOT=./
 SUBDIRS =game graphic gui include interface map menu object sound 
-SUBDIRS+=team tool weapon
+SUBDIRS+=team tool weapon ai
 
 # Common defintions
 include make.env
Index: game/game_loop.cpp
===================================================================
RCS file: /cvs/wormux/wormux/src/game/game_loop.cpp,v
retrieving revision 1.1
diff -u -r1.1 game_loop.cpp
--- game/game_loop.cpp  14 Jul 2004 04:45:01 -0000      1.1
+++ game/game_loop.cpp  14 Jul 2004 16:27:27 -0000
@@ -156,8 +156,15 @@
         || (etat == jeuVER_A_JOUE)
         || ((etat == jeuPAUSE_FIN_TOUR))))
     {
-      souris.Gestion();
-      clavier.Gestion();
+         if (EquipeActive().GetAI())
+         {
+               EquipeActive().Play();
+         }
+         else
+         {
+        souris.Gestion();
+        clavier.Gestion();
+         }
     }
 
     // Gestion des vers
@@ -479,4 +486,4 @@
   return false;
 }
 
-//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
Index: menu/options_menu.cpp
===================================================================
RCS file: /cvs/wormux/wormux/src/menu/options_menu.cpp,v
retrieving revision 1.1
diff -u -r1.1 options_menu.cpp
--- menu/options_menu.cpp       14 Jul 2004 04:45:01 -0000      1.1
+++ menu/options_menu.cpp       14 Jul 2004 16:27:29 -0000
@@ -116,6 +116,12 @@
       ChangeTerrain();
     } else if (lboxVideoMode.Clic(x, y)) {
     } else if (lboxTeams.Clic(x, y)) {
+       } else {
+               bool clic_ai = false;
+               for (unsigned int i = 0; i < team_ai.size(); i++)
+                       if (team_ai[i].Clic(x, y))
+                               clic_ai = true;
+               if (clic_ai) {
     } else if (option_affichage_energie.Clic(x, y)) {
     } else if (option_affichage_nom.Clic(x, y)) {
     } else if (full_screen.Clic(x, y)) {
@@ -126,7 +132,7 @@
     } else if (opt_sound.Clic (x,y)) {
     } else if (opt_music.Clic (x,y)) {
     } else if (opt_sound_effects.Clic (x,y)) {
-    }
+    }}
     return;
   }
 }
@@ -198,6 +204,10 @@
     bool choix = gst_equipes.EstSelectionnee (i);
     lboxTeams.AddItem (choix, (*it).LitNom());
     ++i;
+       CheckBox box;
+       box.Init(_("AI"), 0, 0);
+       box.SetValue(false);
+       team_ai.push_back(box);
   }
 
   // Generate video mode list
@@ -233,6 +243,12 @@
 {
   lst_terrain.ChangeTerrain (lboxMaps.GetSelectedItem());
   gst_equipes.ChangeSelection (lboxTeams.GetSelection());
+       
+  std::list<int> ai_list;
+  for (unsigned int i = 0; i < team_ai.size(); i++)
+    ai_list.push_back(team_ai[i].GetValue());
+  gst_equipes.ChangeAI(ai_list);
+                 
   config.affiche_energie_ver = option_affichage_energie.GetValue();
   config.affiche_nom_ver = option_affichage_nom.GetValue();
 
@@ -313,6 +329,8 @@
 
   lboxMaps.SetXY (espace, 30);
   lboxTeams.SetXY ((espace*3)+CARTE_LARG+MAPS_LARG, TEAMS_Y);
+  for (unsigned int i = 0; i < team_ai.size(); i++)
+         team_ai[i].SetXY(espace*3+CARTE_LARG+MAPS_LARG+TEAMS_LARG, TEAMS_Y + 
i * 15);
   lboxVideoMode.SetXY ((espace*3)+CARTE_LARG+MAPS_LARG-30, VIDEO_MODE_Y);
 
   option_affichage_energie.SetXY (espace, CBOX_ENERGIE_Y);
@@ -354,6 +372,8 @@
     enregistrer.Draw(x,y) ;
     lboxMaps.Display(x,y);
     lboxTeams.Display(x,y);
+       for (unsigned int i = 0; i < team_ai.size(); i++)
+               team_ai[i].Display(x,y);
     lboxVideoMode.Display(x,y);
     option_affichage_energie.Display(x,y);
     option_affichage_nom.Display(x,y);
Index: menu/options_menu.h
===================================================================
RCS file: /cvs/wormux/wormux/src/menu/options_menu.h,v
retrieving revision 1.1
diff -u -r1.1 options_menu.h
--- menu/options_menu.h 14 Jul 2004 04:45:01 -0000      1.1
+++ menu/options_menu.h 14 Jul 2004 16:27:29 -0000
@@ -30,6 +30,7 @@
 #include "../gui/check_box.h"
 #include "../gui/spin_button.h"
 #include <string>
+#include <vector>
 #include <ClanLib/core.h>
 //-----------------------------------------------------------------------------
 
@@ -42,6 +43,7 @@
 
   CheckBox option_affichage_energie, option_affichage_nom, full_screen;
   CheckBox opt_sound, opt_music, opt_sound_effects;
+  std::vector<CheckBox> team_ai;
 
   SpinButton option_temps_tour, option_temps_fin_tour, option_nb_ver, 
option_energie_ini;
   bool m_init;
Index: team/team.cpp
===================================================================
RCS file: /cvs/wormux/wormux/src/team/team.cpp,v
retrieving revision 1.1
diff -u -r1.1 team.cpp
--- team/team.cpp       14 Jul 2004 04:45:01 -0000      1.1
+++ team/team.cpp       14 Jul 2004 16:27:31 -0000
@@ -43,6 +43,8 @@
 Equipe::Equipe()
 {
   vers_fin = vers.end();
+  strategy_type = 0;
+  computer = NULL;
 }
 
 //-----------------------------------------------------------------------------
@@ -237,6 +239,9 @@
     PasseVerSuivant();
   }
 
+  if (strategy_type)
+         computer = new Computer(strategy_type);
+
   if (camera_est_sauve) camera.ChangeXYabs (sauve_camera.x, sauve_camera.y);
   camera.ChangeObjSuivi (&VerActif(), 
                         !camera_est_sauve, !camera_est_sauve, 
@@ -255,6 +260,8 @@
   // Désactive notre arme
   (*arme_active).Desactive();
   camera_est_sauve = true;
+  if (computer != NULL)
+         delete computer;
   sauve_camera = CL_Point(camera.LitX(), camera.LitY());
 }
 
@@ -360,4 +367,23 @@
   }
 }
 
+void Equipe::SetAI(int type)
+{
+       assert (computer == NULL);
+       assert (strategy_type == 0);
+       assert (type >= 0);
+       assert (type <= 1); // Only one strategy for the moment
+       strategy_type = type;
+}
+
+int Equipe::GetAI() const
+{
+       return strategy_type;
+}
+
+void Equipe::Play()
+{
+       assert (computer != NULL);
+       computer->Play();
+}
 //-----------------------------------------------------------------------------
Index: team/team.h
===================================================================
RCS file: /cvs/wormux/wormux/src/team/team.h,v
retrieving revision 1.1
diff -u -r1.1 team.h
--- team/team.h 14 Jul 2004 04:45:01 -0000      1.1
+++ team/team.h 14 Jul 2004 16:27:31 -0000
@@ -27,6 +27,7 @@
 #include "../weapon/crosshair.h"
 #include "../weapon/weapon.h"
 #include "../graphic/image.h"
+#include "../ai/computer.h"
 #include "character.h"
 #include "team_energy.h"
 #include <ClanLib/display.h>
@@ -72,6 +73,8 @@
   type_arme type_arme_active;
   Arme *arme_active;
   bool ChargeDonnee (int nbr_ver, xmlpp::Element *xml, CL_ResourceManager 
*res);
+  Computer * computer;  
+  int strategy_type;
 
 public:
   // Initialisation
@@ -80,6 +83,10 @@
             const std::string &name, 
             const std::string &directory);
   void RAZ();
+
+  void SetAI(int);
+  int GetAI() const;
+  void Play();
 
   // Passe au ver suivant
   void VerSuivant();
Index: team/teams_list.cpp
===================================================================
RCS file: /cvs/wormux/wormux/src/team/teams_list.cpp,v
retrieving revision 1.1
diff -u -r1.1 teams_list.cpp
--- team/teams_list.cpp 14 Jul 2004 04:45:01 -0000      1.1
+++ team/teams_list.cpp 14 Jul 2004 16:27:33 -0000
@@ -371,6 +371,17 @@
   m_equipe_active = liste.begin();
 }
 
+void GestionEquipes::ChangeAI(const std::list<int>& ai_list)
+{
+       iterator_complet team_it=liste_complete.begin(), 
team_fin=liste_complete.end();
+       std::list<int>::const_iterator ai_it=ai_list.begin(), 
ai_fin=ai_list.end();
+       for (; team_it != team_fin; team_it++, ai_it++)
+       {
+               assert (ai_it != ai_fin);
+               if (*ai_it != 0)
+                       team_it->SetAI(*ai_it);
+       }
+}
 //-----------------------------------------------------------------------------
 
 bool GestionEquipes::EstSelectionnee (uint index)
@@ -379,4 +390,4 @@
   return pos != selection.end();
 }
 
-//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
Index: team/teams_list.h
===================================================================
RCS file: /cvs/wormux/wormux/src/team/teams_list.h,v
retrieving revision 1.1
diff -u -r1.1 teams_list.h
--- team/teams_list.h   14 Jul 2004 04:45:01 -0000      1.1
+++ team/teams_list.h   14 Jul 2004 16:27:33 -0000
@@ -50,6 +50,7 @@
   void ActualiseEnergie (); //Actuale les jauges d'énergie
   void ActualiseClassement (); //Actuale le classement des jauges
   void ChangeSelection (const std::list<uint>& liste);
+  void ChangeAI(const std::list<int>&);
   bool EstSelectionnee (uint index);
   Equipe *ChercheNomfich (const std::string &nomfich, int &pos);
   Equipe *ChercheIndex (uint index);
@@ -65,4 +66,4 @@
 Ver& VerActif();
 
 //-----------------------------------------------------------------------------
-#endif
+#endif
/******************************************************************************
 *  Wormux, a free clone of the game Worms from Team17.
 *  Copyright (C) 2001-2004 Lawrence Azzoug.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 ******************************************************************************
 * Gestion de l'intelligence artificielle.
 *****************************************************************************/


#ifndef ORDINATEUR_H
#define ORDINATEUR_H

#include <iostream>

#include "strategy.h"

class Computer
{
	public:
	Computer::Computer(int strategy_type = -1);
	Computer::~Computer();
	void Computer::Play();
	
	protected:
	
	Strategy * strategie;
	
	long int compteur_temps;
	static const long int delai_entre_actions = 100;
	
	bool a_choisi_strategie;
	bool a_choisi_ver;
	bool a_deplace_ver;
	bool a_vise;
	bool a_tire;
	bool a_planque_ver;
	
	void ComChooseWorm();
	void ComMove();
	void ComAim();
	void ComShoot();
	void ComMoveEndTurn();
	
	void Pause();
};

#endif
/******************************************************************************
 *  Wormux, a free clone of the game Worms from Team17.
 *  Copyright (C) 2001-2004 Lawrence Azzoug.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 ******************************************************************************
 * Gestion de l'intelligence artificielle
 *****************************************************************************/

#include "computer.h"

#include "../team/teams_list.h"
#include "../tool/random.h"
#include "../team/move.h"
#include "../tool/math_tools.h"
#include <math.h>

#include <iostream>
using namespace std;

Computer::Computer(int strategy_type)
{
	switch (strategy_type)
	{
		case 1:
			strategie = new StrategyGun();
			break;
		default:
			assert(false);
			break;
	}
	
	compteur_temps = 0;
	
	a_choisi_strategie = false;
	a_choisi_ver = false;
	a_deplace_ver = false;
	a_vise = false;
	a_tire = false;
	a_planque_ver = false;
}

Computer::~Computer()
{
	delete strategie;
}

void Computer::Pause()
{
	compteur_temps = 0;
}

void Computer::Play()
{
	compteur_temps++;

	if (!a_choisi_strategie)
	{
		strategie->Compute();
		a_choisi_strategie = true;
	}
	
	if (compteur_temps >= delai_entre_actions)
	{		
		if (!a_choisi_ver)
		{
			ComChooseWorm();
		}
		else
		if (!a_deplace_ver)
		{
			ComMove();
		}
		else	
		if (!a_vise)
		{
			ComAim();
		}
		else
		if (!a_tire)
		{
			ComShoot();
		}
		else
		if (!a_planque_ver)
		{
			ComMoveEndTurn();
		}
	}
	return;
}

void Computer::ComChooseWorm()
{
	if (strategie->ChosenWorm() == & VerActif())
	{
		a_choisi_ver = true;
	} else
	{
		EquipeActive().VerSuivant();
	}
	Pause();
	return;
}

void Computer::ComMove()
{
	if (   (strategie->ShootPosition().x == VerActif().LitX())
		&& (strategie->ShootPosition().y == VerActif().LitY()))
	{
		VerActif().ChangeDirection (strategie->ShootDirection());
		a_deplace_ver = true;
		Pause();
	}
}	
	
void Computer::ComAim()
{
	if (strategie->ChosenWeapon() != EquipeActive().LitTypeArme())
	{
		EquipeActive().ChangeArme(strategie->ChosenWeapon());
		Pause();		
	}
	
	int angle_viseur;
	double angleRad = EquipeActive().viseur.LitAngle();
	if (VerActif().LitDirection() == -1) 
		angle_viseur = static_cast<int>(InverseAngle(angleRad)*180.0/M_PI);
	else
		angle_viseur = static_cast<int>(angleRad*180.0/M_PI);
	int diff_angle = strategie->ChosenAngle() - angle_viseur;	
	
	if (AbsReel(diff_angle) <= 1)
	{
		a_vise = true;
		Pause();
	}
	else
	{
		int delta;
		if (diff_angle > 0.0)
			delta = +1;
		else
			delta = -1;
		EquipeActive().viseur.ChangeAngle(delta);
	}
}

void Computer::ComShoot()
{	
	EquipeActive().AccesArme().Tire ();
	a_tire = true;
	// Pause(); // pas de pause s'il faut se cacher
}

void Computer::ComMoveEndTurn()
{
	if (   (strategie->EndTurnPosition().x == VerActif().LitX())
		&& (strategie->EndTurnPosition().y == VerActif().LitY()))
	{
		a_planque_ver = true;
	}
	// else : deplacer ver (à faire).
}
/******************************************************************************
 *  Wormux, a free clone of the game Worms from Team17.
 *  Copyright (C) 2001-2004 Lawrence Azzoug.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 ******************************************************************************
 * Gestion de la stratégie de l'intelligence artificielle.
 *****************************************************************************/

#ifndef STRATEGIE_H
#define STRATEGIE_H

#include "../team/character.h"
#include "../weapon/weapon.h"


class Strategy
{
	public:
		virtual void Compute() = 0;
		virtual ~Strategy() { };
		Ver * ChosenWorm() const 
			{return verchoisi;}
		type_arme ChosenWeapon() const 
			{return armechoisie;}
		ObjPhysique::VecteurDouble ShootPosition() const 
			{return positiontir;}
		int ShootDirection() const
			{return direction;}
		ObjPhysique::VecteurDouble EndTurnPosition() const
			{return positionfintour;}
		int ChosenAngle() const
			{return angle;}
		int ChosenForce() const
			{return force;}
	protected:
		Ver * verchoisi;
		type_arme armechoisie;
		ObjPhysique::VecteurDouble positiontir;
		ObjPhysique::VecteurDouble positionfintour;
		int angle;
		int force;
		int direction;
	
		Ver * NearestEnemy(Ver * mon_ver = NULL);
		Ver * WormNearestOfEnemy(Equipe * mon_equipe = NULL);
		void Aims(const Ver *);
};

class StrategyGun : public Strategy
{
	public:
		StrategyGun();
		void Compute();
};

#endif //STRATEGIE_H
/******************************************************************************
 *  Wormux, a free clone of the game Worms from Team17.
 *  Copyright (C) 2001-2004 Lawrence Azzoug.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 ******************************************************************************
 * Gestion de l'intelligence artificielle
 *****************************************************************************/

#include "strategy.h"

#include "../tool/math_tools.h"
#include "../team/teams_list.h"
#include "../tool/random.h"
#include "../team/macro.h"
#include "../tool/geometry_tools.h"
#include "../map/map.h"

#include <math.h>

/*******************************************************************/
/*                  FONCTIONS GENERIQUES                           */
/*******************************************************************/

Ver * Strategy::NearestEnemy(Ver * mon_ver)
{
	if (mon_ver == NULL)
	{
		// Base du calcul : le ver actif.
		mon_ver = verchoisi;
	}
	
	/* Calcule la distance max. entre deux vers */
	double distance_min = 
		sqrt(static_cast<double>(monde.LitLarg() * monde.LitLarg() + 
								 monde.LitHaut() * monde.LitHaut()));
	
	Ver * le_plus_proche = NULL;
	
	POUR_TOUS_VERS_VIVANTS(equipe, ver)
	{
		if (*equipe != & (EquipeActive()))
		{
			double distance = Distance(ver->LitPos(), mon_ver->LitPos());
			if (distance < distance_min)
			{
				distance_min = distance;
				le_plus_proche = &*ver;
			}
		}
	}
	
	assert (le_plus_proche != NULL);
	return le_plus_proche;
}

Ver * Strategy::WormNearestOfEnemy(Equipe * mon_equipe)
{
	if (mon_equipe == NULL)
	{
		// Si l'équipe n'est pas spécifiée : équipe active
		mon_equipe = &(EquipeActive());
	}
	
	double distance_min = 
		sqrt(static_cast<double>(monde.LitLarg() * monde.LitLarg() + 
								 monde.LitHaut() * monde.LitHaut()));
	
	Ver * le_plus_proche_d_un_ennemi = NULL;
	
	POUR_CHAQUE_VER_VIVANT(mon_equipe, ver)
	{
		Ver * plus_proche_ennemi = NearestEnemy(&*ver);
		double distance = Distance(ver->LitPos(), plus_proche_ennemi->LitPos());
		if (distance < distance_min)
		{
			distance_min = distance;
			le_plus_proche_d_un_ennemi = &*ver;
		}
	}
	assert (le_plus_proche_d_un_ennemi != NULL);
	return le_plus_proche_d_un_ennemi;
}

void Strategy::Aims(const Ver * ver_vise)
{
	double angleRad = CalculeAngle(verchoisi->LitPos(), ver_vise->LitPos());
	if ((angleRad > M_PI/2.0) || (angleRad < -M_PI/2.0))
	{
		angleRad = InverseAngle(angleRad);
		direction = -1;
	} 
	else 
	{
		direction = 1;
	}
	angle = static_cast<int>(180.0*angleRad/M_PI);
}

/*******************************************************************/
/*                STRATEGIE PISTOLET                               */
/*******************************************************************/

StrategyGun::StrategyGun()
{
	verchoisi = NULL;
	armechoisie = armePISTOLET; 
	positiontir.x = -1;
	positiontir.y = -1;
	positionfintour.x = -1;
	positionfintour.y = -1;
	angle = 0;
	force = 0;
}

void StrategyGun::Compute()
{
	verchoisi = WormNearestOfEnemy();
	// armechoisie : toujours armePISTOLET
	positiontir.x = verchoisi->LitX();
	positiontir.y = verchoisi->LitY();
	Ver * plus_proche_ennemi = NearestEnemy();

	Aims(plus_proche_ennemi);

	force = 0;
	
	positionfintour.x = verchoisi->LitX();
	positionfintour.y = verchoisi->LitY();		
}

Répondre à