/*Applet du jeu de la vie
Copyright Amadeus mai 1998
theamadeus@chez.com
http://www.chez.com/theamadeus/index.html*/


import java.awt.*;
import java.applet.*;

/*--------- Lifegame : automate 
	la classe Lifegame simule un automate cellulaire dans un plan 10x10, 
       (dont les bords sont toujours vides)
-------------------------------------*/

public class Lifegame extends Applet implements Runnable {
// début de la classe principale
	static int N = 10; // taille du plan
	Cellule[][] plan = new Cellule[N][N];	// le plan 10x10 est composé de cellules


	//=============================================================
	// code de gestion de la tâche de séquencement des générations, à 4 Hz
	Thread tickTock; //tâche d'exécution pour rafraichir l'affichage

  public void start() {
		if (tickTock == null) {  tickTock = new Thread(this);  tickTock.start();  } }
 
	public void stop() {
		if (tickTock != null) {  tickTock.stop();  tickTock = null;  } }
 
	public void run() { // calculer indéfiniment, quatre générations par seconde
		while (true) {  try {  Thread.currentThread().sleep(250); }  // séquencement à 4 Hz
			catch (InterruptedException e) {}  
			super.repaint();  }   // pour affichage de l'automate
	}
	//=============================================================


	//========  init()   initialisations ===============================
	public void init() {
		int i,j;
		// créer un plan NxN de cellules vides
		for (i=0; i<N; i++)
			for (j=0; j<N; j++) {
				plan[i][j] = new Cellule(i, j, this.getGraphics());  }
				/*  new :   instancier un objet Cellule
							i,j :     aux coordonnées (i,j)
							false : cellule vide
        			getGraphics : initialiser le graphisme */
		// placer un motif de cellule occupées = génération initiale
		plan[5][4].creer();plan[5][5].creer(); plan[5][6].creer();
	} //fin d'init

	//=== update() passage d'une génération à la suivante =================
	public final synchronized void update (Graphics g) {
		g.setColor(Color.white); //rend la couleur blanche
		g.fillRect(0,0,20*N,20*N); //dessine le fond
		int i,j;
		// 1) afficher l'automate, ancienne génération
		for (i=0; i<N; i++)
			for (j=0; j<N; j++)
				plan[i][j].paint(); //affiche la cellule
		// 2) mémoriser l'état de l'ancienne génération
		for (i=0; i<N; i++)
			for (j=0; j<N; j++)
				plan[i][j].basculer();
		// 3) calculer le nouvel état de l'automate
		for (i=1; i<N-2; i++)      // on parcourt le plan en long
			for (j=1; j<N-2; j++) {  // et en large
				int voisinage=  //nombre de cellules occupées adjacentes au point (i,j)
								plan[i-1][j-1].etat()+plan[i-1][j].etat()+plan[i-1][j+1].etat()
								+plan[i][j-1].etat()+plan[i][j+1].etat()
								+plan[i+1][j-1].etat()+plan[i+1][j].etat()+plan[i+1][j+1].etat(); 
				plan[i][j].changementGeneration(voisinage); //détermine le nouvel état
			}
	}  // update()

} //fin de la classe principale Lifegame



/*--------- Cellule -----------------------------------------------
 la classe Cellule décrit les fonctionnalités d'une cellule de l'automate 
-----------------------------------------------------------------*/

class Cellule { 
	int x,y;                            //coordonées de la cellule dans l'automate
	boolean celluleOccupee;       // état de la cellule, true si occupée
	boolean ancienEtat;              // état de la cellule à la génération précédente
	private Graphics g;         //pour le graphisme

	//========  etat()   =========================================
	//retourne l'état de la cellule, 0 si vide, 1 si occupée
 	public int etat() { 
		int occupe=1;
		int vide=0;
		if (ancienEtat) 
			return occupe;  //retourne 1: la cellule est occupée
		else 
			return vide;      //retourne 0: la cellule est vide
	}  //etat()

	//========  basculer()  ======================================
	// changement de génération, mémoriser l'état de la cellule
 	public void basculer() { 
		ancienEtat = celluleOccupee;
	}

	//========  changementGeneration()   =========================
	public void changementGeneration (int nombreVoisins) {
		if (ancienEtat)  //cellule reste occupee si exactement 2 ou 3 voisins
				celluleOccupee = (nombreVoisins==2) || (nombreVoisins==3); 
		else    //naissance si exactement 3 voisins
				celluleOccupee = (nombreVoisins==3);
	}

	//========  Cellule()  =======================================
	//constructeur de cellule
	public Cellule(int x, int y, Graphics appletG) { 
		g=appletG;  //pour le graphisme
		this.x=x;
		this.y=y;
		this.celluleOccupee=false; // à la génèse le monde était vide
	}

	//========  creer()  ========================================
	// rendre la cellule occupée 
	public void creer () { 
		this.celluleOccupee=true;
	}

	//========  paint()  =============================================
	//graphisme : affichage de la cellule 
	public void paint(){ 
		int nx,ny;
		nx=15*x;
		ny=15*y;
		if (celluleOccupee) { //si cellule occupée
			g.setColor(Color.black); 
			g.fillOval(nx+1,ny+1,15-2,15-2); } //dessiner la cellule avec un cercle noir
		else { //si cellule vide
			g.setColor(Color.white); 
			g.fillRect(nx+1,ny+1,15-2,15-2);} //effacer la cellule avec un carré blanc
		}

} //fin de la classe Cellule



