Concetti Chiave
- Il meccanismo di evoluzione biologica è simulato su una matrice dove ogni cella rappresenta un organismo.
- Gli organismi sopravvivono o muoiono in base al numero di vicini viventi, mentre nuovi organismi nascono con esattamente 3 vicini vivi.
- L'input iniziale degli organismi vivi può essere inserito manualmente o generato casualmente.
- La visualizzazione grafica della matrice utilizza asterischi per gli organismi viventi e spazi vuoti per le celle senza vita.
- La soluzione implementa due matrici per gestire le generazioni attuale e futura, scambiandole ad ogni iterazione per simulare l'evoluzione.
Un meccanismo biologico di evoluzione viene simulato supponendo che gli organismi che si considerano
occupino ciascuno una cella di una matrice di dimensioni pari a MAX righe e MAX colonne. Il meccanismo di
evoluzione è basato sulle seguenti regole che determinano il passaggio da una generazione alla successiva:
· un organismo sopravvive se nelle celle vicine ha 2 o 3 organismi viventi
· un organismo cessa di esistere se nelle celle vicine ha:
- 0 o 1 organismi viventi (solitudine) oppure
- da 4 a 8 organismi viventi (sovrappopolamento)
· un nuovo organismo nasce in una cella se nelle celle vicine coi sono 3 organismi viventi
Realizzare un pgm C in grado, a partire da una configurazione iniziale, di mostrare l'evoluzione della specie.
SPECIFICHE
1) Configurazione iniziale:
· Leggere da tastiera le coordinate dei soli elementi vivi.
· (in alternativa) Generazione casuale degli elementi vivi.
2) Visualizzazione configurazione iniziale e generazioni successive:
Tabella di caratteri dove:
· Un asterisco indica la presenza di un organismo vivente
· Uno spazio indica assenza di vita
ESEMPIO
L'evoluzione di una specie risulta alquanto interessante dal punto di vista grafico. Sia l'input il seguente
(indicante la posizione dei soli elementi vivi)
2 1
2 2
2 3
-1 -1
L'evoluzione della popolazione di organismi risulta la seguente (in cui si è evidenziato il contorno della
matrice):
Configurazione Prima E così via …..
Iniziale generazione:
####### #######
# # # #
# # # * #
# *** # # * #
# # # * #
# # # #
####### #######
IPOTESI DI SOLUZIONE:
La soluzione prevede che in ciascun istante vengano memorizzate due generazioni della specie: la generazione
attuale e quella futura. Con il passaggio da una generazione a quella successiva la generazione futura diviene
quella attuale e una nuova generazione viene valutata. Questo meccanismo può essere realizzato mediante l'uso
di due matrici che contengono due generazioni successive e che si "scambino di ruolo" ad ogni iterazione. Una
soluzione particolarmente elegante può essere realizzata attraverso l'utilizzo di una matrice a tre dimensioni:
#define STATO 2
#define MAX 5
int vita [STATO][MAX][MAX]; //var globale
Una variabile (stato nel programma ) indica che la generazione attuale si trova nella matrice anteriore e quella
futura nella matrice posteriore ( se stato è uguale a 0) e la situazione inversa (se stato vale 1).
La matrice contiene 1 se l'organismo corrispondente è vivo, 0 altrimenti.
Un ulteriore problema è la determinazione del numero di organismi vicini ad un organismo dato. Tale valore
può essere individuato, a partire dall'organismo nell'elemento (i,j), indicando gli offset, cioè gli scostamenti, sui
due indici.
i-1,j-1 i-1,j i-1,j+1
i,j-1 i,j i,j+1
i+1,j-1 i+1,j i+1,j+1
Tali offset (-1,0,+1) possono essere memorizzati in una coppia di vettori.
#define DIREZIONI 8
int scostX [DIREZIONI] = { 0, 1, 1, 1, 0, -1, -1, -1}; //var globale
int scostY [DIREZIONI] = { 1, 1 , 0, -1, -1, -1, 0, 1}; //var globale
int stato; //var booleana 0: stato attuale 1: stato futuro (locale alla funzione main())
Nel nostro caso quindi la var stato viene inizializzata a 0 (configurazione iniziale).
Individuazione dei sottopgm:
void insert(); //inserimento della configurazione iniziale
void visualizza(int stato); //visualizza una generazione (compresa la configurazione iniziale)
void aggiorna (int stato); // calcolo di una nuova generazione (sulla base degli elementi vicini
// e se la casella è viva o morta)
int vicini(int x,int y,int stato); // calcola il numero di vicini vivi all'elemento x,y
int viva(int x,int,y,int stato); //determina se una casella è viva: 1 viva, 0 morta
void azzera(int stato); // azzera la matrice relativa alla generazione futura
// preparandola a contenere nuovi dati
6
Il pgm quando termina?
Mai, ciclo infinito (di evoluzioni)
while(1)
{
…..
}
Domande da interrogazione
- Qual è il meccanismo di evoluzione degli organismi descritto nel testo?
- Come viene rappresentata la configurazione iniziale degli organismi?
- Qual è la struttura dati utilizzata per memorizzare le generazioni degli organismi?
- Come si determina il numero di organismi vicini a un dato organismo?
- Quando termina il programma descritto nel testo?
Il meccanismo di evoluzione si basa su regole che determinano la sopravvivenza, la morte o la nascita di organismi in base al numero di organismi viventi nelle celle vicine.
La configurazione iniziale può essere inserita manualmente tramite coordinate o generata casualmente, e viene visualizzata in una tabella di caratteri con asterischi per organismi viventi e spazi per assenza di vita.
Vengono utilizzate due matrici per memorizzare la generazione attuale e quella futura, che si scambiano di ruolo ad ogni iterazione. Una matrice tridimensionale può essere usata per una soluzione elegante.
Il numero di organismi vicini viene calcolato utilizzando offset memorizzati in due vettori che indicano gli scostamenti sui due indici della matrice.
Il programma non termina mai, poiché è progettato per eseguire un ciclo infinito di evoluzioni.