Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Exercice] zCellular : un automate cellulaire !

18 décembre 2013 à 21:43:15

Ca y est j'ai trouvé. ^^ Juste quand tu me l'as dit. :) Merci. ^^

Développe pour mon code. ;)

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

En fait, c'est surtout l'échange de s et t à chaque génération, et le fait de devoir passer deux chaînes à proceed. Je trouve ça assez moche, même si je comprends tout à fait pourquoi tu l'as fais. Et puis, il y a aussi ces deux printf, qui se remplacent par puts. Mais ça, c'est juste pour la frime. :D Autre chose que je n'aime pas, mais qui là est vraiment personnel, c'est la notation "unsigned" sans "int".

Enfin, je n'ai pas compris l'utilité de "<< 0", l.17.

  • Partager sur Facebook
  • Partager sur Twitter
18 décembre 2013 à 22:45:40

Tu trouves ça moche mais comment tu le ferais ? Autrement ce serait moche, là je trouve ça correct. ;) printf, puts... osef c'est juste de l'affichage. :p Pareil pour le int, osef. ^^ Le <<0 c'est un truc que j'ai laissé, c'était pour les tests. ^^ Ca sert à rien.

  • Partager sur Facebook
  • Partager sur Twitter
18 décembre 2013 à 23:49:35

Tu m'as donné envie de faire un code le plus court possible (mais en restant clair et bien présenté). Je me suis un peu inspiré de ton code, du coup tu peux considérer ça comme un exemple de la façon dont je l'aurais fait. C'est encore un brouillon, et il fait 36 lignes (31 sans la présentation, c'est-à-dire le titre et la fin), mais je pense que je reprendrai le code demain.

#include <stdio.h>

void generateNext(char gen[], unsigned char rule) {
    int i, tmp;

    if (gen[0] == '\0')
        return;

    tmp = (gen[0] == 'o' ? 1 : 0);
    for (i = 1; gen[i] != '\0'; ++i) {
        tmp = (tmp << 1 | (gen[i] == 'o' ? 1 : 0)) & 0b111;
        gen[i-1] = (rule & (1 << tmp) ? 'o' : '-');
    }
    gen[i-1] = (rule & (1 << ((tmp<<1) & 0b111)) ? 'o' : '-');
}

int main(void)
{
    char gen[] = "----oo----"; // char[] is mutable while char* can not be used as a mutable char[]
    unsigned char rule = 0b00011110;
    int ngen = 20;
    int i;

    puts("\nzTinyCellular\n");
    
    puts(gen);
    for (i = 0; i < ngen; ++i) {
        generateNext(gen, rule);
        puts(gen);
    }

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

    return 0;
}

Autre chose que tu peux remarquer : je n'aime pas la représentation des cellules en 0 et 1. :-°

  • Partager sur Facebook
  • Partager sur Twitter
19 décembre 2013 à 1:07:19

Le code est peut-être court mais impossible de comprendre le code "facilement" à la première lecture.

EDIT : sur deux petites fonctions comme ça, ça passe, mais si ça grossit vive la maintenabilité du code.

-
Edité par Oxynori 19 décembre 2013 à 1:08:42

  • Partager sur Facebook
  • Partager sur Twitter
19 décembre 2013 à 12:07:45

Oxynori a écrit:

Le code est peut-être court mais impossible de comprendre le code "facilement" à la première lecture.

EDIT : sur deux petites fonctions comme ça, ça passe, mais si ça grossit vive la maintenabilité du code.

C'est pas pour rien que j'ai appelé ça un brouillon. De plus, le code ne s'allongera pas puisque c'est un simple exercice. Mais si ça peut te rassurer, je ne code pas comme ça sur les projets un peu plus sérieux.

Comme je l'ai dis, j'ai repris le code : il est un peu plus clair (et commenté), et je l'ai même raccourci de 5 ou 6 lignes (j'hésitais à mettre int ngen sur la même ligne que int i dans main()). Voilà ce que ça donne :

#include <stdio.h>

void generateNext(char gen[], unsigned char rule) {
    int i, tmp = (gen[0] == 'o' ? 1 : 0); // Get the first cell state

    for (i = 0; gen[i] != '\0'; ++i) { // Each step, read one more cell and write the previous one
        tmp = (tmp << 1 | (gen[i+1] == 'o' ? 1 : 0)) & 0b111; // Advance - gen[i+1] can be '\0'
        gen[i] = (rule & (1 << tmp) ? 'o' : '-'); // We have already read this cell, so we can write
    }
}

int main(void)
{
    char gen[] = "----oo----"; // char[] is mutable while char* can not be used as a mutable char[]
    unsigned char rule = 0b00011110;
    int i, ngen = 25;

    puts("\nzTinyCellular\n");

    puts(gen);
    for (i = 0; i < ngen; ++i) {
        generateNext(gen, rule);
        puts(gen);
    }

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

    return 0;
}

En testant ce code, je me suis même rendu compte que mon premier contenait une erreur (l.94, c'était return (state & 0b11) << 1;). J'ai édité.

  • Partager sur Facebook
  • Partager sur Twitter
19 décembre 2013 à 19:30:57

Hello toutes/tous,

Par ce jeudi pluvieux, je me suis mis à zCellular avec plaisir, merci Paraze :). Voici le code:

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

#define CHUNK_SIZE 65536

void print_row(char *,unsigned int);

void print_row(char *data,unsigned int data_size) {
unsigned int i;
	for (i = 0; i < data_size; i++) fprintf(stdout,"%s",data[i] ? "&#9608;":"&nbsp;");
	fprintf(stdout,"<BR>\n");
	fflush(stdout);
}

int main(int argc,char **argv) {
char *buffer,*data[2],*last,*next,rules[8],*tmp;
unsigned char rule;
int c;
unsigned int cycles,buffer_size,vdata_start,rdata_start,data_size,i,j;

	/* Check/Get rule and cycles */
	if (argc != 3) {
		fprintf(stderr,"Usage: %s rule cycles\n",argv[0]);
		fflush(stderr);
		return 3;
	}
	rule = (unsigned char)atoi(argv[1]);
	cycles = (unsigned int)atoi(argv[2]);

	/* Read input into temporary buffer */
	buffer_size = 0;
	buffer = malloc(sizeof(char)*CHUNK_SIZE);
	if (!buffer) {
		fprintf(stderr,"%s: buffer malloc error\n",argv[0]);
		fflush(stderr);
		return 2;
	}
	c = fgetc(stdin);
	while (!feof(stdin)) {
		if (!(buffer_size%CHUNK_SIZE)) {
			buffer = realloc(buffer,sizeof(char)*(buffer_size+CHUNK_SIZE));
			if (!buffer) {
				fprintf(stderr,"%s: buffer realloc error\n",argv[0]);
				fflush(stderr);
				return 2;
			}
		}
		buffer_size++;
		buffer[buffer_size-1] = (char)c;
		c = fgetc(stdin);
	}

	/* Remove final carriage return from buffer if needed */
	if (buffer_size && buffer[buffer_size-1] == '\n') buffer_size--;

	/* Input may not be empty */
	if (!buffer_size) {
		fprintf(stderr,"%s: input may not be empty\n",argv[0]);
		fflush(stderr);
		free(buffer);
		return 1;
	}

	/* Input may only contain '0' or '1' */
	for (i = 0; i < buffer_size && (buffer[i] == '0' || buffer[i] == '1'); i++);
	if (i < buffer_size) {
		fprintf(stderr,"%s: input may only contain '0' or '1'\n",argv[0]);
		fflush(stderr);
		free(buffer);
		return 1;
	}

	/*
	   Build data from buffer
	   Data consists of 3 parts
	   - Variable part (V)
	   - Non-variable part at the left of variable part (L)
	   - Non-variable part at the right of variable part (R)
	   The size of V is (buffer_size) bytes initially
	   The size of L and R is (cycles) bytes initially but may be considered infinite
	   buffer is copied to V
	   First byte in buffer is copied to all bytes of L
	   Last byte in buffer is copied to all bytes of R
	   Maximum growth rate of V is 2 bytes/cycle
	*/
	vdata_start = cycles;
	rdata_start = vdata_start+buffer_size;
	data_size = rdata_start+cycles;
	for (i = 0; i < 2; i++) {
		data[i] = malloc(sizeof(char)*data_size);
		if (!data[i]) {
			fprintf(stderr,"%s: data[%u] malloc error\n",argv[0],i);
			fflush(stderr);
			for (j = 0; j < i; j++) free(data[j]);
			free(buffer);
			return 2;
		}
	}
	last = data[0];
	for (i = 0; i < vdata_start; i++) last[i] = (char)(buffer[0]-'0');
	for (i = vdata_start; i < rdata_start; i++) last[i] = (char)(buffer[i-vdata_start]-'0');
	for (i = rdata_start; i < data_size; i++) last[i] = (char)(buffer[buffer_size-1]-'0');
	free(buffer);
	next = data[1];

	/* Build ruleset */
	rules[0] = (char)(rule & 1);
	for (i = 1; i < 8; i++) rules[i] = (char)((rule & (1 << i)) >> i);

	/* Print HTML header */
	fprintf(stdout,"<!DOCTYPE HTML>\n");
	fprintf(stdout,"<HTML DIR=\"ltr\" LANG=\"en\">\n");
	fprintf(stdout,"<HEAD>\n");
	fprintf(stdout,"<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; CHARSET=utf-8\">\n");
	fprintf(stdout,"<TITLE>zCellular</TITLE>\n");
	fprintf(stdout,"<STYLE TYPE=\"text/css\">\n");
	fprintf(stdout,"BODY { font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; }\n");
	fprintf(stdout,"DIV { margin: 0; overflow: auto; padding: 2px 6px 2px 6px; }\n");
	fprintf(stdout,"H1 { font-size: 18px; }\n");
	fprintf(stdout,"A { color: #CCCCCC; text-decoration: none; }\n");
	fprintf(stdout,"A:hover { color: #888888; }\n");
	fprintf(stdout,"P { background-color: #CCCCCC; color: blue; font-family: monospace; font-size: 6px; line-height: 1.1; overflow: auto; text-align: center; }\n");
	fprintf(stdout,".header { background-color: #008844; color: white; text-align: center; }\n");
	fprintf(stdout,".data { background-color: #44CC88; }\n");
	fprintf(stdout,"</STYLE>\n");
	fprintf(stdout,"</HEAD>\n");
	fprintf(stdout,"<BODY>\n");
	fprintf(stdout,"<DIV CLASS=\"header\">\n");
	fprintf(stdout,"<H1>\n");
	fprintf(stdout,"<A HREF=\"http://fr.openclassrooms.com/forum/sujet/exercice-zcellular-un-automate-cellulaire\" TARGET=\"_blank\">zCellular</A> - Elementary Cellular Automaton - Rule %u - Cycles %u\n",rule,cycles);
	fprintf(stdout,"</H1>\n");
	fprintf(stdout,"</DIV>\n");
	fprintf(stdout,"<DIV CLASS=\"data\">\n");
	fprintf(stdout,"<P>\n");
	fflush(stdout);

	/* Print initial row */
	print_row(last,data_size);

	/* Process cycles */
	for (i = 0; i < cycles; i++) {

		/* Update variable/right data indexes if needed */
		if (last[vdata_start] != last[0]) vdata_start--;
		if (last[rdata_start-1] != last[data_size-1]) rdata_start++;

		/* Apply ruleset to compute next data from last data */
		for (j = vdata_start-1; j < rdata_start+1; j++) next[j] = rules[last[j+1] | (last[j] << 1) | (last[j-1] << 2)]; /* V */
		if (next[vdata_start-1] != last[vdata_start-1]) for (j = 0; j < vdata_start-1; j++) next[j] = next[vdata_start-1]; /* L */
		if (next[rdata_start] != last[rdata_start]) for (j = rdata_start+1; j < data_size; j++) next[j] = next[rdata_start]; /* R */

		/* Print row after computation */
		print_row(next,data_size);

		/* Switch last/next pointers */
		tmp = last;
		last = next;
		next = tmp;
	}

	/* Print HTML footer */
	fprintf(stdout,"</P>\n");
	fprintf(stdout,"</DIV>\n");
	fprintf(stdout,"</BODY>\n");
	fprintf(stdout,"</HTML>\n");
	fflush(stdout);

	/* Free data then exit program normally */
	for (i = 0; i < 2; i++) free(data[i]);
	return 0;
}

Le programme gère les 256 règles et le nombre de cycles que l'on veut (paramètres du programme). Le pattern de départ est lu depuis l'entrée standard et du html est généré en sortie, pour avoir un résultat plus sympa à regarder.

Le premier et le dernier chiffre du pattern en entrée sont considérés comme la valeur qui sera répétée à l'infini à gauche et à droite du pattern respectivement (exemple 010 sera en fait considéré comme ...00000100000...). Le pattern peut donc croitre de manière infinie (théoriquement bien sûr ;)).

EDIT: 2 exemples de ce que cela donne pour la règle 30 et la règle 110 (pattern 0110 en entrée).

EDIT2: nouvelle version pour optimiser la taille du fichier html.

-
Edité par fromvega 21 décembre 2013 à 9:35:46

  • Partager sur Facebook
  • Partager sur Twitter
19 décembre 2013 à 22:44:37

N'étant pas très habile avec les opérateurs de bits, je me suis vu dans l'obligation de passer par des tableaux :

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

int *morph(int *sequence, int *rule, int generations, size_t len);
void display(int *sequence, size_t len);
int *arg_to_arr(const char *arg);

int main(int argc, char *argv[])
{
	if(argc < 5)
	{
		printf("Utilisation : %s <sequence> <generations> <cellules> <regle>\n", argv[0]);
		printf("Exemple : %s 0000110000 4 10 00011110\n", argv[0]);
		return 0;
	}
	
	int *sequence = arg_to_arr(argv[1]);
	int generations = atoi(argv[2]);
	int len = atoi(argv[3]);
	int *rule = arg_to_arr(argv[4]);
	
	int *new_sequence = morph(sequence, rule, generations, len);
	
	display(sequence, len);
	display(new_sequence, len);
	
	free(rule);
	free(sequence);
	free(new_sequence);
	
	return 0;
}

int *arg_to_arr(const char *arg)
{
	int i, len = strlen(arg);
	int *arr = (int *) malloc(sizeof(int) * len);
	for(i = 0; arg[i] != '\0'; i++)
	{
		arr[i] = arg[i] - '0';
	}
	return arr;
}

int *morph(int *sequence, int *rule, int generations, size_t len)
{
	static int pattern[8][3] = {
		{1, 1, 1},
		{1, 1, 0},
		{1, 0, 1},
		{1, 0, 0},
		{0, 1, 1},
		{0, 1, 0},
		{0, 0, 1},
		{0, 0, 0}
	};
	int i, j;
	int *new_sequence = (int *) malloc(sizeof(int) * len);
	memcpy(new_sequence, sequence, len * sizeof(int));

	if(--generations == 0)
	{
		return new_sequence;
	}
	
	for(i = 1; i < len - 1; i++)
	{
		int prev = sequence[i - 1], cur = sequence[i], next = sequence[i + 1];
		for(j = 0; j < 8; j++)
		{
			if(prev == pattern[j][0] && cur == pattern[j][1] && next == pattern[j][2])
			{
				new_sequence[i] = rule[j];
				break;
			}
		}
	}
	
	return morph(new_sequence, rule, generations, len);
}

void display(int *sequence, size_t len)
{
	int i;
	printf("\n[");
	for(i = 0; i < len - 1; i++)
	{
		printf("%d, ", sequence[i]);
	}
	printf("%d]\n", sequence[len - 1]);
}

Solution certes pas aussi élégante que celles postées, mais qui fait tout de même l'affaire.

(enfin, je suppose. je ne l'ai testée qu'avec la règle 30)

-
Edité par Scroph 20 décembre 2013 à 19:58:39

  • Partager sur Facebook
  • Partager sur Twitter
20 décembre 2013 à 16:53:00

Si j'enlève tous mes trucs superflus et que je fais une transformation en place je peux réduire mon code de quelques lignes aussi. ^^

#include <stdio.h>

void proceed(char * src, 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;
    src[i] = (((rule & 0xFF) >> (n & 0x7)) & 1) + '0';
  }
}

int main(void) {
  char s[] = "01000000000";
  unsigned rule = 0xFA;
  unsigned ngen = 6;
  unsigned i;
  
  puts(s);
  for (i = 0; i < ngen; i++) {
    proceed(s, rule);
    puts(s);
  }
  
  return 0;
}

Je vais ptete supprimer mes codes et les remettre après, faut pas que les autres se calquent sur ce que j'ai fait... ^^

-
Edité par Pouet_forever 20 décembre 2013 à 16:54:39

  • Partager sur Facebook
  • Partager sur Twitter
20 décembre 2013 à 17:29:09

Pouet_forever : on a la même forme de code, de toutes façons. Tout ce qui diffère, c'est le for de la fonction :

for (i = 0; gen[i] != '\0'; ++i) {
    tmp = (tmp << 1 | (gen[i+1] == 'o' ? 1 : 0)) & 0b111; 
    gen[i] = (rule & (1 << tmp) ? 'o' : '-');
}

for (i = 0; src[i]; i++) {
    n = ((n << 1) | ((src[i] - '0') << 1) | (src[i + 1] ? (src[i + 1] - '0') : 0)) & 0x7;
    src[i] = (((rule & 0xFF) >> (n & 0x7)) & 1) + '0';
}

et la déclaration de n/tmp : n = 0;/tmp = (gen[0] == 'o' ? 1 : 0);

Ca montre quelque chose : ton code fait quelque chose de plus à chaque boucle, alors que je fais la même chose au début, une seule fois. C'est cette partie dans ton code (l.8) : ((src[i] - '0') << 1)

D'ailleurs, tu vois que deux chaînes et des allocations dynamiques ne sont pas nécessaires. :D

Autre chose d'inutile dans ton code : (n & 0x7), l.9. n est déjà "masqué" (comment qu'on dit ?).

Pouet_forever a écrit:

Je vais ptete supprimer mes codes et les remettre après, faut pas que les autres se calquent sur ce que j'ai fait... ^^

Mais non, l'exercice est fait pour réfléchir seul, pas pour se calquer sur un travail déjà posté. Si quelqu'un ne comprend pas ça, tant pis. Et puis, je pense que la plupart des débutants qui fréquentent ce forum (s'ils osent tenter l'exercice) ne comprendront pas (ou difficilement) nos codes.

Pour la forme, je poste le code le plus petit que j'ai trouvé, en enlevant la fonction (étant donné qu'il n'y a qu'un appel dans le code).

#include <stdio.h>

int main(void) {
    char gen[] = "----oo----";
    unsigned char rule = 0b00011110;
    int i, j, tmp, ngen = 25;

    puts(gen);
    for (i = 0; i < ngen; ++i) {
        tmp = (gen[0] == 'o' ? 1 : 0);
        for (j = 0; gen[j] != '\0'; ++j) {
            tmp = (tmp << 1 | (gen[j+1] == 'o' ? 1 : 0)) & 0b111;
            gen[j] = (rule & (1 << tmp) ? 'o' : '-');
        }
        puts(gen);
    }

    return 0;
}

Oui, c'est moche. Et d'ailleurs, on peut encore enlever 5 lignes en effaçant les 3 sauts de ligne, en effaçant l'un des puts() (et en mettant l'autre avant la "fonction"), et en mettant la première affectation de tmp dans la boucle, Pouet_forever-style. Mais en plus d'être moche, c'est inefficace (et sûrement contre-productif) Edit : je parle surtout de la suppression d'un puts().

-
Edité par Nelxiost 20 décembre 2013 à 19:33:13

  • Partager sur Facebook
  • Partager sur Twitter
20 décembre 2013 à 17:53:59

A dire vrai j'ai pas regardé ton code. :-°

Je n'ai jamais dit que mes allocations étaient ce qu'il y a de plus utile. ;) Je me suis un peu calqué sur un strcpy ou un truc du genre qui te permet d'avoir une chaîne non modifiée et une chaîne modifiée. ;)

En théorie les 2 &0xFF et &0x7 sont inutiles, les valeurs ne doivent pas arriver à ce stade là, mais c'est par précaution. ;)

Le problème de laisser les codes (c'est du déjà vu 100 fois), c'est que les débutants vont regarder nos codes et se dire "ah ! c'est super dur en fait", du coup ils n'essayeront même pas de le faire, pourtant c'est pas dur... :s

Tes 0b pour mettre tes nombres en binaire ne compilent pas chez moi. :-°

"et en mettant la première affectation de tmp dans la boucle, Pouet_forever-style. Mais en plus d'être moche, c'est inefficace (et sûrement contre-productif)."

J'ai bien rigolé. :lol:

Si tu veux parler de mocheté et d'inefficacité et de contre-productivité, on peut parler de ton code. Le fait de mettre des ternaires à gogo juste parce que tu n'aimes pas les 0/1 est moche, inefficace et contre productif, Nelxiost-style. ;) Un ternaire est beaucoup plus lent qu'un simple -/+'0'. ;)

Le fait d'utiliser des mélanges de type char/unsigned char/int est super aussi, tu fais des milliers de conversions implicites. ;)

  • Partager sur Facebook
  • Partager sur Twitter
20 décembre 2013 à 19:30:57

Pouet_forever a écrit:

En théorie les 2 &0xFF et &0x7 sont inutiles, les valeurs ne doivent pas arriver à ce stade là, mais c'est par précaution. ;)

Non, le masque 0x7 l.9 est bien inutile, puisqu'il est déjà l.8. Quant à la précaution, c'est vrai pour le masque 0xFF, mais pas pour le 0x7 : ça éviterait un overflow si la chaîne est trop longue et la capacité d'un unsigned int trop petite (Mais c'est vrai qu'il faudrait une chaîne très longue).

Pouet_forever a écrit:

Tes 0b pour mettre tes nombres en binaire ne compilent pas chez moi. :-°

Effectivement, je ne savais pas que le C n'intégrait pas ça nativement. C'est une extension de GCC. Je m'y suis habitué sans le savoir...

Quant à mes critiques, j'ai du mal me faire comprendre, excuse-moi. En effet, le "en plus d'être moche" renvoyait au code que j'ai posté (d'où le "Oui, c'est moche."), et le "inefficace" renvoyait plus au retrait d'un puts() qu'à la première affectation de n/tmp (ça revient à faire une dernière génération pour ne rien afficher). Cependant, je soutiens quand même que mettre cette affectation en dehors de la boucle est plus efficace.

D'ailleurs, par curiosité, j'ai essayé de tester la rapidité d'exécution de plusieurs codes. Note que je ne suis pas un pro de l'optimisation ou de la vitesse d'exécution. Mais je suis plus ou moins arrivé aux résultats que j'attendais. J'ai testé les trois codes rassemblés ici, sans optimisation et avec l'option O1. Chez moi, j'ai une augmentation du temps d'exécution d'environ 25% pour ton code par rapport au mien. Encore une fois, je précise que je peux avoir fait une erreur. J'ai aussi fait une combinaison des deux codes (à partir du tien, en mettant la fameuse affectation hors de la boucle), et j'ai le meilleur résultat (un peu plus rapide que mon code).

Si ça ne te dérange pas, il serait intéressant de voir quels résultats tu obtiens chez toi (et au passage, vérifie que rien ne biaise les tests).

Désolé d'avoir semblé blâmer ton code, mais ce n'était réellement pas contre toi.

  • Partager sur Facebook
  • Partager sur Twitter
21 décembre 2013 à 14:03:52

Pour la rapidité, j'ai testé tes codes, j'ai les mêmes résultats que toi. :)

J'ai essayé de faire un truc vite fait avec une table, il se trouve que c'est plus long. o_O Je ne vois pas trop pourquoi lol. ^^

Je vais regarder ça un peu plus tard. ^^

Edit : en fait non, c'est pas plus long, c'est légèrement plus rapide, mais je pensais gagner beaucoup plus de temps. :)

-
Edité par Pouet_forever 21 décembre 2013 à 14:08:31

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

hey ! Mon code est assez court, je le met comme ça :

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

#define TYPE    126 // or 30, 126, 250, 190, 110 - must be < 256
#define WIDTH   80

int **ft_init_tab(void)
{
    int i, **line;

    line = malloc(2 * sizeof(int*));
    line[0] = malloc(WIDTH * sizeof(int));
    line[1] = malloc(WIDTH * sizeof(int));

    for (i = 0; i < WIDTH; i++)
        line[0][i] = 0;
    line[0][WIDTH/2] = 1;

    return line;
}

int ft_get_next(int *ptr)
{
    return !!((1 << ((ptr[-1]<<2) + (ptr[0]<<1) + (ptr[1]))) & TYPE);
}

void ft_print_line(int *line)
{
    int i;

    for (i = 0; i < WIDTH; i++)
        printf("%c", line[i] == 0 ? ' ' : 'X');
    printf("\n");
}

int main(void)
{
    int i, j, cur, new = 0;
    int **line = ft_init_tab();

    ft_print_line(line[new]);
    for (j = 1; j < WIDTH/2; j++)
    {
        cur = new, new = !cur;
        for (i = 1; i < WIDTH-1; i++)
            line[new][i] = ft_get_next(&line[cur][i]);

        ft_print_line(line[new]);
    }

    free(line[0]);
    free(line[1]);
    free(line);
    return 0;
}



  • Partager sur Facebook
  • Partager sur Twitter
Vive le peupl et les clémentines !
21 décembre 2013 à 18:05:26

Pouet_forever : qu'entends-tu par une table ?

nodrak : Il me semble que calloc fait exactement ce que tu veux (l.15-16). Et l.24, il y a deux opérateurs '!' à la suite. Etourderie ?

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

^ Je pense que ça agit comme un cast en booléen : !!3 == 1, mais il se peut que je me trompe.

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

Etant donné que le résultat est un 1 décalé de n bits (n entre 0 et 7) vers la gauche, avec un masque (& TYPE), le résultat est toujours binaire (ou booléen). Donc je ne pense pas que ce soit une sorte de "cast". D'ailleurs, pour faire d'une valeur un booléen, je pense qu'on utilise plutôt la comparaison avec 0 : != 0.
  • Partager sur Facebook
  • Partager sur Twitter
21 décembre 2013 à 20:25:56

Bonjour,

!! est une double négation qui force un résultat à 0 ou 1,

!128 = 0,

!!128 = !0 = 1.

EDIT: comme avait pensé Scroph en fait

-
Edité par fromvega 21 décembre 2013 à 20:35:45

  • Partager sur Facebook
  • Partager sur Twitter
21 décembre 2013 à 20:42:23

Effectivement, après quelques recherches, je sais maintenant que c'est souvent utilisé. Je n'avais jamais vu ça avant (et d'ailleurs je préfère toujours la comparaison explicite à 0). Toujours est-il que c'est inutile dans ce cas précis, n'est-ce pas ?
  • Partager sur Facebook
  • Partager sur Twitter
21 décembre 2013 à 20:53:38

Nelxiost a écrit:

Effectivement, après quelques recherches, je sais maintenant que c'est souvent utilisé. Je n'avais jamais vu ça avant (et d'ailleurs je préfère toujours la comparaison explicite à 0). Toujours est-il que c'est inutile dans ce cas précis, n'est-ce pas ?


Dans le code de Nodrak il ne s'agit pas d'une comparaison mais d'une affectation, la valeur de retour de la fonction ft_get_next sera forcée à 0 ou 1 (valeur retournée dans le tableau line).
  • Partager sur Facebook
  • Partager sur Twitter
21 décembre 2013 à 21:58:59

!!n et n != 0 sont équivalents, et les deux sont des comparaisons. Après, on peut affecter le résultat d'une comparaison (un test booléen) à une variable, mais ce n'est pas la question...

En tout cas, les deux me donnent le même résultat : 1 pour tout nombre non-nul, 0 sinon.

#include <stdio.h>

int main(void)
{
  printf("%d, %d", !!2, 2 != 0);
  return 0;
}

Après, c'est sûrement une question de goût : je préfère ce qui est explicite (dans le premier cas, il serait facile d'oublier un '!' ou de penser en relisant que c'est une étourderie - comme je l'ai cru au départ).

  • Partager sur Facebook
  • Partager sur Twitter
22 décembre 2013 à 13:58:24

Moi j'aime bien le coup du !! je l'utilise de temps en temps c'est rigolo. ^^

Pour le coup de la table, c'est un truc comme ça :

#include <stdio.h>
#include <time.h>

int main(void) {
  char s[] = "000001100000";
  unsigned rule = 0x1E;
  unsigned ngen = 10000000;
  unsigned i, j, n;
  unsigned table[8] = {
    (rule & 1) + '0',
    ((rule >> 1) & 1) + '0',
    ((rule >> 2) & 1) + '0',
    ((rule >> 3) & 1) + '0',
    ((rule >> 4) & 1) + '0',
    ((rule >> 5) & 1) + '0',
    ((rule >> 6) & 1) + '0',
    ((rule >> 7) & 1) + '0'
  };
  
  clock_t t = clock();
  
  for (i = 0; i < ngen; i++) {
    n = (s[0] - '0') << 1;
    for (j = 0; s[j]; j++) {
      n = ((n << 1) | (s[j + 1] ? (s[j + 1] - '0') : 0)) & 0x7;
      s[j] = table[n];
    }
  }
  
  printf("%lf", (double) clock() - t);
  return 0;
}



  • Partager sur Facebook
  • Partager sur Twitter
22 décembre 2013 à 14:32:20

J'ai essayé de comprendre vos code mais.. Je suis un peu perdu xD. Il y aurait moyen que l'un de vous m'explique comment ça fonctionne ?

J'ai fait un truc mais je comprend pas l'utilisation de la règle, comment vous faite ? Parce que moi (page 1) je fais unt ruc bien galère...

Edit : J'ai pris un papier et je crois avoir compris, merci quand meme

Edit 2 : Je peux mp l'un de vous ? J'ai une question et ej veux laisser les autres essayer de comprendre :)

-
Edité par Ricocotam 22 décembre 2013 à 14:49:24

  • Partager sur Facebook
  • Partager sur Twitter
22 décembre 2013 à 14:41:15

Etrange : chez moi, c'est beaucoup plus lent (1730/570 comparé à 1050/440) ... J'ai loupé quelque chose ?
  • Partager sur Facebook
  • Partager sur Twitter
22 décembre 2013 à 14:46:49

Ricocotam a écrit:

J'ai essayé de comprendre vos code mais.. Je suis un peu perdu xD. Il y aurait moyen que l'un de vous m'explique comment ça fonctionne ?

J'ai fait un truc mais je comprend pas l'utilisation de la règle, comment vous faite ? Parce que moi (page 1) je fais unt ruc bien galère...


Bonjour,

Un principe de base c'est que tu ne dois pas modifier la chaine directement, car tu vas réutiliser des valeurs modifiées pour les cellules suivantes ce qui va fausser ton calcul. Le calcul de la génération suivante se fait globalement avec les valeurs de l'ancienne génération. Donc soit tu travailles sur 2 buffers last, next que tu permutes à chaque génération, soit tu sauvegardes les valeurs avant modifications pour faire le bon calcul.

  • Partager sur Facebook
  • Partager sur Twitter
22 décembre 2013 à 14:50:43

Oui, faudrait que je recommence je crois parce que c'est un peu pas terrible ce que j'ai fait :).

Mais je comprend pas comment utiliser la règle. Ce que j'ai fait ca n'a rien a voir...

  • Partager sur Facebook
  • Partager sur Twitter
22 décembre 2013 à 15:03:06

Peut-être le mieux c'est que tu expliques comment tu as compris l'exposé de paraze, et qu'on rectifie si besoin...
  • Partager sur Facebook
  • Partager sur Twitter
22 décembre 2013 à 15:22:54

J'ai compris l'exo j'en suis sûr, c'est le comment que je suis pas sur ^^.

Si tu regardes mon code, je cré des patrons pour chaque cas. Alors qu'en fait il faut faire un modèle et travailler à partir de celui ci. Mais je comprend pas comment on travail dessus, je comprend pas ce qu'elle veut dire cette règle 30 :).

  • Partager sur Facebook
  • Partager sur Twitter
22 décembre 2013 à 15:36:39

Ricocotam a écrit:

J'ai compris l'exo j'en suis sûr, c'est le comment que je suis pas sur ^^.

Si tu regardes mon code, je cré des patrons pour chaque cas. Alors qu'en fait il faut faire un modèle et travailler à partir de celui ci. Mais je comprend pas comment on travail dessus, je comprend pas ce qu'elle veut dire cette règle 30 :).


D'après ce que je vois tu fais saisir la règle à l'utilisateur, pourquoi pas, après pour que cela corresponde avec la règle 30 il faudrait saisir dans AVANT/APRES:

AVANT APRES    VALEUR

"000"     '0'               0

"001"     '1'               2

"010"     '1'               4

"011"     '1'               8

"100"     '1'               16

"101"     '0'               0

"110"     '0'               0

"111"     '0'               0

J'ai rajouté une colonne qui correspond à la valeur du bit si tu prends la colonne APRES comme un entier sur 8 bits. Tu vois que la somme  de la colonne VALEUR donne 30. C'est pour cela qu'on l'appelle la règle 30, et il y a donc 256 règles différentes en tout (le nombre de valeur d'un entier 8 bits).

Par contre j'ai vu que tu faisais saisir la chaine en entrée à l'utilisateur, et qu'ensuite tu la remplis de '0'... o_O

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

Bonjour :)

Une petite version, sans prétention pour le rules30.

#include <stdio.h>

#define N_GEN   10
#define N_CELLS 10

int cellContents(int *t, int pos){

    return (pos < 0 || pos >= N_CELLS) ? 0 : t[pos];
}

int changeState(int st){

    static int rules[] = {0, 1, 1, 1, 1, 0, 0, 0};
    return rules[st];
}

void displayCells(int (*t)[N_GEN], int n){

    for(int i = 0; i < N_CELLS; i++){
        printf("%d", t[n % 2][i]);
    }
    puts("");
}

void generate(int (*t)[N_GEN], int n){

     for(int gen = 0; gen < n; gen++){
        for(int crtCell = 0; crtCell < N_CELLS; crtCell++){
            int state = 0;
            for(int i = -1; i <= 1; i++){
                state += cellContents(t[gen % 2], crtCell + i) << (2 - (i + 1));
                t[(gen + 1) % 2][crtCell] = changeState(state);
            }
        }
    }
}

int main(void)
{
    int cells[2][N_CELLS] = {{0},{0}};
    // Construction de la con,fig de départ
    cells[0][N_CELLS / 2] = 1;

    generate(cells, N_GEN);
    displayCells(cells, N_GEN);

    return 0;
}

C'est bien, il y a tout de même un peu d'activité ici.
Et, salut Pouet :)

  • Partager sur Facebook
  • Partager sur Twitter
Zeste de Savoir, le site qui en a dans le citron !