Home Page Preferiti
Lista Articoli: [1-D] [D-P] [P-Z] | Lista Categorie | Lista Directory | Una pagina a caso | Puntano qui

Gioco life di Conway


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.

Versione grafica del gioco della vita
Ingrandisci
Versione grafica del gioco della vita
Indice

Regole

Le regole del gioco sono molto semplici:

Regole topologiche

  1. Il mondo è una griglia di caselle quadrate
  2. Una cellula occupa una casella della griglia
  3. I vicini di una casella sono le otto caselle circostanti

Regole biologiche

  1. Se una cellula ha più di tre vicini muore (per soffocamento)
  2. Se una cellula ha meno di due vicini muore (per isolamento)
  3. Una casella vuota genera una cellula se ha esattamente tre vicini (per benessere)
  4. In ogni altro caso, nulla cambia

Tutte le modifiche avvengono contemporaneamente in tutto il mondo: possiamo insomma dire che è passata una "generazione".

Codice C++

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;
}

Vedi anche


Links esterni:





This site support the Wikimedia Foundation. This Article originally from Wikipedia. All text is available under the terms of the GNU Free Documentation License Page HistoryOriginal ArticleWikipedia