Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Exercice] zCellular : un automate cellulaire !

15 décembre 2013 à 16:11:25

Bonjour et bonsoir à tous et à toutes.

Cet exercice a pour but de vous faire réaliser un petit automate cellulaire. Vous allez voir, c'est amusant !

zCellular

Un automate cellulaire, des automates cellulaires

Pour ceux qui auraient la flemme de lire le lien ci-dessus, voici une rapide explication du fonctionnement des automates cellulaires. Vous avez très certainement déjà entendu parlé du Jeu de la vie de Conway, et bien sachez que c'est en fait un simple automate cellulaire bidimensionnel. Celui que je vous propose d'implémenter est unidimensionnel, et encore plus simple. Un automate cellulaire évolue étapes par étapes selon quelques règles, telles que par exemple, pour le jeu de la vie :

  • Si la cellule est vivante et entourée par deux ou trois cellules vivantes, elle reste en vie à la génération suivante, sinon elle meurt ;
  • Si la cellule est morte et entourée par exactement trois cellules vivantes, elle naît à la génération suivante.

Ainsi, le nouvel état d'une cellule dépend de son état actuel, et de celui de ses voisins.

Voici maintenant la présentation de l'automate que vous allez implémenter. Supposons deux cellules vivantes (deux cases noires) et huit autres mortes (blanches), disposées ainsi en ligne :

Faisons maintenant évoluer notre automate cellulaire avec la règle d'évolution suivante :

Voici ce que l'on obtient après quatre générations :

La règle 30

Le nombre décimal 30 s'écrit en binaire 00011110. Si l'on se représente une case blanche pour chaque 0, et une case noire pour chaque 1 : on retombe sur notre règle d'évolution précédemment vue. C'est pourquoi on appelle cette dernière « règle 30 ».

Arrêtons de blablater, et mettez-vous au travail : implémentez la règle 30 !

Pour rendre cet exercice plus intéressant, il faudrait pourvoir varier dans votre programme :

  • Le nombre de cellules ;
  • Le nombre de générations à afficher ;
  • La configuration initiale.

Bonne chance !

La règle 0 à 255

Enfin, pour rendre cet exercice encore plus intéressant, il vous reste encore un paramètre à varier : la règle. Un code évolutif, qui permet d'afficher N générations de n cellules, et ce, quelle que soit la règle utilisée ; est si beau.

Je vous invite à réaliser ce si beau code, et j'espère que vous serez fier de vous et de votre travail, une fois la tâche accomplie !

Sur ce, je vous laisse, et bon codage !


Ressources :

  • Partager sur Facebook
  • Partager sur Twitter
15 décembre 2013 à 20:54:33

Bon exercice, même si une entrée plus en douceur dans sujet pourrais je pense le rendre plus accessible aux débutants.

-
Edité par simbilou 15 décembre 2013 à 20:54:54

  • Partager sur Facebook
  • Partager sur Twitter
Zeste de Savoirbépocode minimal  — Ge0 <3
15 décembre 2013 à 21:22:03

Merci simbilou.

Je pense que de toutes manières, ce n'est pas l'exercice le plus accessible jamais rédigé. L'enrober d'une myriade d'informations et de conseils l'aurait sans doute rendu plus compréhensible vis-à-vis du débutant moyen, mais pour le nombre de réponses que j'aurais obtenu de toutes manières... Ce n'est pas que je commence à désespérer, mais je me souviens d'une époque où les anciens hallucinaient de ne voir que deux pages de réponses en deux jours. Peut-être que les exercices deviennent trop compliqués, mais je ne suis pas sûr que ne ce soit que ça : certains anciens exos était vraiment balèzes eux aussi. Peut-être que mes exercices ne sont pas intéressants. Peut-être qu'ils nécessiteraient un gros coup de pub. Quoi qu'il en soit, si j'arrive à aider ne serait-ce qu'un zéro à l'aide d'un de mes exercices, je serais déjà content. :)

-
Edité par paraze 15 décembre 2013 à 21:24:18

  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
15 décembre 2013 à 21:37:45

Je suis (malheureusement !) sûr à 99% que le problème n'est pas lié à la difficulté des exos. Je ne pense pas qu'un automate cellulaire soit si compliqué que ça. Une représentation binaire dans la console n'est pas si compliquée à implémenter. Je ne sais pas comment amener les débutants à faire ces exercices et à participer.
Lorsque j'a débuté, j'ai fait les exercices en partant des premiers proposés. Je ne le s postais pas vu que l'exercice était fini depuis entre 2 ans et 2 mois. On peut toujours espérer que c'est ce que font les débutants actuellement.

Je mets à jour ma signature pour le nouvel exercice.

Je proposerai un code après mon dernier examen de cette session qui se déroulera mardi. Donc vers jeudi/vendredi.

Ceci-dit, je pense que l'essentiel est dit et/ou donné dans les liens. Peut-être que si t'en avais le courage, tu pourrais faire un système de niveau, mais effectivement, pour le nombre de réponse(s) que tu obtiens...

  • Partager sur Facebook
  • Partager sur Twitter
15 décembre 2013 à 22:01:49

Salut ! rassurez-vous il y a toujours des débutants pour faire des exercices ! :)

Voici mon code pour la règle de 30:

#include <stdio.h>
#include <stdlib.h>

#include "color.h"

int live(int gauche, int cell, int droite); // la fonction qui fait "vivre" la cellule

int main(int argc, char* argv[])
{
	int i;// un premier buffer
	int buffer; // un second
	int nbFois; // le nombre de générations
	int nbCell; // le nombre de cellules

	float conf; // pour récupérer la configuration de départ

	printf("zCellular\n"); // "Bonjour !"

	printf("Combien de cellules ? ");
	scanf("%d",&nbCell); // on renseigne le nombre de cellules
	
	printf("Combien de générations ?"); 
	scanf("%d",&nbFois); // idem pour le nombre de générations

	int *cellules = NULL; // pour mettre toutes les cellules
	int *sortie = NULL; // on écrira la nouvelle chaine de cellules dedans

	cellules = malloc(nbCell * sizeof(int)); // on donne leurs tailles aux deux tableaux
	sortie = malloc(nbCell * sizeof(int));

	printf("Configuration de départ : "); // et on les remplis
	scanf("%f",&conf);
	for(i=0; i<nbCell; i++)
	{
		cellules[i] = (conf/10 - (int)(conf / 10)) * 10;
		conf = (int)(conf/10);
	}

	// boucle principale
	for(i=0; i<nbFois; i++) // on fait vivre le nombre de fois qu'il faut
	{
		for(buffer=0; buffer<nbCell; buffer++) // boucle de l'affichage et de l'appel à la fonction vivre
		{
			// affichage
			if(cellules[buffer]) // si la cellule est vivante, elle est rouge
			{
				couleur("41");
				couleur("31");
				printf("%d", cellules[buffer]);
				couleur("0");
			}
			else // sinon elle est blanche
			{
				couleur("47");
				printf("%d", cellules[buffer]);
				couleur("0");
			}

			//opérations
			if(buffer==0) // si c'est la première cellule, elle n'a pas de cellule à gauche
			{
				sortie[buffer]=live(0,cellules[buffer],cellules[buffer+1]);
			}
			else if(buffer==nbCell-1) // si c'est la dernière, elle n'a pas de cellule à droite
			{
				sortie[buffer]=live(cellules[buffer-1],cellules[buffer],0);
			}
			else // sinon elle a deux voisins
			{
				sortie[buffer]=live(cellules[buffer-1], cellules[buffer], cellules[buffer+1]);
			}
		}

		for(buffer=0; buffer<nbCell; buffer++) // on récupère la chaine de sortie
		{
			cellules[buffer] = sortie[buffer];
		}
		printf("\n"); // on va a la ligne
		
	}

	free(sortie); // on libère les dux tableaux alloués dynamiquement
	free(cellules);

	return 0;
}

int live(int gauche, int cell, int droite) // fonction qui fait vivre les cellules
{
	if((!gauche && (cell || droite))||(gauche && !cell && !droite)) // si elle doit vivre
	{
		return 1;
	}
	else // sinon elle meurt : P !
	{
		return 0;
	}
}

le fichier color.h vient de ce tutoriel

@+ !

-
Edité par klafyvel 15 décembre 2013 à 22:09:29

  • Partager sur Facebook
  • Partager sur Twitter
15 décembre 2013 à 22:34:02

Merci de ta participation klafyvel !

Ton code me paraît correct, quoi qu'un peu trop commenté à mon goût (les commentaires tels que « on va a la ligne » gênent plus la lecture qu'autre chose AMHA). J'ai quelques doutes cependant quant à l'efficacité de ce bout de code :

printf("Configuration de départ : "); // et on les remplis
scanf("%f",&conf);
for(i=0; i<nbCell; i++)
{
    cellules[i] = (conf/10 - (int)(conf / 10)) * 10;
    conf = (int)(conf/10);
}

Pour illustrer ma pensée, voici un exemple d'exécution :

zCellular
Combien de cellules ? 10
Combien de générations ?2
Configuration de départ : 0001000000
0000001000
0000011100

Comme tu peux le voir, cela ne fonctionne pas à merveille. ^^

Sinon, je pense que tu l'auras compris, adapter ce code aux 255 autres règles n'est pas chose aisée. Tu ne vas pas créer 256 fonctions différentes, il faut donc que tu arrives à concevoir une fonction générique (si je puis dire), qui est capable de fonctionner avec n'importe quelle règle. Petit indice : introduis dans ton code un petit système de règle, et renseigne-toi sur la conversation décimal -> binaire.

Et encore merci de ta participation. :)

Edit : Et merci poupou9779 aussi.

-
Edité par paraze 15 décembre 2013 à 22:37:19

  • Partager sur Facebook
  • Partager sur Twitter
15 décembre 2013 à 22:42:59

Vu que je m'ennuie la tout de suite, je vais le faire xD.

Par contre je n'ai pas compris les différentes améliorations...

  • Partager sur Facebook
  • Partager sur Twitter
15 décembre 2013 à 22:58:32

Bonsoir Ricocotam et merci de ta future participation. ^^

Le principe des différentes améliorations est de concevoir, à terme, un programme évolutif. En gros, pouvoir afficher le nombre de génération du nombre de cellules que l'on veut, et ce, quelle que soit la règle la configuration et la règle de départ; c'est ça un code évolutif pour moi (un autre exemple, le morpion : il serait bien que le programme puisse fonctionner avec des grilles d'une quasi-infinité de tailles différentes par exemple). Si tu regardes le code de klafyvel, tu peux t'apercevoir qu'il suffit de changer une ou deux variables pour obtenir ce que l'on veut. Ce n'est pas statique. C'est ce que je demande, c'est ce qui est intéressant (AMHA).

En espérant avoir été assez clair, :)

  • Partager sur Facebook
  • Partager sur Twitter
15 décembre 2013 à 23:12:02

Je l'aurais fait instinctivement ^^.

Par contre, On considère une cellule inexistante (bout de tableau) comme morte ? vivante ? ou on considère une boucle ?

  • Partager sur Facebook
  • Partager sur Twitter
16 décembre 2013 à 0:01:54

Bon alors, voici un premier truc, j'ai une merde sur ma fonction afficher... :(

Prototypes

/* Structure des modèles */
typedef struct Modele_Vie {
	char avant[3];
	char apres;
} Modele_vie;

/* Prototypes */

/* Cette fonction initialise un modèle */
void initialiser_modele(Modele_Vie *modele);

/* Cette fonction permet de passer à la génération suivante */
void generation_suivante(char* chaine, int nb_cellule, Modele_Vie* liste_modele, int nb_modele);


/* Cette fonction permet de trouver un modele pour une chaine donnée */
int modele_correspondant(char* chaine, int i, int nb_cellule, int etendue, Modele_Vie* liste_modele, int nb_modele);

/* Permet d'afficher la chaine sous forme de nombre */
void afficher(char* chaine);

main

int main (void) {
	char *chaine;
	Modele_Vie liste_modele[8];
	int nb_cellule = 10, i;

	/* alloc dynamique de la chaine contenant l'ensemble des cellules */
	chaine = (char*)malloc(nb_cellule*sizeof(char) + 1);	
	if(chaine == NULL)
		exit(EXIT_FAILURE);

	/* Saisie de la chaine de départ */
	printf("Saisissez la chaine de départ :");
	gets(chaine);


	/* Définition des règles */
	for(i = 0; i < 8; i++)
		initialiser_modele(&liste_modele[i]);

	/* Initialisation de la chaine */
	for(i = 0; i < nb_cellule; i++)
		chaine[i] = '0';
	chaine[i] = '\0';
	
	while(getchar() != '0'){
		generation_suivante(chaine, nb_cellule, liste_modele, 8);
		afficher(chaine);
	}

	afficher(chaine);

	free(chaine);

	return (EXIT_SUCCESS);
}

Fonctions

/* Sources des fonctions */

void initialiser_modele(Modele_Vie *modele){
	char c;

	fflush(stdin);

	printf("\nEntrez un modele de depart : ");
	gets(modele->avant);	

	printf("Entrez le changement de la case du milieu : ");
	modele->apres = getchar();
}


void generation_suivante(char* chaine, int nb_cellule, Modele_Vie* liste_modele, int nb_modele){
	int i, modele_courant;
	
	for(i = 0; i < nb_cellule; i++){
		modele_courant = modele_correspondant(chaine, i, nb_cellule, 3, liste_modele, nb_modele);
		chaine[i] = liste_modele[modele_courant].apres;
	}
}


int modele_correspondant(char* chaine, int i, int nb_cellule, int etendue, Modele_Vie* liste_modele, int nb_modele){
	char* a_comparer;	// Variable temporaire pour mieux gérer
	int k;

	a_comparer = (char*)malloc(etendue*sizeof(char) + 1);
	if(a_comparer == NULL)
		exit(EXIT_FAILURE);

	/* On initialise proprement la variable temporaire */
	if(i == 0){
		a_comparer[0] = '0';
		strncpy(&a_comparer[1], &chaine[i], etendue - 1);
	}
	else{		
		strncpy(a_comparer, &chaine[i], etendue);
		if(i == (nb_cellule - 1))
			a_comparer[etendue] = '0';
	}

	a_comparer[etendue + 1] = '\0';


	/* On cherche le modèle */
	for(k = 0; k < nb_modele && strcmp(a_comparer, liste_modele[k].avant); k++);

	free(a_comparer);
	return (k);
}

void afficher(char* chaine){
	int i = 0;

	while(chaine[i] != '\0')
		printf("%d", (int)chaine[i++]);
}





  • Partager sur Facebook
  • Partager sur Twitter
16 décembre 2013 à 18:07:23

Salut ! oui je viens de me rendre compte que j'ai inversé la boucle for... le bon code est :

for(i=nbCell-1; i>=0; i--)



  • Partager sur Facebook
  • Partager sur Twitter
16 décembre 2013 à 18:28:59

Salut,

J'ai jeté un coup d'oeil ici par curiosité, et je me suis dis que je pouvais m'amuser un peu. J'ai donc tenté de réaliser l'exercice en manipulant des bits, et j'ai pondu un code assez court (une centaine de lignes) avec plusieurs configurations en macros. On peut bien sûr modifier le nombre de cases (en revanche, on ne peut pas dépasser 32 sans modifier un peu le code), l'état initial du jeu et le nombre de générations à afficher. En plus de cela j'ai ajouté un mode de jeu qui affiche un certain nombre de générations par seconde (le jeu évolue jusqu'à l'arrêt du programme), nombre qui est également modifiable.

#include <stdio.h> // fputs, putchar
#include <time.h> // clock

#define ALIVE 0xFE // ■ (alt+254)
#define DEAD '-'

/** -- Configuration -- **/

#define SIZE 10 /** Up to 32 cells **/
#define INITIAL_STATE 0b0000110000
#define RULES 0b00011110 /** First rule is for 111 local state, second for 110, and so on to 000 **/

#define LIVING 0 /** Continuous game **/
#define GENERATIONS 20 /** Only for standard game **/
#define FPS 2 /** Only for LIVING game **/

/** -- Configuration -- **/

void delay(double seconds);
int localState(int state, int cell);
int nextState(int currentState);
void printState(int state);

int main(void)
{
    int state = INITIAL_STATE;

#if LIVING

    clock_t t;

    puts("zLivingCellular\n\n");

    t = clock();
    printState(state);
    while (1) {
        state = nextState(state);
        delay(1.0/FPS - (double)(clock()-t)/CLOCKS_PER_SEC);
        t = clock();
        putchar('\r');
        printState(state);
    }

#else

    int i;

    puts("\nzCellularGenerations\n");

    printState(state);
    for (i = 0; i < GENERATIONS; ++i) {
        putchar('\n');
        state = nextState(state);
        printState(state);
    }

    puts("\n\nPress any key");
    getchar();

#endif // LIVING

    return 0;
}

void printState(int state) {
    int i;
    char s[SIZE+1];
    s[SIZE] = '\0';
    for (i = 0; i < SIZE; ++i) {
        if (state & (0b1 << (SIZE-1-i))) {
            s[i] = ALIVE;
        } else {
            s[i] = DEAD;
        }
    }
    fputs(s, stdout);
}

int nextState(int currentState) {
    int result = 0, mask, i;
    for (i = 0; i < SIZE; ++i) {
        mask = 0b1 << localState(currentState, i); // the local state acts as a 1-bit mask
        if (RULES & mask) {
            result |= 0b1 << (SIZE - 1 - i); // Activate the correct cell
        }
    }
    return result;
}

int localState(int state, int cell) {
    if (cell == 0) {
        return (state >> (SIZE-2)) & 0b11; // Keep the 2 first cells and add a dead one
    } else if (cell == SIZE-1) {
        return (state & 0b11) << 1; // Keep the 2 last cells
    } else {
        int mask = 0b111 << (SIZE - 2 - cell); // Locate the local cells
        state &= mask; // Keep the local cells
        return state >> (SIZE - 2 - cell); // Replace them
    }
}

void delay(double seconds) {
    double t = (double)clock()/CLOCKS_PER_SEC + seconds;
    while ((double)clock()/CLOCKS_PER_SEC < t);
}


Si vous n'aimez pas la représentation des cases, modifiez les macros ALIVE et DEAD au début. Je pense que le code est assez commenté. Une petite remarque cependant : je n'ai pas trouvé l'équivalent portable d'une fonction qui permet d'"endormir" le programme pendant moins d'une seconde. J'ai donc codé une minuscule fonction qui fait travailler le CPU à fond, dommage.

Il est possible que mon code contienne encore des bugs, mais je l'ai testé à plusieurs reprises et pour différentes configurations sans en voir.

Bon codage aux autres participants, comme on dit.

-
Edité par Nelxiost 19 décembre 2013 à 12:08:12

  • Partager sur Facebook
  • Partager sur Twitter
16 décembre 2013 à 22:16:51

Et voilà ma version pour la règle paramétrable !

#include <stdio.h>
#include <stdlib.h>


#include "color.h"

int live(int gauche, int cell, int droite, int regle[]); // la fonction qui fait "vivre" la cellule

int main(int argc, char* argv[])
{
	int i;// un premier buffer
	int buffer; // un second
	int nbFois; // le nombre de générations
	int nbCell; // le nombre de cellules

	int regle[8]; // la règle
	int regleIn;

	float conf; // pour récupérer la configuration de départ


	printf("zCellular\n");

	printf("Combien de cellules ? ");
	scanf("%d",&nbCell); // on renseigne le nombre de cellules
	
	printf("Combien de générations ?"); 
	scanf("%d",&nbFois); // idem pour le nombre de générations

	printf("Regle (0~255): ");
	scanf("%d",&regleIn);
	if(regleIn>255)
		return -1;
	buffer = 0;
	while(regleIn>=2)
	{
		regle[7-buffer]=regleIn%2;
		regleIn /= 2;
		buffer++;
	}
	regle[7-(buffer)] = regleIn;
	buffer ++;
	for(i=7-buffer; i>=0; i--)
		regle[i]=0;


	int *cellules = NULL; // pour mettre toutes les cellules
	int *sortie = NULL; // on écrira la nouvelle chaine de cellules dedans

	cellules = malloc(nbCell * sizeof(int)); // on donne leurs tailles aux deux tableaux
	sortie = malloc(nbCell * sizeof(int));

	printf("Configuration de départ : "); // et on les remplis
	scanf("%f",&conf);
	for(i=nbCell-1; i>=0; i--)
	{
		cellules[i] = (conf/10 - (int)(conf / 10)) * 10;
		conf = (int)(conf/10);
	}
	

	// boucle principale
	for(i=0; i<nbFois; i++) // on fait vivre le nombre de fois qu'il faut
	{
		for(buffer=0; buffer<nbCell; buffer++) // boucle de l'affichage et de l'appel à la fonction vivre
		{
			// affichage
			if(cellules[buffer]) // si la cellule est vivante, elle est rouge
			{
				couleur("41");
				couleur("31");
				printf("%d", cellules[buffer]);
				couleur("0");
			}
			else // sinon elle est blanche
			{
				couleur("47");
				printf("%d", cellules[buffer]);
				couleur("0");
			}

			//opérations
			if(buffer==0) // si c'est la première cellule, elle n'a pas de cellule à gauche
			{
				sortie[buffer]=live(0,cellules[buffer],cellules[buffer+1], regle);
			}
			else if(buffer==nbCell-1) // si c'est la dernière, elle n'a pas de cellule à droite
			{
				sortie[buffer]=live(cellules[buffer-1],cellules[buffer],0, regle);
			}
			else // sinon elle a deux voisins
			{
				sortie[buffer]=live(cellules[buffer-1], cellules[buffer], cellules[buffer+1], regle);
			}
		}

		for(buffer=0; buffer<nbCell; buffer++) // on récupère la chaine de sortie
		{
			cellules[buffer] = sortie[buffer];
		}
		printf("\n");
		
	}

	free(sortie); // on libère les deux tableaux alloués dynamiquement
	free(cellules);

	return 0;
}

int live(int gauche, int cell, int droite, int regle[]) // fonction qui fait vivre les cellules
{
	
	if((gauche && cell) && droite) 
	{
		if(regle[0]>0)
			return 1;
		else
			return 0;
	}
	if((gauche && cell) && !droite) 
	{
		if(regle[1]>0)
			return 1;
		else
			return 0;
	}
	if((gauche && !cell) && droite) 
	{
		if(regle[2]>0)
			return 1;
		else
			return 0;
	}
	if((gauche && !cell) && !droite) 
	{
		if(regle[3]>0)
			return 1;
		else
			return 0;
	}
	if((!gauche && cell) && droite) 
	{
		if(regle[4]>0)
			return 1;
		else
			return 0;
	}
	if((!gauche && cell) && !droite) 
	{
		if(regle[5]>0)
			return 1;
		else
			return 0;
	}
	if((!gauche && !cell) && droite) 
	{
		if(regle[6]>0)
			return 1;
		else
			return 0;
	}
	
	if((!gauche && !cell) && !droite) 
	{
		if(regle[7]>0)
			return 1;
		else
			return 0;
	}
}



  • Partager sur Facebook
  • Partager sur Twitter
16 décembre 2013 à 23:19:44

Je ne peux m'empêcher de remarquer les répétitions dans ta fonction live et de te proposer un raccourci :

int live(int gauche, int milieu, int droite, int regle[]) {
    return regle[7 - 4*gauche - 2*milieu - droite];
}

Bon, d'accord, c'est un peu gros...

Voilà une version qui prend en compte la possibilité que les variables soient différents de 0 ou de 1 :

int live(int gauche, int milieu, int droite, int regle[]) {
    int i = 0;
    if (!gauche)
        i += 4;
    if (!milieu)
        i += 2;
    if (!droite)
        i += 1;
    return regle[i] > 0;
}

Et la version raccourcie (j'étais obligé) :

int live(int gauche, int milieu, int droite, int regle[]) {
    return regle[(gauche?0:4) + (milieu?0:2) + (droite?0:1)] > 0;
}

Je n'ai pas testé ces codes, mais je pense que ça peut en intéresser certains (si quelqu'un a besoin d'explication, je peux en donner), autant pour le concept que pour l'amusement !

  • Partager sur Facebook
  • Partager sur Twitter
17 décembre 2013 à 15:43:18

klafyvel a écrit:

Et voilà ma version pour la règle paramétrable !

#include <stdio.h>
#include <stdlib.h>


#include "color.h"

int live(int gauche, int cell, int droite, int regle[]); // la fonction qui fait "vivre" la cellule

int main(int argc, char* argv[])
{
	int i;// un premier buffer
	int buffer; // un second
	int nbFois; // le nombre de générations
	int nbCell; // le nombre de cellules

	int regle[8]; // la règle
	int regleIn;

	float conf; // pour récupérer la configuration de départ


	printf("zCellular\n");

	printf("Combien de cellules ? ");
	scanf("%d",&nbCell); // on renseigne le nombre de cellules
	
	printf("Combien de générations ?"); 
	scanf("%d",&nbFois); // idem pour le nombre de générations

	printf("Regle (0~255): ");
	scanf("%d",&regleIn);
	if(regleIn>255)
		return -1;
	buffer = 0;
	while(regleIn>=2)
	{
		regle[7-buffer]=regleIn%2;
		regleIn /= 2;
		buffer++;
	}
	regle[7-(buffer)] = regleIn;
	buffer ++;
	for(i=7-buffer; i>=0; i--)
		regle[i]=0;


	int *cellules = NULL; // pour mettre toutes les cellules
	int *sortie = NULL; // on écrira la nouvelle chaine de cellules dedans

	cellules = malloc(nbCell * sizeof(int)); // on donne leurs tailles aux deux tableaux
	sortie = malloc(nbCell * sizeof(int));

	printf("Configuration de départ : "); // et on les remplis
	scanf("%f",&conf);
	for(i=nbCell-1; i>=0; i--)
	{
		cellules[i] = (conf/10 - (int)(conf / 10)) * 10;
		conf = (int)(conf/10);
	}
	

	// boucle principale
	for(i=0; i<nbFois; i++) // on fait vivre le nombre de fois qu'il faut
	{
		for(buffer=0; buffer<nbCell; buffer++) // boucle de l'affichage et de l'appel à la fonction vivre
		{
			// affichage
			if(cellules[buffer]) // si la cellule est vivante, elle est rouge
			{
				couleur("41");
				couleur("31");
				printf("%d", cellules[buffer]);
				couleur("0");
			}
			else // sinon elle est blanche
			{
				couleur("47");
				printf("%d", cellules[buffer]);
				couleur("0");
			}

			//opérations
			if(buffer==0) // si c'est la première cellule, elle n'a pas de cellule à gauche
			{
				sortie[buffer]=live(0,cellules[buffer],cellules[buffer+1], regle);
			}
			else if(buffer==nbCell-1) // si c'est la dernière, elle n'a pas de cellule à droite
			{
				sortie[buffer]=live(cellules[buffer-1],cellules[buffer],0, regle);
			}
			else // sinon elle a deux voisins
			{
				sortie[buffer]=live(cellules[buffer-1], cellules[buffer], cellules[buffer+1], regle);
			}
		}

		for(buffer=0; buffer<nbCell; buffer++) // on récupère la chaine de sortie
		{
			cellules[buffer] = sortie[buffer];
		}
		printf("\n");
		
	}

	free(sortie); // on libère les deux tableaux alloués dynamiquement
	free(cellules);

	return 0;
}

int live(int gauche, int cell, int droite, int regle[]) // fonction qui fait vivre les cellules
{
	
	if((gauche && cell) && droite) 
	{
		if(regle[0]>0)
			return 1;
		else
			return 0;
	}
	if((gauche && cell) && !droite) 
	{
		if(regle[1]>0)
			return 1;
		else
			return 0;
	}
	if((gauche && !cell) && droite) 
	{
		if(regle[2]>0)
			return 1;
		else
			return 0;
	}
	if((gauche && !cell) && !droite) 
	{
		if(regle[3]>0)
			return 1;
		else
			return 0;
	}
	if((!gauche && cell) && droite) 
	{
		if(regle[4]>0)
			return 1;
		else
			return 0;
	}
	if((!gauche && cell) && !droite) 
	{
		if(regle[5]>0)
			return 1;
		else
			return 0;
	}
	if((!gauche && !cell) && droite) 
	{
		if(regle[6]>0)
			return 1;
		else
			return 0;
	}
	
	if((!gauche && !cell) && !droite) 
	{
		if(regle[7]>0)
			return 1;
		else
			return 0;
	}
}





  • Partager sur Facebook
  • Partager sur Twitter
17 décembre 2013 à 15:44:21

klafyvel a écrit:

Et voilà ma version pour la règle paramétrable !

#include <stdio.h>
#include <stdlib.h>


#include "color.h"

int live(int gauche, int cell, int droite, int regle[]); // la fonction qui fait "vivre" la cellule

int main(int argc, char* argv[])
{
	int i;// un premier buffer
	int buffer; // un second
	int nbFois; // le nombre de générations
	int nbCell; // le nombre de cellules

	int regle[8]; // la règle
	int regleIn;

	float conf; // pour récupérer la configuration de départ


	printf("zCellular\n");

	printf("Combien de cellules ? ");
	scanf("%d",&nbCell); // on renseigne le nombre de cellules
	
	printf("Combien de générations ?"); 
	scanf("%d",&nbFois); // idem pour le nombre de générations

	printf("Regle (0~255): ");
	scanf("%d",&regleIn);
	if(regleIn>255)
		return -1;
	buffer = 0;
	while(regleIn>=2)
	{
		regle[7-buffer]=regleIn%2;
		regleIn /= 2;
		buffer++;
	}
	regle[7-(buffer)] = regleIn;
	buffer ++;
	for(i=7-buffer; i>=0; i--)
		regle[i]=0;


	int *cellules = NULL; // pour mettre toutes les cellules
	int *sortie = NULL; // on écrira la nouvelle chaine de cellules dedans

	cellules = malloc(nbCell * sizeof(int)); // on donne leurs tailles aux deux tableaux
	sortie = malloc(nbCell * sizeof(int));

	printf("Configuration de départ : "); // et on les remplis
	scanf("%f",&conf);
	for(i=nbCell-1; i>=0; i--)
	{
		cellules[i] = (conf/10 - (int)(conf / 10)) * 10;
		conf = (int)(conf/10);
	}
	

	// boucle principale
	for(i=0; i<nbFois; i++) // on fait vivre le nombre de fois qu'il faut
	{
		for(buffer=0; buffer<nbCell; buffer++) // boucle de l'affichage et de l'appel à la fonction vivre
		{
			// affichage
			if(cellules[buffer]) // si la cellule est vivante, elle est rouge
			{
				couleur("41");
				couleur("31");
				printf("%d", cellules[buffer]);
				couleur("0");
			}
			else // sinon elle est blanche
			{
				couleur("47");
				printf("%d", cellules[buffer]);
				couleur("0");
			}

			//opérations
			if(buffer==0) // si c'est la première cellule, elle n'a pas de cellule à gauche
			{
				sortie[buffer]=live(0,cellules[buffer],cellules[buffer+1], regle);
			}
			else if(buffer==nbCell-1) // si c'est la dernière, elle n'a pas de cellule à droite
			{
				sortie[buffer]=live(cellules[buffer-1],cellules[buffer],0, regle);
			}
			else // sinon elle a deux voisins
			{
				sortie[buffer]=live(cellules[buffer-1], cellules[buffer], cellules[buffer+1], regle);
			}
		}

		for(buffer=0; buffer<nbCell; buffer++) // on récupère la chaine de sortie
		{
			cellules[buffer] = sortie[buffer];
		}
		printf("\n");
		
	}

	free(sortie); // on libère les deux tableaux alloués dynamiquement
	free(cellules);

	return 0;
}

int live(int gauche, int cell, int droite, int regle[]) // fonction qui fait vivre les cellules
{
	
	if((gauche && cell) && droite) 
	{
		if(regle[0]>0)
			return 1;
		else
			return 0;
	}
	if((gauche && cell) && !droite) 
	{
		if(regle[1]>0)
			return 1;
		else
			return 0;
	}
	if((gauche && !cell) && droite) 
	{
		if(regle[2]>0)
			return 1;
		else
			return 0;
	}
	if((gauche && !cell) && !droite) 
	{
		if(regle[3]>0)
			return 1;
		else
			return 0;
	}
	if((!gauche && cell) && droite) 
	{
		if(regle[4]>0)
			return 1;
		else
			return 0;
	}
	if((!gauche && cell) && !droite) 
	{
		if(regle[5]>0)
			return 1;
		else
			return 0;
	}
	if((!gauche && !cell) && droite) 
	{
		if(regle[6]>0)
			return 1;
		else
			return 0;
	}
	
	if((!gauche && !cell) && !droite) 
	{
		if(regle[7]>0)
			return 1;
		else
			return 0;
	}
}


SVP j ai pas compris les condition : if(regle[0]>0)..if(regle[7]>0) ? et Merci d'avance :)



-
Edité par saidensak 17 décembre 2013 à 15:47:30

  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
17 décembre 2013 à 18:57:04

L'exercice était sympa à faire ! Je pense que mon code peut encore être amélioré. Je n'ai pas implémenté directement de "règle" dans mon code, mais voilà quoi :p

Voici le lien github.

Merci à paraze pour l'exo, merci à klafyvel et Rico pour avoir participé, merci à Nelxiost pour son code intéressant et... concis :p

  • Partager sur Facebook
  • Partager sur Twitter
17 décembre 2013 à 19:16:45

@Nelxiost : Wahou ! je suis juste fan de la version avec les conditions ternaires :) !!!

  • Partager sur Facebook
  • Partager sur Twitter
17 décembre 2013 à 20:01:40

poupou9779 : C'est "evolve", pas "evoluate" ! Et je ne sais pas ce que tu voulais dire par "plate" ; mais ce ne sont que des remarques de nommage.

klafyvel : le tout est de comprendre comment ça marche, on peut en faire autant de versions qu'on veut ! Le tout est de rester concis, c'est-à-dire clair (même si l'on veut faire court).

  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
17 décembre 2013 à 20:47:33

Nelxiost a écrit:

poupou9779 : C'est "evolve", pas "evoluate" ! Et je ne sais pas ce que tu voulais dire par "plate" ; mais ce ne sont que des remarques de nommage.

oups j'ai foiré sur le coup d'evoluate :p (ma fonction s'appelait evoluer puis j'ai anglicisé mon code, donc je l'ai bien sûr instinctivement renommée evoluate...)

Par plate, je veux dire assiette pardi ! :D
ici, plate, c'est planche, plateau :p

  • Partager sur Facebook
  • Partager sur Twitter
17 décembre 2013 à 21:19:26

Dans ce cas, utilise plutôt "board", comme dans "keyboard" (planche de clefs, ou de touches). "plate", c'est de la vaisselle !

Bref, il ne faudrait pas commencer à inonder le sujet...

  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
17 décembre 2013 à 21:22:25

Nelxiost a écrit:

Dans ce cas, utilise plutôt "board", comme dans "keyboard" (planche de clefs, ou de touches). "plate", c'est de la vaisselle !

Bref, il ne faudrait pas commencer à inonder le sujet...

Je prends la remarque en compte ! (t'aimes pas programmer sur de la vaisselle toi ? :-°)
EDIT : paraze, je viens de tomber là-dessus :p

-
Edité par Anonyme 17 décembre 2013 à 22:03:52

  • Partager sur Facebook
  • Partager sur Twitter
17 décembre 2013 à 22:56:46

Ah bah tu vois Poupou :) On peux très bien faire sans goto ^^ (petite référence à ta fonction quit).

Par contre un petit commentaire sur ta gestion des erreurs. Ta fonction init_cellular vérifie bien le retour de malloc ça c'est cool ... mais ensuite ? Si l'allocation échoue que vas t'il ce passer ? ... suspense ... SEGFAULT ! Je te laisse deviner pourquoi.

-
Edité par Oxynori 17 décembre 2013 à 22:58:05

  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
18 décembre 2013 à 7:52:22

Oxynori a écrit:

Ah bah tu vois Poupou :) On peux très bien faire sans goto ^^ (petite référence à ta fonction quit).

Par contre un petit commentaire sur ta gestion des erreurs. Ta fonction init_cellular vérifie bien le retour de malloc ça c'est cool ... mais ensuite ? Si l'allocation échoue que vas t'il ce passer ? ... suspense ... SEGFAULT ! Je te laisse deviner pourquoi.

Je savais pas trop quoi faire là : je quitte violemment ? Je retourne une valeur pour dire que ça a échoué, mais alors je quitte dans main ? ... donc j'ai rien fait :p

  • Partager sur Facebook
  • Partager sur Twitter
18 décembre 2013 à 16:01:34

Si ret.board vaut NULL suite à l'échec du malloc :

1) ret.board = NULL

2) Toute la brique du else n'est donc pa exécuté (donc ret.tmp non malloqué).

Conquéquences, la fonction init se termine et passe à la suite. appel de la fonction display en lui envoyant cellular (déjà la ya soucis, tu envoie une variable dont tu n'est même pas sur de sa validité). Bon pour la suite, ya qu'une seule ligne dans la fonction display, pas dur à trouver l'erreur.

Sinon tu connais valgrind ? C'est un outil très pratique pour trouver ce genre d'erreur (En compilant avec l'option -g de GCC).

En général si tu vois que tu code segfault alors que tu compile à la paraze-way ... valgrind est de mise. Je te conseille même de l'utiliser tout le temps. Ca évite de laisser des erreurs qu'on ne vois pas forcément.

  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
18 décembre 2013 à 16:13:05

Oxynori a écrit:

Si ret.board vaut NULL suite à l'échec du malloc :

1) ret.board = NULL

2) Toute la brique du else n'est donc pa exécuté (donc ret.tmp non malloqué).

Conquéquences, la fonction init se termine et passe à la suite. appel de la fonction display en lui envoyant cellular (déjà la ya soucis, tu envoie une variable dont tu n'est même pas sur de sa validité). Bon pour la suite, ya qu'une seule ligne dans la fonction display, pas dur à trouver l'erreur.

Sinon tu connais valgrind ? C'est un outil très pratique pour trouver ce genre d'erreur (En compilant avec l'option -g de GCC).

En général si tu vois que tu code segfault alors que tu compile à la paraze-way ... valgrind est de mise. Je te conseille même de l'utiliser tout le temps. Ca évite de laisser des erreurs qu'on ne vois pas forcément.

Mon code n'a pas encore planté ! il n'est effectivement pas safe vu que je gère mal les erreurs, mais il segfault pas obligatoirement
sinon, oui, je connais Valgrind, et je sais à quel point il est vanté sur internet. Mais je suis un windowzien moi, donc pas de Valgrind :/
  • Partager sur Facebook
  • Partager sur Twitter
18 décembre 2013 à 16:25:00

Il n'a pas planté, mais ce n'est pas parce qu'il ne plante pas chez toi qu'il ne planteras pas chez quelqu'un d'autres, un peu de rigueur voyons :p

Sinon je te conseille d'installer un logiciel de virtualisation (VirtualBox est simple à prendre en main, VMWare sinon) afin d'émuler une machine Linux. Comme ça tu pourras coder sous Linux avec tout ces nombreux avantages. Il te faudra peut-être un peu de temps pour prendre en main tout ça, mais crois-moi, c'est plus que bénéfique !

EDIT : Pour une bonne gestion d'erreur il faut que dans ton main tu vérifie le retour de la fonction d'initialisation, et renvoyer quelque chose en conséquence. Si tu retournes (EXIT_FAILURE) par exemple bein ton programme vas s'arrêter proprement.

-
Edité par Oxynori 18 décembre 2013 à 16:30:39

  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
18 décembre 2013 à 16:59:24

Oxynori a écrit:

Il n'a pas planté, mais ce n'est pas parce qu'il ne plante pas chez toi qu'il ne planteras pas chez quelqu'un d'autres, un peu de rigueur voyons :p

Sinon je te conseille d'installer un logiciel de virtualisation (VirtualBox est simple à prendre en main, VMWare sinon) afin d'émuler une machine Linux. Comme ça tu pourras coder sous Linux avec tout ces nombreux avantages. Il te faudra peut-être un peu de temps pour prendre en main tout ça, mais crois-moi, c'est plus que bénéfique !

EDIT : Pour une bonne gestion d'erreur il faut que dans ton main tu vérifie le retour de la fonction d'initialisation, et renvoyer quelque chose en conséquence. Si tu retournes (EXIT_FAILURE) par exemple bein ton programme vas s'arrêter proprement.

Pas besoin de machine virtuelle, j'ai commandé un second HDD qui devrait arriver dans la semaine (normalement) pour installer un Linux. ;)

J'améliorerai ma gestion des erreurs plus tard, pas trop le temps juste là maintenant.

  • Partager sur Facebook
  • Partager sur Twitter
18 décembre 2013 à 20:22:11

Yo !
Je passais par là et j'ai vu de la lumière. ^^
Ca va ? :)
Voilà ma contribution !
Enjoy !
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


unsigned mask(unsigned n, unsigned rule) {
  return (((rule & 0xFF) >> (n & 0x7)) & 1);
}

void proceed(char * src, char * dst, unsigned rule) {
  unsigned n = 0;
  unsigned i;
  
  for (i = 0; src[i]; i++) {
    n = ((n << 1) |
         ((src[i] - '0') << 1) |
         (src[i + 1] ? (src[i + 1] - '0') : 0)) & 0x7;
    
    dst[i] = mask(n, rule) + '0';
  }
  
  dst[i] = '\0';
}

int main(void) {
  char * s;
  char * t;
  char const * const str = "00000100000";
  unsigned rule;
  unsigned ngen;
  unsigned i;
  
  
  rule = 0xFA;
  ngen = 4;
  
  s = malloc((strlen(str) + 1) * sizeof *s);
  t = malloc((strlen(str) + 1) * sizeof *t);
  strcpy(s, str);
  
  printf("%s\n", s);
  
  for (i = 0; i < ngen; i++) {
    char * tmp;
    
    proceed(s, t, rule);
    printf("%s\n", t);
    
    tmp = s;
    s = t;
    t = tmp;
  }
  
  free(s);
  free(t);
  
  return EXIT_SUCCESS;
}



Problème de balises... xD
Comment on fait pour les mettre ? xD
Edit : correction d'une coquille...

-
Edité par Pouet_forever 18 décembre 2013 à 22:58:03

  • Partager sur Facebook
  • Partager sur Twitter
18 décembre 2013 à 21:39:39

Pouet_forever a écrit:

Problème de balises... xD

Comment on fait pour les mettre ? xD

Supprime tout ton code et ce qui est à côté (jusqu'à une ligne écrite normalement - il pourrait rester des balises), remets une balise de code C++ (enfin, je suppose) avec le bouton, et recopie ton code... C'est dommage, le bouton "Voir le HTML" ne marche plus.

Quant à ton code, j'aime bien l'idée, même si certaines choses me gênent un peu. Mais ça doit être personnel. °°

  • Partager sur Facebook
  • Partager sur Twitter