Dal C al C++/Gioco life di Conway: differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
Annullata la modifica 300533 di 151.42.13.92 (discussione)
Nessun oggetto della modifica
Riga 1:
#include <iostream>
{{Dal C al C++}}
#include <cstdlib>
Di seguito il listato in C++ per un'implementazione testuale del gioco della vita.
#include <vector>
#include <set>
#include<ctime>
//Ho usato quasi solo funzioni "void" perché sono mooolto più belle e perché le funzioni "normali" sono sopravvalutate.
 
using std::cout;//Questi 4 "using std::..." servono a fare le cose che fa un programma normalmente, potevamo usare
{{Interprogetto|w=Gioco della vita|w_etichetta=Gioco della vita}}
//il semplice "using namespace std" ma così sembra più complicato.
 
using std::cin;
Paradigmi utilizzati:
using std::dec;
*[[w:Design pattern|Design pattern]]: [[w:observer pattern|observer pattern]]
using std::hex;
 
/*Ho provato a dare dei nomi a tutte le funzioni e variabili che aiutani la spiegazione di ciò che succede all'iterno di tale funzione
<source lang="cpp">
o a cosa serve tale variabile, molti sono in inglese perché sono più brevi in inglese e perché l'inglese è una lingua più bella.*/
// Author: BlakWolf, © 2004
// Released under GPL v.2 or later, at your option
#include <iostream>
#include <cstdlib>
#include <vector>
#include <set>
// Osservabile e osservato contemporaneamente :D, gestisce le regole "biologiche"
using std::cout;
class Casella{
using std::cin;
public: //accessibili dall’esterno e in ogni punto del programma.
using std::dec;
enum stato{vuoto=0,pieno}; //Questa è una enumerazioni, essa è esattamente come i tipi fondamentali e composti, un altro "tipo"
using std::hex;
//essa nello specifico tratta solo valori che possono essere assunti da una variabile enumerazione e questi
//sono ristretti ad un insieme di valori interi costanti, ad ognuno dei quali viene associato un nome.
typedef std::set<Casella *> Container; //Typedef ha come scopo quello di semplificare la vita, esso infatti,
//a differenza di una dichiarazione standard troppo fastidiosa, riesce a rendere il codice moooolto più riutilizzabile
//tra un'implementazione e un'altra.
typedef Container::iterator Iterator;
private: //utilizzabili soltanto all’interno della classe stessa.
// Osservabile e osservato contemporaneamente, gestisce le regole "biologiche"
stato stato_;
class Casella{
int vicini_futuri;
public:
int vicini;
enum stato{vuoto=0,pieno};
Container osservatori;
typedef std::set<Casella *> Container;
typedef Container::iterator Iterator;
public:
private:
Casella( const Casella::stato & s = Casella::vuoto ) //const non ha bisogno di essere spiegato.
stato stato_;
: intstato_(s), vicini_futuri;(0), vicini(0){}
int vicini;
Container osservatori;
//non copia gli osservatori
public:
Casella( const Casella::stato & s = Casellac)::vuoto vicini(c.vicini) ,
: stato_(s), vicini_futuri(0c.vicini_futuri), vicinistato_(0c.stato_){}
virtual ~Casella(){} //Virtual è un pò più difficile da spiegare...è anche questa come int, double, typedef, enum un "tipo" di dichiarazione
//virtual però è diferso dagli altri tipi di dichiarazioni poichè consente di condizionare l’esecuzione del codice
//non copia gli osservatori
//secondo il tipo dell’istanza oggetto cui si fa riferimento. Scusi se non è molto chiaro ma non ho idea di come spiegarlo...
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) { //Riguardo ad "inline" non sono ancora sicuro cosa faccia, ma credo aumenti le prestazioni...
//ma ripeto che non sono sicurissimo su questo fatto, scusi se non sono ferrato ma me l'ha consigliato di usare un amico.
if (&c != this){
if (&c != this){ //this identifica un puntatore speciale che contiene l’indirizzo dell’istanza della classe
osservatori.insert(&c);
//che }ha invocato il metodo.
osservatori.insert(&c);
}
}
}
inline void Imposta(const Casella::stato& s){
stato_=s;
}
inline void Muori(){
if(stato_==pieno){
Imposta(Casella::vuoto);
Notifica(-1);//Utile per la notifica, vedi dopo.
}
}
}
inline void Nasci() {
if (stato_==vuoto){
Imposta(Casella::pieno);
Notifica(1);//Utile per la notifica, vedi dopo.
}
}
// 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){ //A fare sta parte ci ho messo 2 giorni.
(*it)->RiceviNotifica(msg);//Per questa infatti mi sono dovuto studiare una libreria intera.
}
}
// Ricevi la notifica dai vicini
inline void RiceviNotifica(int msg) {
vicini_futuri += msg; //Stessa cosa per sta dannata parte
}
};
// Contenitore di caselle, che genera automaticamente le corrispondenze tra vicini.
// Gestisce le regole "topologiche" --> termine preso da wikipedia
class Griglia{
public:
typedef std::vector<Casella> Container;
typedef Container::iterator Iterator;
private: //utilizzabili soltanto all’interno della classe stessa.
private:
int righe_;
int colonne_;
int time;
Container griglia;
public: //accessibili dall’esterno e in ogni punto del programma.
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(){ //Scusi se questa parte è un poco incasinata ma non avevo trovato modi per scrivere più "ristretto"
inline void Genera(){
//e comunque in un modo "chiaro e capibile".
bool primo, ultimo;
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"; //ne abbiamo messi 2 per bellezza
cout << "+--------------------+\n|";
for (int indice=0;indice < 400;++indice){ //Caratteri.
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(); //Comando che è stra utile poichè registra la pressione del tasto, e quindi è stra utile.
cin.get();
}
// Mai raggiunto
return 0;
}
</source>
 
[[Categoria:Dal C al C++|Gioco life di Conway]]
{{Avanzamento|100%|3 gennaio 2008}}