| Lista Articoli: [1-D] [D-P] [P-Z] | Lista Categorie | Lista Directory | Una pagina a caso | Puntano qui | ||||||
Il gioco della vita (Life) fu sviluppato dal matematico John Conway sul finire degli anni 1960, con lo scopo di mostrare come comportamenti simili alla vita possono emergere da regole semplici e interazioni a molti corpi, principio che è alla base dell'ecobiologia, la quale si rifà anche alla teoria della complessità. Del gioco sono poi state sviluppate versioni con differenti topologie, ad esempio tridimensionali, come in questo sito (http://www.ibiblio.org/e-notes/Life/Game.htm), anche per Matlab (http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=4892&objectType=file), differenti regole biologiche, e differenti tipi di cellule.
| Indice |
Le regole del gioco sono molto semplici:
Regole topologiche
Regole biologiche
Tutte le modifiche avvengono contemporaneamente in tutto il mondo: possiamo insomma dire che è passata una "generazione".
Di seguito il listato in C++ per un'implementazione testuale del gioco della vita. A destra, un'immagine di una versione grafica. La versione sotto riportata è rilasciata sotto GPL versione 2 o superiore.
Paradigmi utilizzati:
// Author: BlakWolf, © 2004
// Released under GPL v.2 or later, at your option
#include <iostream>
#include <cstdlib>
#include <vector>
#include <set>
using std::cout;
using std::cin;
using std::dec;
using std::hex;
// Osservabile e osservato contemporaneamente, gestisce le regole "biologiche"
class Casella{
public:
enum stato{vuoto=0,pieno};
typedef std::set<Casella *> Container;
typedef Container::iterator Iterator;
private:
stato stato_;
int vicini_futuri;
int vicini;
Container osservatori;
public:
Casella( const Casella::stato & s = Casella::vuoto )
: stato_(s), vicini_futuri(0), vicini(0){}
//non copia gli osservatori
Casella(const Casella& c): vicini(c.vicini),
vicini_futuri(c.vicini_futuri), stato_(c.stato_){}
virtual ~Casella(){}
// Registra gli osservatori a cui notificare i cambiamenti
inline void Registra(Casella& c) {
if (&c != this){
osservatori.insert(&c);
}
}
inline void Imposta(const Casella::stato& s){
stato_=s;
}
inline void Muori(){
if(stato_==pieno){
Imposta(Casella::vuoto);
Notifica(-1);
}
}
inline void Nasci() {
if (stato_==vuoto){
Imposta(Casella::pieno);
Notifica(1);
}
}
// Aggiorna
inline void Ciclo() {
vicini=vicini_futuri;
}
// Regole del gioco
inline void Verifica() {
if (stato_==pieno){
if (vicini<2 || vicini>3) // Modificare questa riga per cambiare le regole di morte
Muori();
}else {
if (vicini==3) // Modificare questa riga per cambiare le regole di nascita
Nasci();
}
}
inline bool Leggi() const{
return stato_==pieno;
}
private:
// Notifica ai vicini nascita o morte
inline void Notifica(int msg) const{
for (Iterator it = osservatori.begin(); it != osservatori.end(); ++it){
(*it)->RiceviNotifica(msg);
}
}
// Ricevi la notifica dai vicini
inline void RiceviNotifica(int msg) {
vicini_futuri += msg;
}
};
// Contenitore di caselle, che genera automaticamente le corrispondenze tra vicini.
// Gestisce le regole "topologiche"
class Griglia{
public:
typedef std::vector<Casella> Container;
typedef Container::iterator Iterator;
private:
int righe_;
int colonne_;
Container griglia;
public:
virtual ~Griglia(){}
Griglia(const int& righe, const int& colonne)
:righe_(righe), colonne_(colonne) {
if (righe_ < 5) righe_=5;
if (colonne_ < 5) righe_=5;
griglia.reserve(righe_*colonne_);
griglia.resize(righe_*colonne_);
}
inline Casella& operator[](const int n) {
return griglia[n];
}
inline void Cicla() {
for (int i = 0; i < righe_*colonne_;++i)
griglia[i].Ciclo();
}
void Verifica(){
for (int i = 0; i < righe_*colonne_;++i)
griglia[i].Verifica();
}
inline void Imposta (const int& pos) {
if ((pos >=0)&&(pos < griglia.size()))
griglia[pos].Nasci();
}
inline void Resetta (const int& pos) {
if ((pos >=0)&&(pos < griglia.size()))
griglia[pos].Muori();
}
// Modificare questa routine per cambiare le regole topologiche di vicinanza
inline void Genera(){
bool primo, ultimo;
for (int indice=0; indice< righe_*colonne_;++indice){
primo = ( (indice%colonne_) == 0);
ultimo = ( (indice%colonne_) == colonne_-1);
if (indice > colonne_){
if (!primo)
griglia[indice].Registra(griglia[indice-colonne_ - 1]);
griglia[indice].Registra(griglia[indice-colonne_]);
if (!ultimo)
griglia[indice].Registra(griglia[indice-colonne_ + 1]);
}
if (!primo)
griglia[indice].Registra(griglia[indice-1]);
if (!ultimo)
griglia[indice].Registra(griglia[indice+1]);
if (indice < ((colonne_)*(righe_-1)) ){
if (!ultimo)
griglia[indice].Registra(griglia[indice+colonne_+1]);
griglia[indice].Registra(griglia[indice+colonne_]);
if (!primo)
griglia[indice].Registra(griglia[indice+colonne_-1]);
}
}
}
inline const int Righe() const { return righe_; }
inline const int Colonne() const { return colonne_; }
};
//Stampa a schermo la griglia. Gestione statica delle dimensioni. Per variare, utilizzare griglia.Righe() e Colonne()
void Stampa( Griglia& g) {
cout << "\n\n";
cout << "+--------------------+\n|";
for (int indice=0;indice < 400;++indice){
bool ultimo = ( (indice%20) == 19);
g[indice].Leggi()?cout << "O":cout << " ";
if (ultimo){
if (indice !=399)
{cout << "|\n|";}
else
{cout << "|\n";}
}
}
cout << "+--------------------+\n";
}
int main () {
Griglia griglia(20,20) ;
griglia.Genera();
// Inizializza la griglia casualmente, con fattore di
// riempimento un ottavo.
// Gestione statica delle dimensioni. Per variare, utilizzare griglia.Righe() e Colonne()
srand(time(0));
for (int i=0; i < 100;++i){
griglia.Imposta((rand()>>4) %400);
}
while (1){
Stampa(griglia);
griglia.Cicla();
griglia.Verifica();
// Aspetta la pressione di enter
cin.get();
}
// Mai raggiunto
return 0;
}


