import java.util.Random;
import java.util.Scanner;

/**
 * Created by zulupero on 02/12/15.
 */

public class JeuVie {
    static final Scanner input = new Scanner(System.in);
    static final Random rand = new Random();

    enum Cell{DEAD, ALIVE}
    int size ;
    Cell[][] ecosysteme ;
    int[][] voisines ;

    /**
     * Constructeur d'un jeu de la vie de taille n.
     * Initialisé avec nxn cellules dont p% sont vivantes
     * @param n la taille du coté de l'écosystème
     */
    public JeuVie(int n, double p){
        size = n;
        ecosysteme = new Cell[n][n];
        voisines = new int[n][n];
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++){
                if( tireProba(p) )
                    ecosysteme[i][j] = Cell.ALIVE ;
                else
                    ecosysteme[i][j] = Cell.DEAD ;
            }
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++){
                voisines[i][j] = nbVoisines(i, j);
            }
    }

    /**
     * Renvoie vrai avec une probabilité p
     * @param p la probabilité de tirage vrai souhaitée
     * @return  le tirage vrai ou faux
     */
    public boolean tireProba(double p){
        if(rand.nextDouble() < p)
            return true ;
        return false ;
    }

    /**
     * trace la grille à raison d'un point par cellule
     */
    public void dispEco(){
        StdDraw.clear();
        StdDraw.setPenColor(StdDraw.RED);
        for(int i=0; i<size; i++)
            for(int j=0; j<size; j++) {
                if (ecosysteme[i][j] == Cell.ALIVE)
                    StdDraw.filledCircle(j + 0.5, (size - 1 - i) + 0.5, 0.5);
            }
        if (size < 30){
            StdDraw.setPenColor(StdDraw.LIGHT_GRAY);
            for(int i=0; i<size; i++)
                for(int j=0; j<size; j++)
                    StdDraw.text(j + 0.5, (size - 1 - i) + 0.5, String.valueOf(voisines[i][j]));
            }
    }

    /**
     * Calcule le nb de voisines vivantes
     * @param i ligne
     * @param j colonne
     * @return nb de voisines vivantes
     */
    public int nbVoisines(int i, int j){
        int vois = 0;
        int ic ;
        int jc ;
        for(int k=i-1; k<= i+1; k++) {
            ic = (k + size)%size;
            for (int l = j-1; l<= j+1; l++) {
                jc = (l+size)%size;
                if (((ic != i) || (jc != j)) && (ecosysteme[ic][jc] == Cell.ALIVE))
                    vois++;
            }
        }
        return vois ;
    }

    /**
     * Effectue une itération sur le tableau de cellules
     * et renvoie le nombre total de chengements d'états
     * @return le nombre de cellules dont l'état a changé en une génération
     */
    public int nextGen() {
        int changes = 0;

        for (int i = 0; i < size; i++)
            for (int j = 0; j < size; j++)
                voisines[i][j] = nbVoisines( i, j);

        for (int i = 0; i < size; i++)
            for (int j = 0; j < size; j++) {
               if(nextState(i,j) != ecosysteme[i][j]) {
                   ecosysteme[i][j] = nextState(i, j);
                   changes++;
               }

            }
        return changes ;
    }

    /**
     * Détermine l'état d'une cellule à la prochaine génération
     * @param i ligne de la cellule
     * @param j colonne de la cellule
     * @return le prochain état de la cellule
     */
    public Cell nextState(int i, int j){
        int nbVoisines = voisines[i][j];
        Cell nextState = ecosysteme[i][j];
        if ( nbVoisines == 3 && ecosysteme[i][j] == Cell.DEAD)
            nextState = Cell.ALIVE;
        else if (nbVoisines !=2 && nbVoisines !=3 && ecosysteme[i][j] == Cell.ALIVE)
            nextState = Cell.DEAD;
        return nextState;
    }

    public static void main(String[] args) {
        int n;
        int nb ;
        int gen =0;
        int cpt;
        int ch;
        final double proba = 0.5 ;
        System.out.println("Taille de l'ecosystème : ");
        n = input.nextInt();

        StdDraw.setScale(0, n);

        JeuVie jeu = new JeuVie(n,proba) ;
        jeu.dispEco();


        do{
            System.out.println("Évolution après combien de cycles ? (1 = pas à pas)");
            nb = input.nextInt();
            cpt =0 ;
            do{
                ch=jeu.nextGen();
                gen++ ;
                cpt++ ;
            } while (cpt < nb && ch!=0);
            jeu.dispEco();
            System.out.println("Génération n°"+(gen+1) + ", diff avec gen "+gen+" : "+ch);
        } while (nb != -1 && ch !=0);
    }
}
