Le cas 4, « système à forte dynamique, modèle par arbre d'exécution », tel que proposé dans vos notes de cours, se présente comme suit.
class Bonhomme;
struct AffecterBonhomme;
#include "Mutex.h"
#include "Incopiable.h"
#include <algorithm>
#include <vector>
#include <memory>
class Population
: Incopiable
{
std::vector<std::shared_ptr<Bonhomme>> individus_;
Population()
{ }
Mutex mutex_;
public:
void inscrire(std::shared_ptr<Bonhomme> p)
{
Autoverrou av(mutex_);
individus_.push_back(p);
}
void desinscrire(std::shared_ptr<Bonhomme> p)
{
Autoverrou av(mutex_);
using std::find;
using std::begin;
using std::end;
auto itt = find(begin(individus_), end(individus_), p);
if (itt != end(individus_))
individus_.erase(itt);
}
static Population &get()
{
static Population singleton;
return singleton;
}
template <class Pred>
std::shared_ptr<Bonhomme> trouver(Pred);
void agir_sur_survivant(AffecterBonhomme &);
void afficher_etat() const;
void apocalypse() throw()
{
Autoverrou av(mutex_);
individus_.clear();
}
};
#include <string>
#include <sstream>
template <class T>
std::string ttos(const T &val)
{
using std::stringstream;
stringstream sstr;
sstr << val;
return sstr.str();
}
#include "Autonome.h"
class Bonhomme
: public Acteur
{
enum { VIE_DEFAUT = 10 };
int vie_;
public:
typedef std::string str_type;
private:
const str_type nom_;
void agir()
{ if (est_vivant()) agir_impl(); }
protected:
virtual void agir_impl() = 0;
public:
Bonhomme(const str_type &nom, const int vie = VIE_DEFAUT)
: vie_(vie), nom_(nom)
{
}
virtual bool peut_blesser() const throw()
{ return true; }
void blesser(const int degats) throw()
{ vie_ -= degats; }
void soigner(const int soins) throw()
{ vie_ += soins; }
int vie() const throw()
{ return vie_; }
str_type nom() const
{ return nom_; }
bool est_vivant() const throw()
{ return vie() > 0; }
bool est_mort() const throw()
{ return !est_vivant(); }
virtual str_type descriptif() const
{ return nom() + " (" + ttos(vie()) + ")"; }
};
struct AffecterBonhomme
{
virtual void operation(std::shared_ptr<Bonhomme>) = 0;
virtual ~AffecterBonhomme() throw()
{ }
};
class SoignerBonhomme
: public AffecterBonhomme
{
const int soins_;
public:
SoignerBonhomme(const int soins)
: soins_(soins)
{
}
virtual bool peut_blesser() const throw()
{ return false; }
int soins() const throw()
{ return soins_; }
void operation(std::shared_ptr<Bonhomme> b)
{ b->soigner(soins()); }
};
class BlesserBonhomme
: public AffecterBonhomme
{
const int degats_;
public:
BlesserBonhomme(const int degats)
: degats_(degats)
{
}
int degats() const throw()
{ return degats_; }
void operation(std::shared_ptr<Bonhomme> b)
{ b->blesser(degats()); }
};
template <class Pred>
std::shared_ptr<Bonhomme> Population::trouver(Pred pred)
{
using std::shared_ptr;
using std::begin;
using std::end;
using std::find_if;
Autoverrou av(mutex_);
auto itt = find_if(begin(individus_), end(individus_), pred);
return itt != end(individus_)? *itt : 0;
}
#include <iterator>
void Population::agir_sur_survivant(AffecterBonhomme &ab)
{
using std::vector;
using std::back_inserter;
using std::copy_if;
using std::remove_if;
using std::random_shuffle;
using std::shared_ptr;
vector<shared_ptr<Bonhomme>> v;
{
Autoverrou av(mutex_);
copy_if(begin(individus_), end(individus_), back_inserter(v), [](shared_ptr<Bonhomme> b) {
return b->est_vivant();
});
}
if (v.empty()) return;
random_shuffle(begin(v), end(v));
ab.operation(v.front());
}
#include <iostream>
void Population::afficher_etat() const
{
using std::begin;
using std::end;
using std::cout;
using std::endl;
using std::for_each;
using std::shared_ptr;
Autoverrou av(mutex_);
for_each(begin(individus_),end(individus_), [](shared_ptr<Bonhomme> b) {
if (b->est_vivant()) cout << b->descriptif() << ", ";
});
cout << endl<< endl;
}
#include <cstdlib>
class Tireur
: public Bonhomme
{
Tireur(const str_type &nom)
: Bonhomme(nom)
{
}
public:
static std::shared_ptr<Bonhomme> creer(const str_type &nom)
{ return std::shared_ptr<Bonhomme>(new Tireur(nom)); }
private:
void agir_impl()
{
using std::rand;
const int BOBO = rand() % 5 + 1;
Population::get().agir_sur_survivant(BlesserBonhomme(BOBO));
}
public:
str_type descriptif() const
{ return str_type("Tireur: ") + Bonhomme::descriptif(); }
};
class Soigneur
: public Bonhomme
{
Soigneur(const str_type &nom)
: Bonhomme(nom)
{
}
public:
static std::shared_ptr<Bonhomme> creer(const str_type &nom)
{ return std::shared_ptr<Bonhomme>(new Soigneur(nom)); }
private:
bool peut_blesser() const throw()
{ return false; }
void agir_impl()
{
using std::rand;
const int OUF = rand() % 3 + 1;
Population::get().agir_sur_survivant(SoignerBonhomme(OUF));
}
public:
str_type descriptif() const
{ return str_type("Soigneur: ") + Bonhomme::descriptif(); }
};
class Surveillant
: public Autonome
{
enum { SUSPENS_SURVEILLANT = 1000 };
Surveillant()
: Autonome(SUSPENS_SURVEILLANT)
{
}
public:
static std::unique_ptr<Surveillant> creer()
{
using std::unique_ptr;
unique_ptr<Surveillant> p(new Surveillant);
p->demarrer();
return p;
}
void agir ()
{
Population::get().afficher_etat();
using std::cout;
using std::endl;
using std::shared_ptr;
auto survivant = [](shared_ptr<Bonhomme> b) {
return b->est_vivant();
};
auto tireur = [](shared_ptr<Bonhomme> b) {
return b->est_vivant() && b->peut_blesser();
};
if (!Population::get().trouver(survivant))
{
cout << "Ce fut un carnage..." << endl;
demander_arret();
}
else if (!Population::get().trouver(tireur))
{
cout << "Il ne reste que des soigneurs!" << endl;
demander_arret();
}
}
};
class StrateInvalide {};
class ObjetInvalide {};
class ObjetIntrouvable {};
#include <vector>
#include <cmath>
#include <cassert>
#include <array>
template <int B, int E>
struct puissance
{
enum { VAL = B * puissance<B, E-1>::VAL };
};
template <int B>
struct puissance<B,0>
{
static_assert(B!=0, "0^0 est indéfini");
enum { VAL = 1 };
};
template <int Prof>
class Moteur
: public Autonome
{
class StrateBase
{
std::vector<std::shared_ptr<Acteur>> acteurs_;
Mutex mutex_;
public:
void abonner(std::shared_ptr<Acteur> p)
{
if (!p) throw ObjetInvalide();
Autoverrou av(mutex_);
acteurs_.push_back(p);
}
void desabonner(std::shared_ptr<Acteur> p)
{
if (!p) throw ObjetInvalide();
using std::find;
Autoverrou av(mutex_);
auto itt = find(begin(acteurs_), end(acteurs_), p);
if (itt != end(acteurs_)) acteurs_.erase(itt);
}
void operer()
{
using std::begin;
using std::end;
using std::for_each;
using std::shared_ptr;
Autoverrou av(mutex_);
for_each(begin(acteurs_), end(acteurs_), [](shared_ptr<Acteur> p) {
p->agir();
});
}
};
template <int N>
class Strate
: StrateBase
{
std::array<Strate<N-1>, puissance<2,Prof-N>::VAL> enfants_;
public:
typedef typename
std::array<Strate<N-1>, puissance<2,Prof-N>::VAL>::size_type size_type;
private:
size_type cur_;
public:
Strate()
: cur_(size_type())
{
}
void abonner(std::shared_ptr<Acteur> p, int strate)
{
if (strate)
enfants_[rand() % enfants_.size()].abonner(p, strate - 1);
else
StrateBase::abonner(p);
}
void desabonner(std::shared_ptr<Acteur> p, int strate)
{
if (strate)
{
using std::for_each;
using std::begin;
using std::end;
for_each(begin(enfants_), end(enfants_), [&](Strate &s) {
s.desabonner(p, strate - 1);
});
}
else
StrateBase::desabonner(p);
}
void operer()
{
StrateBase::operer();
enfants_[cur_].operer();
cur_ = (cur_ + 1) % enfants_.size();
}
};
template <>
class Strate<0>
: StrateBase
{
public:
void abonner(std::shared_ptr<Acteur> p, int strate)
{
if (strate) throw StrateInvalide();
StrateBase::abonner(p);
}
void desabonner(std::shared_ptr<Acteur> p, int strate)
{
if (strate) throw StrateInvalide();
StrateBase::desabonner(p);
}
using StrateBase::operer;
};
Strate<Prof> strates_;
Moteur(const std::vector<std::pair<std::shared_ptr<Acteur>, int>> &acteurs)
: Autonome(500)
{
using std::begin;
using std::end;
using std::for_each;
using std::pair;
using std::shared_ptr;
for_each(begin(acteurs), end(acteurs), [&](pair<shared_ptr<Acteur>,int> acteur) {
strates_.abonner(acteur.first, acteur.second);
});
}
public:
void abonner(std::shared_ptr<Acteur> p, const int strate)
{
assert(strate >= 0);
strates_.abonner(p, strate);
}
void desabonner(std::shared_ptr<Acteur> p, const int strate)
{
assert(strate >= 0);
strates_.desabonner(p);
}
static std::unique_ptr<Moteur> creer(const std::vector<std::pair<std::shared_ptr<Acteur>, int>> &acteurs)
{
using std::unique_ptr;
unique_ptr<Moteur> p(new Moteur(acteurs));
p->demarrer();
return p;
}
void agir()
{ strates_.operer(); }
};
int main()
{
using std::srand;
using std::time;
using std::shared_ptr;
using std::vector;
using std::pair;
using std::make_pair;
srand(static_cast<unsigned int>(time(0)));
const int NB_BONSHOMMES = 20;
const Bonhomme::str_type NOMS[] =
{
"Adele", "Bob", "Chuck", "Diane", "Ed",
"Fred", "Gus", "Ida", "Jack", "Ken"
};
enum { NB_NOMS = sizeof(NOMS)/sizeof(*NOMS) };
vector<pair<shared_ptr<Acteur>, int>> v;
for (int i = 0; i < NB_BONSHOMMES; ++i)
{
auto nom = NOMS[i % NB_NOMS] + " " + ttos(i);
shared_ptr<Bonhomme> p;
if (rand() % 4 != 0)
{
p = Tireur::creer(nom);
v.push_back(make_pair(p,1));
Population::get().inscrire(p);
}
else
{
p= Soigneur::creer(nom);
v.push_back(make_pair(p,2));
Population::get().inscrire(p);
}
}
auto moteur = Moteur<4>::creer(v);
auto surveillant = Surveillant::creer();
surveillant->attendre_fin();
}
Sur mon petit ordinateur portatif, compilé avec Visual Studio 2010, configuration Release, et en prenant bien entendu soin d'ajouter _SECURE_SCL=0 aux options du préprocesseur pour désactiver les (franchement inutiles et nuisibles) Checked Iterators, j'obtiens évidemment plusieurs résultats, comme par exemple :
Tireur: Adele 0 (10), Tireur: Bob 1 (10), Soigneur: Chuck 2 (10), Tireur: Diane
3 (10), Tireur: Ed 4 (10), Soigneur: Fred 5 (10), Tireur: Gus 6 (10), Soigneur:
Ida 7 (10), Soigneur: Jack 8 (10), Tireur: Ken 9 (10), Soigneur: Adele 10 (10),
Tireur: Bob 11 (10), Tireur: Chuck 12 (10), Tireur: Diane 13 (10), Tireur: Ed 14
(10), Tireur: Fred 15 (10), Tireur: Gus 16 (10), Tireur: Ida 17 (10), Soigneur:
Jack 18 (10), Tireur: Ken 19 (10),
Tireur: Bob 1 (10), Soigneur: Chuck 2 (7), Tireur: Diane 3 (6), Tireur: Ed 4 (2)
, Soigneur: Fred 5 (1), Tireur: Gus 6 (6), Soigneur: Jack 8 (6), Tireur: Ken 9 (
9), Soigneur: Adele 10 (10), Tireur: Bob 11 (8), Tireur: Chuck 12 (4), Tireur: D
iane 13 (6), Tireur: Ed 14 (6), Tireur: Fred 15 (3), Tireur: Gus 16 (7), Tireur:
Ida 17 (10), Soigneur: Jack 18 (10), Tireur: Ken 19 (10),
Tireur: Bob 1 (4), Tireur: Diane 3 (6), Soigneur: Fred 5 (1), Soigneur: Jack 8 (
6), Tireur: Ken 9 (3), Soigneur: Adele 10 (8), Tireur: Bob 11 (8), Tireur: Diane
13 (10), Tireur: Ed 14 (5), Tireur: Fred 15 (3), Tireur: Gus 16 (6), Tireur: Id
a 17 (2), Soigneur: Jack 18 (7),
Tireur: Diane 3 (6), Soigneur: Fred 5 (1), Soigneur: Jack 8 (8), Tireur: Ken 9 (
2), Soigneur: Adele 10 (6), Tireur: Diane 13 (10), Tireur: Fred 15 (5), Tireur:
Gus 16 (6),
Soigneur: Fred 5 (4), Soigneur: Jack 8 (5), Soigneur: Adele 10 (5), Tireur: Dian
e 13 (10), Tireur: Gus 16 (4),
Soigneur: Jack 8 (5), Tireur: Diane 13 (9), Tireur: Gus 16 (5),
Soigneur: Jack 8 (4), Tireur: Diane 13 (1), Tireur: Gus 16 (6),
Tireur: Gus 16 (4),
Ce fut un carnage...
Appuyez sur une touche pour continuer...