Partage

[FAIT][Défis] #2 : Le jeu de la vie !

SDL

10 septembre 2011 à 15:35:00

Bon très bien, je remets mon code initial avec l'ancienne entête de mes projets. Pour l'instant les améliorations que je dois apporter aux code sont :
- Mettre plus de fonctions
- Corriger les allocations dynamique.

Je modifirais tout ça quand j'aurais le temps :)
10 septembre 2011 à 17:38:48

Je me suis amusé à faire le défi mais avec un tableau unidimensionnel et en travaillant directement sur les pixels :pirate: (un tableau de 10 x 10 signifie donc une fenêtre de 10 x 10 pixels).

/* compile: gcc main.c -o life_game.exe -lmingw32 -lSDLmain -lSDL */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <dirent.h>
#include <SDL/SDL.h>

#define WIDTH (200)
#define HEIGHT (150)
#define NBR_CELLS (WIDTH * HEIGHT)
#define DEPTH (16)
#define APP_NAME "jeu de la vie"

typedef struct
{
    char key[SDLK_LAST];
    char mousebutton[8];
    char quit;
    int mousex, mousey, mousexrel, mouseyrel;
} Input;

SDL_Surface *Init(void);
unsigned char ToggleFullScreen(unsigned char mode);
void PutPixel(SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 pixel);
unsigned char UpdateInput(Input *in);
void framerate(Uint32 fps);
void Screenshot(SDL_Surface *toSave);
unsigned char mouseInScreen(int x, int y);
unsigned char getNeighbor(unsigned char *tab, unsigned int i);

int main(int argc, char *argv[])
{
    /* Déclarations */
    SDL_Surface *screen = NULL;
    unsigned char tab0[NBR_CELLS], tab[NBR_CELLS];
    unsigned int i = 0;
    unsigned char cpt = 0, press = 0, isPaused = 1, isFullScreen = 0;
    Uint32 prev = 0, now = 0;
    Input in;

    if((screen = Init()) != NULL)
    {
        /* Initialisations */
        Uint32 dead = SDL_MapRGB(screen->format, 255, 255, 255);
        Uint32 alive = SDL_MapRGB(screen->format, 255, 0, 0);
        memset(tab0, 0, sizeof(*tab0) * NBR_CELLS);
        memset(tab, 0, sizeof(*tab) * NBR_CELLS);
        memset(&in, 0, sizeof(Input));
        prev = SDL_GetTicks();
        srand(time(NULL));

        /* Boucle principale */
        while(!in.key[SDLK_ESCAPE] == 1 && !in.quit)
        {
            press = UpdateInput(&in);

            if(in.key[SDLK_p]) // toogle pause
            {
                isPaused ^= 1;
                in.key[SDLK_p] = 0;
            }
            if(in.key[SDLK_s]) // screenshot
            {
                Screenshot(screen);
                in.key[SDLK_s] = 0;
            }
            if(in.key[SDLK_f]) // fullscreen
            {
                isFullScreen = ToggleFullScreen(isFullScreen);
                in.key[SDLK_f] = 0;
            }

            if(isPaused)
            {
                if(in.mousebutton[0] && mouseInScreen(in.mousex, in.mousey)) //clic de souris (change l'état de la cellule)
                {
                    tab[in.mousey * WIDTH + in.mousex] ^= 1;
                    in.mousebutton[0] = 0;
                }
                if(in.key[SDLK_r]) // remplissage aléatoire
                {
                    for(i = 0; i < NBR_CELLS; i++)
                        tab[i] = rand() % 2;
                    in.key[SDLK_r] = 0;
                }
            }
            else
            {
                now = SDL_GetTicks();
                if(now - prev > 500) // mise à jour toutes les demi-secondes
                {
                    memcpy(tab0, tab, sizeof(*tab0) * NBR_CELLS);
                    for(i = 0; i < NBR_CELLS; i++)
                    {
                        cpt = getNeighbor(tab0, i);

                        if(tab[i])
                            tab[i] = (cpt < 2 || cpt > 3) ? 0 : 1;
                        else
                            tab[i] = (cpt == 3) ? 1 : 0;
                    }
                    prev = now;
                }
            }

            /* Rendu */
            SDL_LockSurface(screen);
            for(i = 0; i < NBR_CELLS; i++)
            {
                if(tab[i])
                    PutPixel(screen, i%WIDTH, i/WIDTH, alive);
                else
                    PutPixel(screen, i%WIDTH, i/WIDTH, dead);
            }
            SDL_UnlockSurface(screen);

            framerate(60);
            SDL_Flip(screen);
        }
    }

    return EXIT_SUCCESS;
}

SDL_Surface *Init(void)
{
    SDL_Surface *tmp = NULL;

    if(SDL_Init (SDL_INIT_VIDEO) < 0)
    {
		fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
		return NULL;
	}

	atexit(SDL_Quit);

	tmp = SDL_SetVideoMode(WIDTH, HEIGHT, DEPTH, SDL_HWSURFACE | SDL_DOUBLEBUF);
	if(tmp == NULL)
    {
		fprintf(stderr, "Couldn't set %dx%dx%d video mode: %s\n", WIDTH, HEIGHT, DEPTH, SDL_GetError());
		return NULL;
	}

	SDL_WM_SetCaption(APP_NAME, NULL);

	return tmp;
}

unsigned char ToggleFullScreen(unsigned char mode) // peut être un peu crade...
{
    mode ^= 1;
    SDL_Surface *tmp = SDL_GetVideoSurface();
    tmp = SDL_SetVideoMode(WIDTH, HEIGHT, DEPTH, SDL_HWSURFACE | SDL_DOUBLEBUF | (mode ? SDL_FULLSCREEN : 0));
    return mode;
}

void PutPixel(SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 pixel)
{
    if(dst == NULL) return;
    int bpp = dst->format->BytesPerPixel;
    /* Here p is the address to the pixel we want to set */
    Uint8 *p = (Uint8 *)dst->pixels + y * dst->pitch + x * bpp;

    switch(bpp) {
    case 1:
        *p = pixel;
        break;

    case 2:
        *(Uint16 *)p = pixel;
        break;

    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
            p[0] = (pixel >> 16) & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = pixel & 0xff;
        } else {
            p[0] = pixel & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = (pixel >> 16) & 0xff;
        }
        break;

    case 4:
        *(Uint32 *)p = pixel;
        break;
    }
}

unsigned char UpdateInput(Input *in)
{
    unsigned char press = 0;
    SDL_Event event;
    while(SDL_PollEvent(&event))
    {
        switch(event.type)
        {
            case SDL_QUIT:
                in->quit = 1;
            break;
            case SDL_KEYDOWN:
                in->key[event.key.keysym.sym] = 1;
                press = 1;
            break;
            case SDL_KEYUP:
                in->key[event.key.keysym.sym] = 0;
            break;
            case SDL_MOUSEMOTION:
                in->mousex = event.motion.x;
                in->mousey = event.motion.y;
                in->mousexrel = event.motion.xrel;
                in->mouseyrel = event.motion.yrel;
            break;
            case SDL_MOUSEBUTTONDOWN:
                in->mousebutton[event.button.button-1] = 1;
                press = 1;
            break;
            case SDL_MOUSEBUTTONUP:
                in->mousebutton[event.button.button-1] = 0;
            break;
            default:
            break;
        }
    }
    return press;
}

void framerate(Uint32 fps)
{
     static Uint32 next_time = 0;
     Uint32 now;

     now = SDL_GetTicks();
     if(next_time <= now)
         next_time = now + (1000 / fps);
     else
         SDL_Delay(next_time - now);
}

void Screenshot(SDL_Surface *toSave)
{
    int nbr = 0;
    char str[25];
    struct dirent *ent = NULL;
    DIR *rep = NULL;

    if((rep = opendir("./screenshot")) == NULL)
    {
#ifdef WIN32
        mkdir("screenshot");
#endif
#ifdef LINUX
        mkdir("screenshot", 0777);
#endif
        rep = opendir("./screenshot");
    }

    while((ent = readdir(rep)) != NULL)
    {
        if(strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0)
            nbr++;
    }

    if(closedir(rep) == -1)
        return;

    sprintf(str, "./screenshot/img_%03d.bmp", nbr);
    SDL_SaveBMP(toSave, str);
}

unsigned char mouseInScreen(int x, int y)
{
    if(x >= 0 && x < WIDTH && y >= 0 && y < HEIGHT)
        return 1;
    else
        return 0;
}

unsigned char getNeighbor(unsigned char *tab, unsigned int i)
{
    unsigned int cpt = 0;
    unsigned int x = i%WIDTH;
    unsigned int y = i/WIDTH;

    if(x >= 0 && x < WIDTH && y >= 0 && y < HEIGHT)
    {
        if(x != 0 && y != 0)                cpt += tab[i-WIDTH-1];
        if(y != 0)                          cpt += tab[i-WIDTH];
        if(x != WIDTH-1 && y != 0)          cpt += tab[i-WIDTH+1];
        if(x != 0)                          cpt += tab[i-1];
        if(x != WIDTH-1)                    cpt += tab[i+1];
        if(x != 0 && y != HEIGHT-1)         cpt += tab[i+WIDTH-1];
        if(y != HEIGHT-1)                   cpt += tab[i+WIDTH];
        if(x != WIDTH-1 && y != HEIGHT-1)   cpt += tab[i+WIDTH+1];
    }
    return cpt;
}


Compile sous Windows (pas testé Linux) avec : gcc main.c -o life_game.exe -lmingw32 -lSDLmain -lSDL

touches :
  • p - play/pause
  • f - fullscreen/fenêtré
  • s - prendre un screenshot
  • r - remplir la grille éléatoirement (uniquement en pause)
  • clic gauche - changer l'état d'une cellule (uniquement en pause)


J'ai quand même un doute sur la validité de mon algorithme mais bon. :-°
En plus j'ai quand même 300 lignes de codes ....
10 septembre 2011 à 17:59:27

Je me suis amusé à en faire un avec la SDL, mais OpenGL pour le dessin… et pour calculer les différentes étapes de la simulation :)
#include <GL/glew.h>
#include <SDL/SDL.h>
#include <stdlib.h>
#include <time.h>

#include "stb_image.h"

#define STB_IMAGE_WRITE_IMPLEMENTATION 1
#include "stb_image_write.h"

#define CellWidth  10
#define CellHeight 10

#define WindowWidth  640
#define WindowHeight 480

#define BufferWidth  (WindowWidth  / CellWidth)
#define BufferHeight (WindowHeight / CellHeight)

#define LifeColor  255
#define DeathColor 10

#define DoStringify(s) #s
#define Stringify(s)   DoStringify(s)

#define GLSLWidth  "const float width  = 1.0 / " Stringify(BufferWidth)  ";\n"
#define GLSLHeight "const float height = 1.0 / " Stringify(BufferHeight) ";\n"

#define GLSLLifeColor  "const float life_color  = " Stringify(LifeColor) \
  " / 255.0;\n"
#define GLSLDeathColor "const float death_color = " Stringify(DeathColor) \
  " / 255.0;\n"

#define FPS                   60
#define TimePerLoop           (1000 / FPS)
#define MustSleep(duration)   (TimePerLoop > (duration))
#define TimeToSleep(duration) (TimePerLoop - (duration))

/*
 * Always falls through.
 */
const char *vertex_shader =
  "#version 150\n"
  "in vec2 pos;\n"
  "in vec2 tex_coord;\n"
  "out vec2 var_tex_coord;\n"
  "void main() {\n"
  "  gl_Position   = vec4(pos, 0, 1);\n"
  "  var_tex_coord = tex_coord;\n"
  "}\n";

/*
 * Computes the next step of the game of life.
 */
const char *life_fragment_shader =
  "#version 150\n"
  "\n"
  GLSLWidth
  GLSLHeight
  "\n"
  GLSLLifeColor
  GLSLDeathColor
  "\n"
  "const vec3 alive_vector = vec3(life_color, life_color, life_color);\n"
  "\n"
  "uniform sampler2D tex;\n"
  "\n"
  "in  vec2 var_tex_coord;\n"
  "out vec4 frag_color;\n"
  "\n"
  "bvec3 is_alive(vec2 pos) {\n"
  "  return equal(texture(tex, var_tex_coord + pos).rgb, alive_vector);\n"
  "}\n"
  "\n"
  "ivec3 increase_for(vec2 pos) {\n"
  "  bvec3 val = is_alive(pos);\n"
  "  return ivec3(val.x ? 1 : 0, val.y ? 1 : 0, val.z ? 1 : 0);\n"
  "}\n"
  "\n"
  "ivec3 count_neighbours() {\n"
  "  ivec3 count = ivec3(0, 0, 0);\n"
  "\n"
  "  count += increase_for(vec2(-width, -height));\n"
  "  count += increase_for(vec2(-width, +height));\n"
  "  count += increase_for(vec2(+width, -height));\n"
  "  count += increase_for(vec2(+width, +height));\n"
  "\n"
  "  count += increase_for(vec2(+width, 0));\n"
  "  count += increase_for(vec2(-width, 0));\n"
  "  count += increase_for(vec2(0, +height));\n"
  "  count += increase_for(vec2(0, -height));\n"
  "\n"
  "  return count;\n"
  "}\n"
  "\n"
  "void main() {\n"
  "  frag_color = vec4(0, 0, 0, 1);\n"
  "\n"
  "  ivec3 count = count_neighbours();\n"
  "  bvec3 alive = is_alive(vec2(0, 0));"
  "\n"
  "  for (int i = 0; i < 3; i++) {"
  "    if (alive[i]) {\n"
  "      if (count[i] == 2 || count[i] == 3)\n"
  "        frag_color[i] = life_color;\n"
  "      else\n"
  "        frag_color[i] = death_color;\n"
  "    }\n"
  "    else if (count[i] == 3)\n"
  "      frag_color[i] = life_color;\n"
  "    else\n"
  "      frag_color[i] = death_color;\n"
  "  }\n"
  "}\n";

/*
 * Just falls through
 */
const char *normal_fragment_shader =
  "#version 150\n"
  "uniform sampler2D tex;\n"
  "in vec2 var_tex_coord;\n"
  "out vec4 frag_color;\n"
  "void main() {\n"
  "  frag_color = texture(tex, var_tex_coord);"
  "}\n";

GLuint create_shader(GLenum mode, const char *src) {
  GLuint ret = glCreateShader(mode);
  GLint length = strlen(src);
  glShaderSource(ret, 1, &src, &length);
  glCompileShader(ret);

  GLint worked = 0;
  glGetShaderiv(ret, GL_COMPILE_STATUS, &worked);

  if (worked != GL_TRUE) {
    GLint error_length = 0;
    glGetShaderiv(ret, GL_INFO_LOG_LENGTH, &error_length);

    char *error = calloc(error_length + 1, sizeof(char));

    if (!error) {
      fprintf(stderr, "Could not allocate errror buffer!\n");
      exit(1);
    }

    glGetShaderInfoLog(ret, error_length, &error_length, error);
    fprintf(stderr, "Compile error:\n%s", error);

    free(error);

    exit(1);
  }

  return ret;
}

GLuint build_program(GLuint vert, GLuint frag) {
  GLuint prog = glCreateProgram();
  glAttachShader(prog, vert);
  glAttachShader(prog, frag);
  glBindFragDataLocation(prog, 0, "frag_color");
  glBindAttribLocation(prog, 0, "pos");
  glBindAttribLocation(prog, 1, "tex_coord");
  glLinkProgram(prog);

  GLint worked = 0;
  glGetProgramiv(prog, GL_LINK_STATUS, &worked);

  if (!worked) {
    GLint error_length = 0;
    glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &error_length);

    char *error = calloc(error_length + 1, sizeof(char));

    if (!error) {
      fprintf(stderr, "Could not allocate errror buffer!\n");
      exit(1);
    }

    glGetProgramInfoLog(prog, error_length, &error_length, error);
    fprintf(stderr, "Compile error:\n%s", error);

    free(error);

    exit(1);
  }

  glUseProgram(prog);
  glUniform1i(glGetUniformLocation(prog, "tex"), 0);

  return prog;
}

typedef struct vertex {
  GLfloat x, y;
  GLfloat tex_x, tex_y;
} vertex;

vertex vertices[] = {
  {-1, -1, 0, 0},
  {-1, +1, 0, 1},
  {+1, -1, 1, 0},
  {+1, +1, 1, 1}
};

typedef struct color {
  GLubyte r, g, b;
} color;

typedef struct buffer {
  GLuint tex;
  GLuint fbo;

  color colors[BufferWidth * BufferHeight];
} buffer;

typedef struct life_state {
  buffer buffers[2];
  int current;

  GLuint prog;
} life_state;

int color_eq(color a, color b) {
  return a.r == b.r && a.g == b.g && a.b == b.b;
}

void buffer_init(buffer *buf) {
  size_t i = 0;
  srand(time(NULL));

  for (; i < BufferWidth * BufferHeight; i++) {
    GLubyte r = rand() % 2 ? LifeColor : DeathColor;
    GLubyte g = rand() % 2 ? LifeColor : DeathColor;
    GLubyte b = rand() % 2 ? LifeColor : DeathColor;
    buf->colors[i] = (color){r, g, b};
  }

  glGenTextures(1, &buf->tex);
  glBindTexture(GL_TEXTURE_2D, buf->tex);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, BufferWidth, BufferHeight, 0,
               GL_RGB, GL_UNSIGNED_BYTE, buf->colors);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glGenerateMipmap(GL_TEXTURE_2D);

  glGenFramebuffers(1, &buf->fbo);
  glBindFramebuffer(GL_FRAMEBUFFER, buf->fbo);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                         GL_TEXTURE_2D, buf->tex, 0);

  GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  if (status != GL_FRAMEBUFFER_COMPLETE) {
    fprintf(stderr, "Could not create framebuffer!\n");
    exit(1);
  }
}

void buffer_release(buffer *buf) {
  glDeleteTextures(1, &buf->tex);
  glDeleteFramebuffers(1, &buf->fbo);
}

void life_init(life_state *life, GLuint prog) {
  buffer_init(&life->buffers[0]);
  buffer_init(&life->buffers[1]);

  life->current = 0;
  life->prog    = prog;
}

void life_update(life_state *life) {
  int next = life->current ? 0 : 1;

  glUseProgram(life->prog);
  glBindFramebuffer(GL_FRAMEBUFFER, life->buffers[next].fbo);
  glViewport(0, 0, BufferWidth, BufferHeight);
  glBindTexture(GL_TEXTURE_2D, life->buffers[life->current].tex);
  glClear(GL_COLOR_BUFFER_BIT);
  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  glBindFramebuffer(GL_FRAMEBUFFER, 0);

  life->current = next;
}

void life_bind_texture(life_state *life) {
  glBindTexture(GL_TEXTURE_2D, life->buffers[life->current].tex);
}

void life_download(life_state *life) {
  life_bind_texture(life);
  glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE,
                life->buffers[life->current].colors);
}

void life_upload(life_state *life) {
  life_bind_texture(life);
  glTexSubImage2D(GL_TEXTURE_2D, 0,
                  0, 0,
                  BufferWidth, BufferHeight,
                  GL_RGB, GL_UNSIGNED_BYTE,
                  life->buffers[life->current].colors);
}

void color_buffer_flip(const color *buffer, color *flipped_buffer) {
  size_t line_size = sizeof(color) * BufferWidth;

  size_t y;
  for (y = 0; y < BufferHeight; y++) {
    memcpy(&flipped_buffer[y * BufferWidth],
           &buffer[(BufferHeight - y - 1) * BufferWidth],
           line_size);
  }
}

void life_save_as(life_state *life, const char *filename) {
  life_download(life);

  color flipped_buffer[BufferWidth * BufferHeight];
  color_buffer_flip(life->buffers[life->current].colors, flipped_buffer);

  if (!stbi_write_bmp(filename, BufferWidth, BufferHeight, 3,
                      flipped_buffer)) {
    fprintf(stderr, "Could not save file!\n");
    exit(1);
  }
}

void life_load(life_state *life, const char *filename) {
  int width, height, comp;
  stbi_uc *buf = stbi_load(filename, &width, &height, &comp, 3);
  if (!buf) {
    fprintf(stderr, "Could not load file (%s)!\n", stbi_failure_reason());
    exit(1);
  }

  if (width != BufferWidth || height != BufferHeight) {
    fprintf(stderr, "Image sizes don't match, expected %dx%d, but "
            "received %dx%d", BufferWidth, BufferHeight, width, height);
    exit(1);
  }

  color_buffer_flip((color*)buf, life->buffers[life->current].colors);

  stbi_image_free(buf);

  life_upload(life);
}

void life_toggle(life_state *life, int x, int y, int comp) {
  int index = x + (BufferHeight - y - 1) * BufferWidth;
  GLubyte *ptr = &life->buffers[life->current].colors[index].r;

  if (ptr[comp] == LifeColor) {
    ptr[comp] = DeathColor;
  }
  else {
    ptr[comp] = LifeColor;
  }

  life_bind_texture(life);
  glTexSubImage2D(GL_TEXTURE_2D, 0,
                  x, BufferHeight - y - 1,
                  1, 1,
                  GL_RGB, GL_UNSIGNED_BYTE, ptr);
}

void life_release(life_state *life) {
  buffer_release(&life->buffers[0]);
  buffer_release(&life->buffers[1]);
}

int main(int argc, char **argv) {
  if (SDL_Init(SDL_INIT_VIDEO) != 0) {
    fprintf(stderr, "Could not init SDL!\n");
    exit(1);
  }

  if (!SDL_SetVideoMode(WindowWidth, WindowHeight, 32, SDL_OPENGL)) {
    fprintf(stderr, "Could not create window!\n");
    exit(1);
  }

  if (glewInit() != GLEW_OK) {
    fprintf(stderr, "Could not initialze GLEW!");
    exit(1);
  }

  if (!GLEW_VERSION_3_2) {
    fprintf(stderr, "OpenGL version 3.2 is not supported!\n");
    exit(1);
  }

  glClearColor(DeathColor / 255.0, DeathColor / 255.0, DeathColor / 255.0, 1.0);

  GLuint vbo;
  glGenBuffers(1, &vbo);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

  GLuint vao;
  glGenVertexArrays(1, &vao);
  glBindVertexArray(vao);
  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), NULL);
  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex),
                        (void*)(offsetof(vertex, tex_x)));

  glEnableVertexAttribArray(0);
  glEnableVertexAttribArray(1);

  GLuint vert        = create_shader(GL_VERTEX_SHADER, vertex_shader);
  GLuint life_frag   = create_shader(GL_FRAGMENT_SHADER, life_fragment_shader);
  GLuint normal_frag = create_shader(GL_FRAGMENT_SHADER,
                                     normal_fragment_shader);

  GLuint life_prog   = build_program(vert, life_frag);
  GLuint normal_prog = build_program(vert, normal_frag);

  life_state life;
  life_init(&life, life_prog);

  if (argc >= 2) {
    life_load(&life, argv[1]);
  }

  int running = 1;
  int paused  = 0;
  uint32_t last_ticks = SDL_GetTicks();
  while (running) {
    SDL_Event ev;
    while (SDL_PollEvent(&ev)) {
      if (ev.type == SDL_QUIT)
        running = 0;
      else if (ev.type == SDL_KEYDOWN) {
        if (ev.key.keysym.sym == SDLK_SPACE) {
          paused = !paused;

          if (paused)
            life_download(&life);
        }
        else if (ev.key.keysym.sym == SDLK_s) {
          life_save_as(&life, "output.bmp");
        }
      }
      else if (ev.type == SDL_MOUSEBUTTONUP && paused) {
        int x = ev.button.x / CellWidth;
        int y = ev.button.y / CellHeight;

        int comp = 0;
        switch (ev.button.button) {
        case SDL_BUTTON_LEFT:   comp = 0; break;
        case SDL_BUTTON_MIDDLE: comp = 1; break;
        case SDL_BUTTON_RIGHT:  comp = 2; break;
        }

        life_toggle(&life, x, y, comp);
      }
    }

    if (!paused)
      life_update(&life);

    glViewport(0, 0, WindowWidth, WindowHeight);

    life_bind_texture(&life);
    glUseProgram(normal_prog);
    glClear(GL_COLOR_BUFFER_BIT);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    SDL_GL_SwapBuffers();

    uint32_t new_ticks = SDL_GetTicks();
    uint32_t ellapsed  = new_ticks - last_ticks;
    if (MustSleep(ellapsed))
      SDL_Delay(TimeToSleep(ellapsed));
    last_ticks = SDL_GetTicks();
  }

  life_release(&life);

  glDeleteShader(vert);
  glDeleteShader(life_frag);
  glDeleteShader(normal_frag);
  glDeleteProgram(life_prog);
  glDeleteProgram(normal_prog);
  glDeleteVertexArrays(1, &vao);
  glDeleteBuffers(1, &vbo);

  SDL_Quit();
  return 0;
}


J’ai utilsé la bibliothèque stb_image pour charger et sauvegarder des images :
stb_image.h
stb_image_write.h

Pour compiler : gcc life.c -o life -lSDL -lGL -lGLEW.

Il faut appuyer sur la barre espace pour mettre en pause ou faire continuer l'animation. On peut charger une image en passant un chemin à l’exécutable, et sauvegarder en appuyant sur S. Les bouttons de la souris permettent d’activer ou désactiver une cellule pendant la pause.

La plupart des paramètres sontn fixés à la compilation (plus facile :-° ), par les defines au début du fichier.

Voilà une image de ce à quoi ça peut ressembler : http://uppix.net/9/f/a/7d8d67b9c4da37b6f0db568bd3b3b.png

Citation

accélérer; ralentir; mettre en arrière l'animation.


Revenir en arrière est impossible sans garder l’historique en mémoire : deux configurations peuvent donner le même résultat.
10 septembre 2011 à 19:30:20

Citation : Mon ouïe

Citation

accélérer; ralentir; mettre en arrière l'animation.


Revenir en arrière est impossible sans garder l’historique en mémoire : deux configurations peuvent donner le même résultat.


arf, c'est ce que je craignais.

Et bien... il faudrait pré-calculer toute la séquence dès le début.
Ainsi on pourrait se balader dans le temps et cela de manière hyper fluide.
11 septembre 2011 à 0:45:33

Juste pour le fun j'ai fais ce petit défis (niv 1 et 2), voici le code :
/* Un petit jeux de la vie */
/*
 * Cliquez pour définir une cellule morte ou vivante
 * Appuyez sur p pour démarrer ou arrêter le programme
 */

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

#define TAILLE_TAB_X 30 /* ses deux constantes ne servent que pour les fonctions qui n'ont pas de rapport directe avec le jeux de la vie */
#define TAILLE_TAB_Y 30

#define SCREEN_X 800
#define SCREEN_Y 600

void InitGameLife(char **tab, int taille_x, int taille_y);
int ReturnNeighborCell(char **tab, int px, int py);
void Update(char **tab, SDL_Surface *screen);
void SetCell(char **tab, int px, int py);
void AffCells(char **tab, SDL_Surface *screen,int taille_x, int taille_y);

int main (int argc, char *argv[]) 
{
         char **tab=NULL;
         SDL_Surface *screen=NULL;
         int i;
        
         tab = malloc(TAILLE_TAB_Y*sizeof(*tab));
         if(tab == NULL) {
                 puts("Impossible d'allouer la memoire pour le tableau.\nFin du programme.");
                 exit(-1);
         }
         for(i=0;i<TAILLE_TAB_Y;i++) {
                 tab[i] = malloc(TAILLE_TAB_X*sizeof(**tab));
                 if(tab[i] == NULL) {
                         puts("Impossible d'allouer la memoire pour le tableau.\nDesallocation de la mémoire déjà allouer.");
                         while(i) 
                                 free(tab[i--]);
                                
                         puts("Fin du programme.");
                         exit(-1);
                 }
         }
         if(SDL_Init(SDL_INIT_VIDEO) == -1) {
                printf("Erreur a l'initialisation de SDL : %s\nFermeture du programme.\n", SDL_GetError());
                exit(-1);
         }
         if((screen = SDL_SetVideoMode(SCREEN_X, SCREEN_Y, 32, SDL_HWSURFACE | SDL_DOUBLEBUF)) == NULL) {
                printf("Impossible d'ouvrir la fenetre err : %s.\nFermeture du programme.\n", SDL_GetError());
                exit(-1);
         }
         SDL_WM_SetCaption("Jeux de la vie", NULL);
         InitGameLife(tab, TAILLE_TAB_X, TAILLE_TAB_Y);

         Update(tab, screen);
         
         for(i=0;i<TAILLE_TAB_Y;i++)
                free(tab[i]); 
                
         free(tab);
         SDL_Quit();
         return 0;
}

void InitGameLife(char **tab, int taille_x, int taille_y)
{
        int i, j;
        for(i=0;i<taille_y;i++)
                for(j=0;j<taille_x;j++)
                        tab[i][j] = 0; /* 0 = cellule morte */
}

int ReturnNeighborCell(char **tab, int px, int py) 
{
        int tmp=0;
        /* CCC
         * CXC
         * CCC
         * Ceci est le schéma de ce que nous lisons (C) ici (X étant tab[px][py])
         */
        tmp += tab[py+1][px+1];
        tmp += tab[py+1][px];
        tmp += tab[py+1][px-1];
        
        tmp += tab[py-1][px-1];
        tmp += tab[py-1][px];
        tmp += tab[py-1][px+1];
        
        tmp += tab[py][px-1];
        tmp += tab[py][px+1];
        
        
        return tmp;   
}

void UpdateGameLife(char **tab, int taille_x, int taille_y)
{
        int i, j;
        int tmp;
        char **tab_tmp;
        
        tab_tmp = malloc(taille_y*sizeof(*tab_tmp));
        if(tab_tmp == NULL) {
                puts("Impossible d'allouer de la mémoire au tableau temporaire.");
                exit(-1);
        }
         for(i=0;i<taille_y;i++) {
                 tab_tmp[i] = malloc(taille_x*sizeof(**tab_tmp));
                 if(tab_tmp[i] == NULL) {
                         puts("Impossible d'allouer la memoire pour le tableau.\nDesallocation de la mémoire déjà allouer.");
                         while(i) 
                                 free(tab_tmp[i--]);
                                
                         puts("Fin du programme.");
                         exit(-1);
                 }
         }
         
        for(i=0;i<taille_y;i++) /* On copie dans un tableau temporaire (Sinon ... mettre a jours + controler fait mauvais ménage) */
                for(j=0;j<taille_x;j++)
                        tab_tmp[i][j] = tab[i][j];
        for(i=1;i<taille_y-1;i++) { /* J'avoue c'est facil. Mais au moins il y a moins de conditions a gérer pour le ReturnNeighborCell. */
                for(j=1;j<taille_x-1;j++) {
                                tmp = ReturnNeighborCell(tab_tmp, j, i);
                                if(tmp == 3 || tmp == 2 && tab_tmp[i][j]) 
                                        tab[i][j] = 1;
                                else if(tmp > 3 || tmp < 2)
                                        tab[i][j] = 0;
                }
        }
        
        for(i=0;i<taille_y;i++)
                free(tab_tmp[i]); 
        free(tab_tmp);
}

void SetCell(char **tab, int px, int py)
{
        px = px / (SCREEN_X / TAILLE_TAB_X);
        py = py / (SCREEN_Y / TAILLE_TAB_Y);
        tab[py][px] ^= 1;
}

void Update(char **tab, SDL_Surface *screen)
{
         char cont=1, run=0, mouse_app=0, p_app=0;
         int tps1;
         SDL_Event event;
         
          tps1 = SDL_GetTicks();
          while(cont) {
                SDL_PollEvent(&event);
                switch(event.type)
                {
                    case SDL_QUIT:
                        cont = 0;
                        break;   
                    case SDL_KEYDOWN:
                                switch (event.key.keysym.sym)
                                {
                                        case SDLK_ESCAPE:
                                                cont = 0;
                                                break;  
                                        case 'p':
                                                p_app=1;
                                                break;
                                        default:
                                                break;
                                }

                        break; 
                        
                    case SDL_KEYUP:
                                if(event.key.keysym.sym == 'p' && p_app) { /* moins bordélique qu'un éunième switch */
                                                p_app=0;
                                                run ^=1;
                                }
                        break; 
                        
                   case SDL_MOUSEBUTTONDOWN:
                        if (event.button.button == SDL_BUTTON_LEFT && run == 0) {
                                mouse_app = 1;
                        }
                        break;
                        
                   case SDL_MOUSEBUTTONUP:
                        if (event.button.button == SDL_BUTTON_LEFT && run == 0 && mouse_app==1) {
                                mouse_app = 0;
                                SetCell(tab, event.button.x, event.button.y);
                        }
                        break;
                        
                    default:
                        break;
                }
                
                if(run && (SDL_GetTicks() >= tps1 + 500)) { 
                        UpdateGameLife(tab, TAILLE_TAB_X, TAILLE_TAB_Y);
                        tps1 = SDL_GetTicks();
                 }
                        
                AffCells(tab, screen, TAILLE_TAB_X, TAILLE_TAB_Y);
                SDL_Flip(screen);
                SDL_Delay(1); /* Limite la conso processeur dans mon cas (si vous voulez vous jartez) */
         }
}

void AffCells(char **tab, SDL_Surface *screen,int taille_x, int taille_y)
{
        int i, j, ratio_x, ratio_y;
        SDL_Surface *CellSurf;
        SDL_Rect CellPos;
        
        ratio_x = SCREEN_X/taille_x;
        ratio_y = SCREEN_Y/taille_y;
        CellSurf = SDL_CreateRGBSurface(SDL_HWSURFACE, ratio_x, ratio_y, 32, 0, 0, 0, 0);
        
        for(i=1;i<taille_y-1;i++) {
                for(j=1;j<taille_x-1;j++) {
                                CellPos.x = j*ratio_x;
                                CellPos.y = i*ratio_y;
                                
                                if(tab[i][j])                 
                                        SDL_FillRect(CellSurf, NULL, SDL_MapRGB(screen->format, 200, 200, 200));
                                else
                                        SDL_FillRect(CellSurf, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
                                        
                                SDL_BlitSurface(CellSurf, NULL, screen, &CellPos);
                }
        }
        
        SDL_FreeSurface(CellSurf);
}


J'aurai pu faire l'affichage dans la fonction qui met à jours l'automate, seulement par soucis de lisibilité de l'algorithme, je l'ai laisser à part.
11 septembre 2011 à 1:07:12

@Damien7877:

Tu connais la taille de ton tableau à la compilation.
#define TAILLE_TAB_X 30 /* ses deux constantes ne servent que pour les fonctions qui n'ont pas de rapport directe avec le jeux de la vie */
#define TAILLE_TAB_Y 30


Pourquoi utiliser malloc?
Je pense que tu compliques ton code inutilement. ;)

edit: aussi, ta fonction
int ReturnNeighborCell(char **tab, int px, int py)

est maladroite.
2 boucle imbriquées variant de -1 à 1 et c'est plié. ;)
Zeste de Savoir, le site qui en a dans le citron !
11 septembre 2011 à 1:10:22

Je pense continuer ce programme avec des tableaux plus grands (de l'ordre de la taille de la fenêtre) avec l'enregistrement dans les fichiers tout ça donc j'ai directement implanter les mallocs (les tableaux taille fixe de grande capacité ça ne m'a jamais bien plu).

Mais je suis d'accord qu'ici pour poster le code j'aurai pu ne pas utiliser les malloc et j'en suis conscient ;)

Edit : Reflexion faite tu as entièrement raison, je vais le réécrire plus simplement pour le défis pour que tout le monde puisse le comprendre simplement ;)
11 septembre 2011 à 10:22:37

Alors, ci-dessous mon code pour le niveau 2 pas encore commenté. :-°
Il gère les screenshots, permet d'enregistrer une position au format .zgl (Zero Game of Life :p ). Je réfléchis actuellement au codage de ma fonction load, qui va permettre de charger une position.

/* « J'y crois, tout est possible, tout est réalisable, 
 *    c'est le jeu de la vie ! » C-L */

#include <stdlib.h>
#include <SDL/SDL.h>


#define FLAGS_INIT 		SDL_INIT_VIDEO | SDL_INIT_TIMER

#define WIDTH			640
#define HEIGHT			480
#define BITS_PER_CELL		32

#define TITLE			"Site du zéro : jeu de la vie"
#define TITLE_ICON		"Jeu de la vie"

#define CELL			20
#define NB_CELLS_WIDTH	 	WIDTH / CELL
#define NB_CELLS_HEIGHT		HEIGHT / CELL

#define ALIVE			1
#define DEAD			0

#define DELAY			100


typedef struct {
    char key[SDLK_LAST];
    int mousex, mousey;
    char mousebuttons[8];
    char quit;
} Input;


static int init_lib(void)
{
    if (SDL_Init(FLAGS_INIT) == -1) {
	fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError());
	return 0;
    }

    return 1;
}

static int init_video(void)
{
    SDL_Surface *screen;

    if (!
	(screen =
	 SDL_SetVideoMode(WIDTH, HEIGHT, BITS_PER_CELL,
			  SDL_HWSURFACE | SDL_DOUBLEBUF))) {
	fprintf(stderr, "SDL_SetVideoMode failed: %s\n", SDL_GetError());
	return 0;
    }

    return 1;
}

static void routine_quit_lib(void)
{
    atexit(SDL_Quit);
}

static void set_title(void)
{
    SDL_WM_SetCaption(TITLE, TITLE_ICON);
}

static int init(void)
{
    if (!init_lib()) {
	return 0;
    }

    routine_quit_lib();

    if (!init_video()) {
	return 0;
    }

    set_title();

    SDL_EnableUNICODE(SDL_ENABLE);

    return 1;
}

static void analyse_press_button_mouse(SDL_Event event, Input * in)
{
    if (event.button.button != SDL_BUTTON_WHEELUP
	&& event.button.button != SDL_BUTTON_WHEELDOWN)
	in->mousebuttons[event.button.button] = 0;
}

static void analyse_events(SDL_Event event, Input * in)
{
    switch (event.type) {
    case SDL_KEYDOWN:
	if ((event.key.keysym.unicode & 0xFF80) == 0) {
	    in->key[event.key.keysym.unicode] = 1;
	} else {
	    in->key[event.key.keysym.sym] = 0;
	}
	break;
    case SDL_MOUSEMOTION:
	in->mousex = event.motion.x;
	in->mousey = event.motion.y;
	break;
    case SDL_MOUSEBUTTONDOWN:
	in->mousebuttons[event.button.button] = 1;
	break;
    case SDL_MOUSEBUTTONUP:
	analyse_press_button_mouse(event, in);
	break;
    case SDL_QUIT:
	in->quit = 1;
	break;
    default:
	break;
    }
}

static void update_events(Input * in)
{
    SDL_Event event;

    in->mousebuttons[SDL_BUTTON_WHEELUP] = 0;
    in->mousebuttons[SDL_BUTTON_WHEELDOWN] = 0;

    while (SDL_PollEvent(&event)) {
	analyse_events(event, in);
    }
}

static int test_press_any_key(Input * in)
{
    int i;

    for (i = 0; i < SDLK_LAST; i++) {
	if (in->key[i] && in->key[SDLK_l] != 1) {
	    return 1;
	}
    }

    return 0;
}

static void test_press_choice(Input * in, int tab[][NB_CELLS_HEIGHT])
{
    if (in->mousebuttons[SDL_BUTTON_LEFT]) {
	tab[in->mousex / CELL][in->mousey / CELL] = ALIVE;
    }

    if (in->mousebuttons[SDL_BUTTON_RIGHT]) {
	tab[in->mousex / CELL][in->mousey / CELL] = DEAD;
    }
}

static void init_cells(SDL_Surface ** cell_alive, SDL_Surface ** cell_dead)
{
    SDL_Surface *screen = SDL_GetVideoSurface();

    *cell_alive =
	SDL_CreateRGBSurface(SDL_HWSURFACE, CELL, CELL, 32, 0, 0, 0, 0);
    SDL_FillRect(*cell_alive, NULL,
		 SDL_MapRGB(screen->format, 128, 128, 128));

    *cell_dead =
	SDL_CreateRGBSurface(SDL_HWSURFACE, CELL, CELL, 32, 0, 0, 0, 0);
    SDL_FillRect(*cell_dead, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
}

static void free_cells(SDL_Surface ** cell_alive, SDL_Surface ** cell_dead)
{
    SDL_FreeSurface(*cell_alive);
    SDL_FreeSurface(*cell_dead);
}

static void print_screen(int tab[][NB_CELLS_HEIGHT],
			 SDL_Surface * cell_alive, SDL_Surface * cell_dead)
{
    SDL_Rect pos;
    int i, j;

    for (i = 0; i < NB_CELLS_WIDTH; i++) {
	for (j = 0; j < NB_CELLS_HEIGHT; j++) {
	    pos.x = i * CELL;
	    pos.y = j * CELL;

	    if (tab[i][j] == ALIVE) {
		SDL_BlitSurface(cell_alive, NULL, SDL_GetVideoSurface(),
				&pos);
	    } else {
		SDL_BlitSurface(cell_dead, NULL, SDL_GetVideoSurface(),
				&pos);
	    }
	}
    }
}

static int load(int tab[][NB_CELLS_HEIGHT])
{  
    /* A coder */
}

static int get_pos(int tab[][NB_CELLS_HEIGHT])
{
    Input in;
    SDL_Surface *cell_alive, *cell_dead;

    memset(&in, 0, sizeof(in));
    init_cells(&cell_alive, &cell_dead);

    while (!in.key[SDLK_ESCAPE] || !in.quit) {
	update_events(&in);
	test_press_choice(&in, tab);

	if (in.key[SDLK_RETURN]) {
	    if (load(tab)) {
	 	free_cells(&cell_alive, &cell_dead);
	        return 1;
	    }

 	   in.key[SDLK_RETURN] = 0;
	} else if (test_press_any_key(&in)) {
	    free_cells(&cell_alive, &cell_dead);
	    return 1;
	}

	print_screen(tab, cell_alive, cell_dead);

	SDL_Flip(SDL_GetVideoSurface());
    }

    free_cells(&cell_alive, &cell_dead);
    return 0;
}

static int nb_alive_around(int x, int y, int tab[][NB_CELLS_HEIGHT])
{
    int i, j;
    int nb = 0;

    for (i = -1; i <= 1; i++) {
	for (j = -1; j <= 1; j++) {
	    if (!(i == 0 && j == 0)) {
		nb += tab[x + i][y + j];
	    }
	}
    }

    return nb;
}

static void algo(int tab[][NB_CELLS_HEIGHT])
{
    int i, j;

    for (i = 0; i < NB_CELLS_WIDTH; i++) {
	for (j = 0; j < NB_CELLS_HEIGHT; j++) {
	    switch (nb_alive_around(i, j, tab)) {
	    case 2:
		break;
	    case 3:
		tab[i][j] = ALIVE;
		break;
	    default:
		tab[i][j] = DEAD;
		break;
	    }
	}
    }
}

static int game_pause(int tab[][NB_CELLS_HEIGHT])
{
    return get_pos(tab);
}

static void screenshot(void)
{
    FILE * f = NULL;
    char name[32];
    int count = 1;

    do {
	sprintf(name, "screen%d", count);

	if (!(f = fopen(name, "r"))) {
	    break;
	}

	count++;
	fclose(f);
    } while (1);

    SDL_SaveBMP(SDL_GetVideoSurface(), name);
}

static void write_in_file(FILE * f, int tab[][NB_CELLS_HEIGHT])
{
    int i, j;

    for (i = 0 ; i < NB_CELLS_WIDTH ; i++)
    {
 	for (j = 0 ; j < NB_CELLS_HEIGHT ; j++) {
	    fprintf(f, "%d", tab[i][j]);
	}
    }
}

static void save(int tab[][NB_CELLS_HEIGHT])
{
    FILE * f = NULL;
    char name[32];
    int count = 1;

    do {
	sprintf(name, "safeguard%d.zgl", count);

	if (!(f = fopen(name, "r"))) {
	    break;
	}

	count++;
	fclose(f);
    } while (1);

    f = fopen(name, "w");
    write_in_file(f, tab);

    fclose(f);
}

static int test_pause(Input * in, int tab[][NB_CELLS_HEIGHT])
{
    if (in->key[SDLK_p]) {
	if (!game_pause(tab)) {
	    return 0;
	}

	in->key[SDLK_p] = 0;
    }

    return 1;
}

static void test_screenshot(Input * in)
{
    if (in->key[SDLK_c]) {
	screenshot();
	in->key[SDLK_c] = 0;
    }
}

static void test_save(Input * in, int tab[][NB_CELLS_HEIGHT])
{
    if (in->key[SDLK_s]) {
	save(tab);
	in->key[SDLK_s] = 0;
    }
}

static void game_of_life(int tab[][NB_CELLS_HEIGHT])
{
    Input in;
    SDL_Surface *cell_alive, *cell_dead;
    int t1 = 0, t2;

    memset(&in, 0, sizeof(in));
    init_cells(&cell_alive, &cell_dead);

    while (!in.key[SDLK_ESCAPE] || !in.quit) {
	update_events(&in);

	if(!test_pause(&in, tab)) {
	    free_cells(&cell_alive, &cell_dead);
	    return;
	}

	test_screenshot(&in);
	test_save(&in, tab);

	t2 = SDL_GetTicks();
	if (t2 - t1 > DELAY) {
	    algo(tab);
	    t1 = t2;
	} else {
	    SDL_Delay(DELAY - (t2 - t1));
	}

	print_screen(tab, cell_alive, cell_dead);
	SDL_Flip(SDL_GetVideoSurface());
    }

    free_cells(&cell_alive, &cell_dead);
}

int main(int argc, char *argv[])
{
    int tab[NB_CELLS_WIDTH][NB_CELLS_HEIGHT];

    memset(tab, 0, sizeof(tab));

    if (!init()) {
	return EXIT_FAILURE;
    }

    if (!get_pos(tab)) {
	return EXIT_SUCCESS;
    }

    game_of_life(tab);

    (void) argc;
    (void) argv;

    return EXIT_SUCCESS;
}
Staff désormais retraité.
11 septembre 2011 à 10:33:45

Citation

Où chaque cellule a trois voisins vivants, donc on reste bloqué



C’est le principe du jeu : il y a des configurations pour lesquelles la fonction renvoyant la configuration suivante renverra la même configuration, d’autres qui se répètent toutes les N itérations, etc. L’article de wikipédia montre quelques cas courants.
11 septembre 2011 à 10:34:47

Si c'est normal, c'est parfait alors. :)
Staff désormais retraité.
11 septembre 2011 à 14:56:46

Bonjour,

Pas eu vraiment le temps de réfléchir beaucoup à l'algo, j'y penserais plus tard.
(Enfin, j'ai tout de meme essayé de ne pas faire trop bourrin ! :p )

Voici un code de base (= pas interactif : initialisation aléatoire) pour le niveau 1, histoire de participer :
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <SDL.h>


#define _W   60
#define _H   40
#define _BOX_SZ  6
#define SCR_W   (_W * _BOX_SZ)
#define SCR_H   (_H * _BOX_SZ)


typedef struct
{
    SDL_Surface *alive;
    SDL_Surface *dead;
    unsigned** matrix;
    unsigned** mcount;
} Params;


unsigned** init_matrix (unsigned y, unsigned x)
{
    unsigned i, j;
    unsigned** mat = malloc (y * sizeof *mat);   /* index (1ere dimension) */
    if ( mat != NULL )
    {
        *mat = calloc(y * x, sizeof **mat); /* données (2eme dimension) */
        if (*mat != NULL)
        {
            for (i=0,j=0; i<y*x; i+=x,j++)
                mat[j] = (*mat)+i;
        }
    }
    return mat;
}

void delete_matrix (unsigned*** mat)
{
    if (*mat != NULL)
    {
        if (**mat != NULL)
            free(**mat), **mat = NULL;
        free(*mat), *mat = NULL;
    }
}

void draw (Params* params, SDL_Surface* screen)
{
    unsigned i, j;
    for (i=0; i<_H; i++)
    {
        for (j=0; j<_W; j++)
        {
            SDL_Rect pos;
            pos.x = j * _BOX_SZ;
            pos.y = i * _BOX_SZ;
            SDL_BlitSurface(params->matrix[i][j] ? params->alive : params->dead, NULL, screen, &pos);
        }
    }
    SDL_Flip(screen);
}

void update (unsigned** matrix, unsigned** mcount)
{
    memset(*mcount, 0, _H * _W * sizeof **mcount);
    int i, j, _i, _j;
    /* compte les voisins */
    for (i=0; i<_H; i++)
    {
        for (j=0; j<_W; j++)
        {
            if (matrix[i][j])
            {
                for (_i = i-1; _i <= i+1; _i++)
                {
                    for (_j = j-1; _j <= j+1; _j++)
                    {
                        if (_i == i && _j == j) continue;
                        else if (_i >= 0 && _i < _H && _j >= 0 && _j < _W)
                        {
                            mcount[_i][_j]++;
                        }
                    }
                }
            }
        }
    }
    /* actualise le tableau */
    for (i=0; i<_H; i++)
    {
        for (j=0; j<_W; j++)
        {
            if (!matrix[i][j] && mcount[i][j] == 3)
            {
                matrix[i][j] = 1;
            }
            else if (matrix[i][j] && !(mcount[i][j] == 2 || mcount[i][j] == 3))
            {
                matrix[i][j] = 0;
            }
        }
    }
}

Uint32 callback (Uint32 intervalle, void *params)
{
    draw ((Params*)params, SDL_GetVideoSurface());
    update(((Params*)params)->matrix, ((Params*)params)->mcount);

    return intervalle;
}

void init (unsigned** matrix)
{
    unsigned k, n, i, j;
    for (k=0; k < _H * _W / 5; k++)
    {
        n = rand() % (_H * _W);
        i = n / _W, j = n % _W;
        matrix[i][j] = 1;
    }
}

int main ( int argc, char** argv )
{
    unsigned done;
    SDL_Event event;
    SDL_TimerID timer;

    srand(time(NULL));

    /*  initialise SDL video */
    if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER ) < 0 )
    {
        fprintf( stderr, "Unable to init SDL: %s\n", SDL_GetError() );
        return 1;
    }

    SDL_Surface* screen = SDL_SetVideoMode(SCR_W, SCR_H, 32, SDL_HWSURFACE);

    Params params;
    params.matrix = init_matrix(_H, _W);
    params.mcount = init_matrix(_H, _W);
    params.alive = SDL_CreateRGBSurface(SDL_HWSURFACE, _BOX_SZ, _BOX_SZ, 32, 0, 0, 0, 0);
    params.dead = SDL_CreateRGBSurface(SDL_HWSURFACE, _BOX_SZ, _BOX_SZ, 32, 0, 0, 0, 0);
    SDL_FillRect(params.alive, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
    SDL_FillRect(params.dead, NULL, SDL_MapRGB(screen->format, 255, 255, 255));

    /* initialisation aléatoire du tableau */
    init (params.matrix);

    timer = SDL_AddTimer(300, callback, &params);

    done = 0;
    while (!done)
    {
        SDL_WaitEvent(&event);
        switch (event.type)
        {
        case SDL_QUIT:
            done = 1;
            break;

            /*  appui d'une touche */
        case SDL_KEYDOWN:
            switch (event.key.keysym.sym)
            {
            case SDLK_ESCAPE: /*  Touche Echap */
                done = 1;
                break;

            default:
                break;
            } /* fin switch (event.key.keysym.sym) */
            break;

        default:
            break;

        } /* fin switch (event.type) */
    } /* fin boucle evenementielle */

    SDL_FreeSurface(params.alive);
    SDL_FreeSurface(params.dead);
    delete_matrix(&params.matrix);
    delete_matrix(&params.mcount);
    SDL_RemoveTimer(timer);
    SDL_Quit();

    return 0;
}


J'ai choisi d'utiliser un timer, je ne sais pas trop pourquoi.
11 septembre 2011 à 15:09:46

for (i=0; i<_H; i++)
    {
        for (j=0; j<_W; j++)
        {
            if (matrix[i][j])
            {
                for (_i = i-1; _i <= i+1; _i++)
                {
                    for (_j = j-1; _j <= j+1; _j++)
                    {
                        if (_i == i && _j == j) continue;
                        else if (_i >= 0 && _i < _H && _j >= 0 && _j < _W)
                        {
                            mcount[_i][_j]++;
                            printf(".");
                        }
                    }
                }
            }
        }
    }


Ça c'est de l'imbrication ! :D
Staff désormais retraité.
11 septembre 2011 à 15:31:35

Yoch, Six for() dans une seule fonction c'est assez lol quand même ^^
(Comme dit au dessus)

if (_i == i && _j == j) continue;
else if (_i >= 0 && _i < _H && _j >= 0 && _j < _W)
{
   mcount[_i][_j]++;
   printf(".");
}
Pourquoi tu mets "continue" alors que t'aurais juste à mettre cette condition dans le if() d'en dessous?

default:
   break;
ça fait quoi ça?

J'aime bien ta manière de créer un tableau 2D avec que deux malloc :)
11 septembre 2011 à 15:51:57

Le default:break c'est pour virer les warnings de la SDL je crois.
Staff désormais retraité.
11 septembre 2011 à 15:54:46

@Mr21: Salut, Tortor.
Déjà, première chose que j'ai vue qui n'était vraiment pas... véridique, une fonction n'est pas censée faire max 30 lignes. Elle est censée implémenter une fonctionnalité. Je prends comme exemple le chargement d'images d'OpenGL, qui ne prend certainement pas 30 lignes si on fait bien les choses. Et pourtant, je suis un adorateur du découpage de code.
Ensuite, un main() peut être rempli de tout et n'importe quoi. Si le développeur doit, après création du programme, en faire un nouveau qui inclut celui-ci, eh bien, "Rename main() as main_truc()".
Après, au niveau du continue, ce n'est pas mon code, mais c'est souvent utilisé pour la logique syntaxique du code. C'est parfois plus agréable de montrer un cas fréquent en premier, même si ça implique de laisser la gestion de ce cas vide.
Enfin, le default est le cas "général" des switchs, dans le cas où aucun autre... cas n'a marché. break... tous les cas doivent se terminer par un break (tiens, c'marrant, ça me rappelle le C#), sauf, dans certaines situations, les cas qui mènent à d'autres cas.


Mille pardons pour dériver un peu du sujet!
11 septembre 2011 à 16:35:19

Hey \o_


Au sujet de la norme, j'suis de ton avis (et j'ai dû le dire déjà quelque part cheplu où) : une fonction doit faire une chose et une seule.
Mais c'est pas en sachant ça, qu'on va l'faire automatiquement (du moins pas quand on apprend).

Le seul moyen de prendre cette habitude, est de limiter les fonctions à un certain nombre de lignes.
Mais après t'as clairement raison que certaine fois, appliquer cette norme serait contre productif etc.
Sauf qu'ici, tout les codes postés pourraient être mieux découpé sans aucun soucis.

Pour le switch, il n'est pas obligé de mettre un default si?
lucas-84 parle de warning à faire taire, alors bon chepa...

EDIT: lucas-84, Ah oui d'accord je vois...
11 septembre 2011 à 16:39:01

Citation

lucas-84 parle de warning à faire taire, alors bon chepa...



Si on enlève les default:break :

main.c:169: warning: enumeration value ‘SDLK_UNKNOWN’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_FIRST’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_BACKSPACE’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_TAB’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_CLEAR’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_RETURN’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_PAUSE’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_SPACE’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_EXCLAIM’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_QUOTEDBL’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_HASH’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_DOLLAR’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_AMPERSAND’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_QUOTE’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_LEFTPAREN’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_RIGHTPAREN’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_ASTERISK’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_PLUS’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_COMMA’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_MINUS’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_PERIOD’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_SLASH’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_0’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_1’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_2’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_3’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_4’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_5’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_6’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_7’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_8’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_9’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_COLON’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_SEMICOLON’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_LESS’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_EQUALS’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_GREATER’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_QUESTION’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_AT’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_LEFTBRACKET’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_BACKSLASH’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_RIGHTBRACKET’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_CARET’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_UNDERSCORE’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_BACKQUOTE’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_a’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_b’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_c’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_d’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_e’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_f’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_g’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_h’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_i’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_j’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_k’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_l’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_m’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_n’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_o’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_p’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_q’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_r’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_s’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_t’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_u’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_v’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_w’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_x’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_y’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_z’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_DELETE’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_0’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_1’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_2’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_3’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_4’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_5’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_6’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_7’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_8’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_9’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_10’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_11’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_12’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_13’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_14’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_15’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_16’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_17’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_18’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_19’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_20’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_21’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_22’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_23’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_24’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_25’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_26’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_27’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_28’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_29’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_30’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_31’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_32’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_33’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_34’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_35’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_36’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_37’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_38’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_39’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_40’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_41’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_42’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_43’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_44’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_45’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_46’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_47’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_48’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_49’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_50’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_51’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_52’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_53’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_54’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_55’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_56’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_57’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_58’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_59’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_60’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_61’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_62’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_63’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_64’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_65’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_66’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_67’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_68’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_69’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_70’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_71’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_72’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_73’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_74’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_75’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_76’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_77’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_78’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_79’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_80’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_81’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_82’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_83’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_84’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_85’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_86’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_87’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_88’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_89’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_90’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_91’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_92’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_93’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_94’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_WORLD_95’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_KP0’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_KP1’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_KP2’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_KP3’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_KP4’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_KP5’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_KP6’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_KP7’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_KP8’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_KP9’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_KP_PERIOD’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_KP_DIVIDE’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_KP_MULTIPLY’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_KP_MINUS’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_KP_PLUS’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_KP_ENTER’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_KP_EQUALS’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_UP’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_DOWN’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_RIGHT’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_LEFT’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_INSERT’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_HOME’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_END’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_PAGEUP’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_PAGEDOWN’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_F1’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_F2’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_F3’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_F4’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_F5’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_F6’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_F7’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_F8’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_F9’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_F10’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_F11’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_F12’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_F13’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_F14’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_F15’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_NUMLOCK’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_CAPSLOCK’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_SCROLLOCK’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_RSHIFT’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_LSHIFT’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_RCTRL’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_LCTRL’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_RALT’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_LALT’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_RMETA’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_LMETA’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_LSUPER’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_RSUPER’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_MODE’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_COMPOSE’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_HELP’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_PRINT’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_SYSREQ’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_BREAK’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_MENU’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_POWER’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_EURO’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_UNDO’ not handled in switch
main.c:169: warning: enumeration value ‘SDLK_LAST’ not handled in switch


Pas jojo, hein ? :p
Staff désormais retraité.
11 septembre 2011 à 17:18:13

Je confirme pour les warning de la SDL, c'est assez lourd :( donc c'est obligatoire de mettre un default.
Anonyme
11 septembre 2011 à 17:41:14

Je le ferais bien cet exo, mais la SDL, ça fait un bout de temps que j'y ai pas touché. En plus, elle ne marche plus...

Et puis mon DD est mort donc comme ça au moins...
11 septembre 2011 à 18:46:03

Voilà, mon code gère les pauses, les screens et enregistre des positions dans un fichier texte. Reste plus qu'à pouvoir changer une position. On verra ça... mercredi (pas le temps de coder entre temps...).

Mais déjà 420 lignes de code... :-°
Staff désormais retraité.
11 septembre 2011 à 19:25:32

Bonjour,
On commence par le niveau 1. :-°

Voulant tout conserver dans un même fichier source, j'ai hésité à découpé les grosses fonctions, pour pas que ce soit le bordel.
Mais du coup certaines fonctions sont bien vilaines. :(

Une partie initialisation, où on peut:
-placer les cellules soit même avec la souris.
-remplir le monde aléatoirement
-ESPACE pour lancer le jeu

Dans le jeu, n'importe quelle touche pour revenir à la partie initialisation.

#include <SDL/SDL.h>

#define WORLD_W         160U
#define WORLD_H         160U
#define CELL_SIZE       6
#define SCR_W           (WORLD_W * CELL_SIZE)
#define SCR_H           (WORLD_H * CELL_SIZE)
#define START_N_CELLS   ((WORLD_W * WORLD_H) / 5)
#define BPP             32
#define TICK_INTERVAL   300

#define CHECK(cond)                                         \
    do                                                      \
    {                                                       \
        if(!(cond))                                         \
        {                                                   \
            fprintf(stderr, "%s %s %u",                     \
                    SDL_GetError(),                         \
                    __FILE__,                               \
                    __LINE__);                              \
            exit(EXIT_FAILURE);                             \
        }                                                   \
    }while(0)

Uint32 timeLeft(Uint32 nextTime)
{
    Uint32 now;

    now = SDL_GetTicks();
    if(nextTime <= now)
        return 0;
    else
        return nextTime - now;
}



int World_countNeighbors(int *world, int ox, int oy)
{
    static int dir[][2] = {{-1, 0}, {-1, -1}, {0, -1},
        {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}
    };
    int ret = 0;
    for(Uint32 crtDir = 0; crtDir < 8; crtDir++)
    {
        int x = ox + dir[crtDir][0];
        int y = oy + dir[crtDir][1];
        if((unsigned)x < WORLD_W && (unsigned)y < WORLD_H)
            ret += world[y * WORLD_W + x];
    }

    return ret;
}


void World_display(SDL_Surface *screen, int *world)
{
    Uint32 color = SDL_MapRGB(screen->format, 0xff, 0xff, 0xff);
    for(Uint32 y = 0; y < WORLD_H; y++)
        for(Uint32 x = 0; x < WORLD_W; x++)
            if(world[y * WORLD_W + x])
            {
                SDL_Rect pos;
                pos.x = x * CELL_SIZE;
                pos.y = y * CELL_SIZE;
                pos.w = CELL_SIZE;
                pos.h = CELL_SIZE;
                SDL_FillRect(SDL_GetVideoSurface(), &pos, color);
            }
}



void World_update(int **crtWorld, int **nxtWorld)
{
    for(Uint32 y = 0; y < WORLD_H; y++)
        for(Uint32 x = 0; x < WORLD_W; x++)
        {
            Uint32 id = y * WORLD_W + x;
            int nNeighbors = World_countNeighbors(*crtWorld, x, y);
            if((*crtWorld)[id])
                (*nxtWorld)[id] = nNeighbors == 2 || nNeighbors == 3;
            else
                (*nxtWorld)[id] = (nNeighbors == 3);
        }

    int *tmp = *crtWorld;
    *crtWorld = *nxtWorld;
    *nxtWorld = tmp;
}




void World_initRandom(int *world, int nCells)
{
    memset(world, 0, WORLD_W * WORLD_H * sizeof *world);
    for(int i = 0; i < nCells; i++)
    {
        int r = rand() % (WORLD_W * WORLD_H - i - 1);
        while(world[r])
            r++;
        world[r] = 1;
    }
}



int Game_init(int *world)
{
    SDL_Surface *screen = SDL_GetVideoSurface();
    memset(world, 0, WORLD_W * WORLD_H * sizeof *world);

    for(;;)
    {
        SDL_Event ev;
        while(SDL_PollEvent(&ev))
        {
            switch(ev.type)
            {
            case SDL_QUIT:
                return 1;
                break;
            case SDL_KEYDOWN:
                switch(ev.key.keysym.sym)
                {
                case SDLK_SPACE:
                    return 0;
                    break;
                case SDLK_r:
                    World_initRandom(world, START_N_CELLS);
                    break;
                default:
                    break;
                }
                break;
            case SDL_MOUSEBUTTONDOWN:
                if(ev.button.button == SDL_BUTTON_LEFT)
                {
                    int x = ev.button.x / CELL_SIZE;
                    int y = ev.button.y / CELL_SIZE;
                    world[y * WORLD_W + x] ^= 1;
                }

                break;
            default:
                break;
            }
        }

        SDL_FillRect(screen, NULL, 0);
        World_display(screen, world);
        SDL_Flip(screen);
    }
}


void run(void)
{
    static int crtWorld[WORLD_W * WORLD_H];
    static int nxtWorld[WORLD_W * WORLD_H];
    int *p_crtWorld = crtWorld;
    int *p_nxtWorld = nxtWorld;

    SDL_Surface *screen = SDL_GetVideoSurface();


    int done = Game_init(p_crtWorld);
    Uint32 nextTime = SDL_GetTicks() + TICK_INTERVAL;
    while(!done)
    {
        SDL_Event ev;
        while(SDL_PollEvent(&ev))
        {
            switch(ev.type)
            {
            case SDL_QUIT:
                done = 1;
                break;
            case SDL_KEYDOWN:
                done = Game_init(p_crtWorld);
                nextTime = SDL_GetTicks() + TICK_INTERVAL;
                break;
            default:
                break;
            }
        }
        World_update(&p_crtWorld, &p_nxtWorld);

        SDL_FillRect(screen, NULL, 0);
        World_display(screen, p_crtWorld);
        SDL_Delay(timeLeft(nextTime));
        nextTime += TICK_INTERVAL;
        SDL_Flip(screen);
    }
}



int main(int argc, char *argv[])
{
    CHECK(SDL_Init(SDL_INIT_VIDEO) == 0);
    CHECK(SDL_SetVideoMode(SCR_W, SCR_H, BPP, SDL_SWSURFACE) != NULL);

    run();

    (void)argc;
    (void)argv;

    SDL_Quit();

    return 0;
}
Zeste de Savoir, le site qui en a dans le citron !
11 septembre 2011 à 20:03:46

Citation : Mr21

Yoch, Six for() dans une seule fonction c'est assez lol quand même ^^
(Comme dit au dessus)


J'ai codé un peu à l'arrache, effectivement...

Citation : Mr21

if (_i == i && _j == j) continue;
else if (_i >= 0 && _i < _H && _j >= 0 && _j < _W)
{
   mcount[_i][_j]++;
   printf(".");
}

Pourquoi tu mets "continue" alors que t'aurais juste à mettre cette condition dans le if() d'en dessous?


idem

Citation : Mr21

J'aime bien ta manière de créer un tableau 2D avec que deux malloc :)


http://en.wikipedia.org/wiki/Iliffe_vector
http://www.siteduzero.com/forum-83-125 [...] html#r4838547
12 septembre 2011 à 12:12:07

Bonjour,

Un lundi matin à occuper (attention aux yeux, c'est bourrin)...

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

#define COLS 640
#define ROWS 480
#define MODE SDL_HWSURFACE | SDL_DOUBLEBUF

#define FPS 25

int main(int argc, char ** argv) {
    SDL_Surface * screen;

    Uint32 black;
    Uint32 white;

    int grid[1 + COLS + 1][1 + ROWS + 1] = {
        {0} 
    };

    int onclick = 0;
    int onpause = 0;
    int onclear = 0;
    int running = 1; 

/* init ------------------------------------------------------------- */
    if (SDL_Init(SDL_INIT_VIDEO) == -1) {
        fprintf(stderr, "fatal: %s\n", SDL_GetError());
        exit(EXIT_FAILURE);
    }
    
    if ((screen = SDL_SetVideoMode(COLS, ROWS, 32, MODE)) == NULL) {
        fprintf(stderr, "fatal: %s\n", SDL_GetError());
        exit(EXIT_FAILURE);
    }

    black = SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF);
    white = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);

    SDL_WM_SetCaption("Game of Life", NULL);

    for (;;) {
        int x, y;
        SDL_Event event;

/* handle events ---------------------------------------------------- */
        while (SDL_PollEvent(&event)) {
            switch (event.type) {
                case SDL_MOUSEBUTTONDOWN:
                    onclick = 1;
                    break;

                case SDL_MOUSEBUTTONUP:
                    onclick = 0;
                    break;

                case SDL_MOUSEMOTION:
                    x = 1 + event.motion.x;
                    y = 1 + event.motion.y;
                    break;

                case SDL_KEYDOWN:
                    switch (event.key.keysym.sym) {
                        case SDLK_p:
                            onpause = 1;
                            break;

                        case SDLK_r:
                            onclear = 1;
                            break;

                        default:
                            ;
                    }
                    break;

                case SDL_QUIT:
                    goto quit;

                default:
                    ;
            }

/* process events --------------------------------------------------- */
            if (onclick) {
                grid[x][y] = 1;
            }

            if (onpause) {
                running = !running;

                if (running) {
                    SDL_WM_SetCaption("Game of Life", NULL);
                }
                else {
                    SDL_WM_SetCaption("Game of Life (paused)", NULL);
                }

                onpause = 0;
            }

            if (onclear) {
                memset(grid, 0, sizeof grid);

                onclear = 0;
            }
        }

/* update ----------------------------------------------------------- */
        if (running) {
            for (x = 1; x < 1 + COLS; x++) {
                for (y = 1; y < 1 + ROWS; y++) {
                    int n = 0;

                    n += grid[x][y - 1];
                    n += grid[x][y + 1];
                    n += grid[x - 1][y];
                    n += grid[x + 1][y];
                    n += grid[x - 1][y - 1];
                    n += grid[x - 1][y + 1];
                    n += grid[x + 1][y - 1];
                    n += grid[x + 1][y + 1];

                    if (grid[x][y]) {
                        grid[x][y] = n == 2 || n == 3;
                    }
                    else {
                        grid[x][y] = n == 3;
                    }
                }
            }
        }

/* render ----------------------------------------------------------- */
        for (y = 1; y < 1 + ROWS; y++) {
            for (x = 1; x < 1 + COLS; x++) {
                Uint32 * pixel = (Uint32 *) screen->pixels;

                pixel += (y - 1) * screen->pitch / 4 + (x - 1);

                if (grid[x][y]) {
                    *pixel = black;
                }
                else {
                    *pixel = white;
                }
            }
        }

        SDL_Flip(screen);
        SDL_Delay(1000 / FPS);
    }

/* quit ------------------------------------------------------------- */
quit:
    SDL_Quit();
        
    (void) argc;
    (void) argv;

    return 0;
}


Cliquer pour répandre des cellules vivantes, P pour mettre en pause et R pour effacer l'écran.

PS: oui, je me suis permis une petite astuce pour éviter de me casser la tête avec les "bords" :p
12 septembre 2011 à 12:27:53

MaitreZur, mais?! tu as toi même réussi à "découper" ton code avec des "/*-----------*/", pourquoi ne pas l'avoir fait correctement en fonction (et ainsi se passer de goto) ?
12 septembre 2011 à 12:32:14

Citation : Mr21

MaitreZur, mais?! tu as toi même réussi à "découper" ton code avec des "/*-----------*/", pourquoi ne pas l'avoir fait correctement en fonction (et ainsi se passer de goto) ?


Parce que ça n'avait aucun intérêt pour 150 lignes de code ?

Je savais que j'allais choquer avec le goto, c'était voulu, ici il est "bien" utilisé. Il est inutile de faire une mise à jour du contexte suivi d'un rendu si l'utilisateur désire quitter, et rajouter une variable et une condition géante ne ferait qu'alourdir le code.
12 septembre 2011 à 14:07:55

Bonjour,

Voici mon code pour le niveau 2.

Les fonctionnalités :
  • [clic gauche] : activer / désactiver une case
  • espace pour mettre en pause / relancer
  • a pour initialiser aléatoirement
  • r efface l'écran et met en pause
  • + / - pour accélérer / ralentir

Amélioration au niveau algo : à présent, je ne blitte que les surfaces modifiées.
Sinon, je ne gère pas les bords ni le dehors de l'écran.

#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <SDL.h>


#define _W   100
#define _H   100
#define _BOX_SZ  5
#define SCR_W   (_W * _BOX_SZ)
#define SCR_H   (_H * _BOX_SZ)


typedef struct
{
    SDL_Surface *screen;
    SDL_Surface *alive;
    SDL_Surface *dead;
    unsigned** matrix;
    unsigned** mcount;
    SDL_TimerID timer;
    unsigned delay;
} Params;


unsigned** init_matrix (unsigned y, unsigned x)
{
    unsigned i, j;
    unsigned** mat = malloc (y * sizeof *mat);   /* index (1ere dimension) */
    if ( mat != NULL )
    {
        *mat = calloc(y * x, sizeof **mat); /* données (2eme dimension) */
        if (*mat != NULL)
        {
            for (i=0,j=0; i<y*x; i+=x,j++)
                mat[j] = (*mat)+i;
        }
    }
    return mat;
}

void delete_matrix (unsigned*** mat)
{
    if (*mat != NULL)
    {
        if (**mat != NULL)
            free(**mat), **mat = NULL;
        free(*mat), *mat = NULL;
    }
}

void set_point (Params* params, unsigned i, unsigned j)
{
    SDL_Rect pos;
    pos.x = j * _BOX_SZ;
    pos.y = i * _BOX_SZ;
    SDL_BlitSurface(params->matrix[i][j] ? params->alive : params->dead, NULL, params->screen, &pos);
}

void draw (Params* params)
{
    unsigned i, j;
    for (i=0; i<_H; i++)
        for (j=0; j<_W; j++)
            set_point (params, i, j);
    SDL_Flip(params->screen);
}

void update (Params* params)
{
    unsigned** matrix = params->matrix;
    unsigned** mcount = params->mcount;
    /* remet les compteurs à zéro */
    memset(*mcount, 0, _H * _W * sizeof **mcount);
    /* comptage des voisins */
    int i, j, _i, _j;
    for (i=0; i<_H; i++)
        for (j=0; j<_W; j++)
            if (matrix[i][j])
                for (_i = i-1; _i <= i+1; _i++)
                    for (_j = j-1; _j <= j+1; _j++)
                    {
                        if (_i == i && _j == j)
                            continue;
                        else if (_i >= 0 && _i < _H && _j >= 0 && _j < _W)
                            mcount[_i][_j]++;
                    }
    /* actualise les cellules */
    for (i=0; i<_H; i++)
        for (j=0; j<_W; j++)
        {
            if (!matrix[i][j] && mcount[i][j] == 3)
            {
                matrix[i][j] = 1;
                set_point (params, i, j);
            }
            else if (matrix[i][j] && !(mcount[i][j] == 2 || mcount[i][j] == 3))
            {
                matrix[i][j] = 0;
                set_point (params, i, j);
            }
        }
}

Uint32 callback (Uint32 intervalle, void *params)
{
    update((Params*)params);
    SDL_Flip(((Params*)params)->screen);
    return ((Params*)params)->delay;
}

void timer_gestion (Params* params, unsigned paused)
{
    if (!paused)
    {
        params->timer = SDL_AddTimer(300, callback, params);
        SDL_WM_SetCaption("  ON  ", NULL);
    }
    else if (params->timer != NULL)
    {
        SDL_RemoveTimer(params->timer);
        params->timer = NULL;
        SDL_WM_SetCaption(" - PAUSED - ", NULL);
    }
}

/* initialisation aléatoire des cellules */
void init (unsigned** matrix)
{
    unsigned k, n, i, j;
    for (k=0; k < _H * _W / 5; k++)
    {
        n = rand() % (_H * _W);
        i = n / _W, j = n % _W;
        matrix[i][j] = 1;
    }
}

int main ( int argc, char** argv )
{
    unsigned done, paused = 1;
    SDL_Event event;

    srand(time(NULL));

    /*  initialise SDL video */
    if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER ) < 0 )
    {
        fprintf( stderr, "Unable to init SDL: %s\n", SDL_GetError() );
        return 1;
    }

    SDL_Surface* screen = SDL_SetVideoMode(SCR_W, SCR_H, 32, SDL_HWSURFACE);
    SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 255, 255, 255));

    Params params;
    params.screen = screen;
    params.matrix = init_matrix(_H, _W);
    params.mcount = init_matrix(_H, _W);
    params.timer = NULL;
    params.delay = 300;
    params.alive = SDL_CreateRGBSurface(SDL_HWSURFACE, _BOX_SZ, _BOX_SZ, 32, 0, 0, 0, 0);
    params.dead = SDL_CreateRGBSurface(SDL_HWSURFACE, _BOX_SZ, _BOX_SZ, 32, 0, 0, 0, 0);
    SDL_FillRect(params.alive, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
    SDL_FillRect(params.dead, NULL, SDL_MapRGB(screen->format, 255, 255, 255));

    draw (&params);

    done = 0;
    while (!done)
    {
        SDL_WaitEvent(&event);
        switch (event.type)
        {
        case SDL_QUIT:
            done = 1;
            break;

            /*  appui d'une touche */
        case SDL_KEYDOWN:
            switch (event.key.keysym.sym)
            {
            case SDLK_ESCAPE: /*  Touche Echap */
                done = 1;
                break;

            case SDLK_SPACE:
                paused ^= 1;
                timer_gestion (&params, paused);
                break;

            case SDLK_PLUS:
            case SDLK_KP_PLUS:
                if (params.delay > 100) params.delay -= 100;
                break;

            case SDLK_MINUS:
            case SDLK_KP_MINUS:
                if (params.delay < 1200) params.delay += 100;
                break;

            /* réinitialisation du tableau vide */
            case SDLK_r:
            /* initialisation aléatoire du tableau */
            case SDLK_a:
                paused = 1;
                timer_gestion (&params, paused);
                memset(*(params.matrix), 0, _H * _W * sizeof **(params.matrix));
                if (event.key.keysym.sym == SDLK_a) init (params.matrix);
                draw (&params);
                break;

            default:
                break;
            } /* fin switch (event.key.keysym.sym) */
            break;

            /* Clic de la souris */
        case SDL_MOUSEBUTTONUP:
            switch (event.button.button)
            {
            case SDL_BUTTON_LEFT:
                if (paused)
                {
                    unsigned i = event.button.y / _BOX_SZ;
                    unsigned j = event.button.x / _BOX_SZ;
                    params.matrix[i][j] ^= 1;
                    set_point (&params, i, j);
                    SDL_Flip(screen);
                }
                break;

            default:
                break;
            }
            break;

        default:
            break;

        } /* fin switch (event.type) */
    } /* fin boucle evenementielle */

    SDL_FreeSurface(params.alive);
    SDL_FreeSurface(params.dead);
    delete_matrix(&params.matrix);
    delete_matrix(&params.mcount);
    SDL_Quit();

    return 0;
}
12 septembre 2011 à 14:23:48

Ahh j'ai testé c'est cool!

Mais c'est un peu casse pied de dessiner un truc, il faudrait que l'on puisse maintenir enfoncé le clique gauche pour dessiner et clique droit pour delete.
Et pouvoir dessiner pendant que ça joue serait sympa aussi jpense

Au final j'fais des points partout puis tout meurt en une frame :(

Bref, j'y prend gout à ce truc là.

PS: Ça fait un viseur de faire un carré de 3*3 :D
12 septembre 2011 à 14:40:04

Citation : Mr21

PS: Ça fait un viseur de faire un carré de 3*3 :D


Essaye un U 3*3 (au centre)...
12 septembre 2011 à 14:44:20

Salut,
Je ne sait pas quelle niveaux représente mon code mais voila^^.

-3 niveau d'âge (Vert, Bleu, Rouge)
-Peut se multiplier a partir du 2ème âge
-Si une cellule morte à exactement trois voisines vivantes, elle devient alors vivante à son tour.
-Si une cellule vivante à deux ou trois voisines vivantes, elle le reste. Elle meurt dans tous les autres cas.

Control:
-p: lancer la partie
-<souligne>pad:</souligne>
-> +: Augmenter la vitesse
-> -: diminuer la vitesse


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

#include <SDL/SDL.h>

#include "main.h"

int main(int argc, char *argv[])
{

    srand(time(NULL));

    SDL_Init(SDL_INIT_VIDEO);

    SDL_Surface *ecran;
    SDL_Event event;
    int grille[X][Y], fin = 1, debut = 0, vitesse = V_MINI, tp =0, ta = 0;

    ecran = SDL_SetVideoMode(X*TAILLE_PIX ,Y*TAILLE_PIX ,32 ,SDL_HWSURFACE | SDL_DOUBLEBUF);

    initJeux(grille);

    affichage(ecran, grille);

    while(fin)
    {

        SDL_PollEvent(&event);
        switch(event.type)
        {
            case SDL_KEYDOWN:

                if(event.key.keysym.sym == SDLK_p)
                    debut = 1;
                else if(event.key.keysym.sym == SDLK_KP_PLUS && vitesse < V_MAX)
                    vitesse++;
                else if(event.key.keysym.sym == SDLK_KP_MINUS && vitesse > V_MINI)
                    vitesse --;

            break;
            case SDL_QUIT:

                fin = 0;

            break;

            default:
            break;
        }

        if(debut)
        {

            ta = SDL_GetTicks();
            if(ta - tp > (TEMPS / vitesse))
            {
                gestionRegle(grille);
                affichage(ecran, grille);
                tp = ta;
            }

        }

    }

    SDL_Quit();

    return 0;

}

void initJeux(int grille[X][Y])
{

    int nb_cellule, x, y, j, i, etat;

    for(i=0;i<X;i++)
        for(j=0;j<Y;j++)
            grille[i][j] = 0;

    nb_cellule = X*Y*TAUX_INIT/100;

    for(i=0;i<nb_cellule;i++)
    {

        x = rand() % X;
        y = rand() % Y;
        etat = (rand() % 3) + 1;

        if(grille[x][y] == 0)
            grille[x][y] = etat;
        else
            i--;

    }

}

void affichage(SDL_Surface *ecran, int grille[X][Y])
{
    int i, j;
    SDL_Rect pixel = {0, 0, TAILLE_PIX, TAILLE_PIX};

    for(i=0; i<X; i++)
        for(j=0;j<Y;j++)
        {

            pixel.x = i*TAILLE_PIX;
            pixel.y = j*TAILLE_PIX;

            if(grille[i][j] == 0)
                SDL_FillRect(ecran, &pixel, SDL_MapRGB(ecran->format, 0, 0, 0));
            else if(grille[i][j] == 1)
                SDL_FillRect(ecran, &pixel, SDL_MapRGB(ecran->format, 0, 0, 255));
            else if(grille[i][j] == 2)
                SDL_FillRect(ecran, &pixel, SDL_MapRGB(ecran->format, 0, 255, 0));
            else if(grille[i][j] == 3)
                SDL_FillRect(ecran, &pixel, SDL_MapRGB(ecran->format, 255, 0, 0));

        }

    SDL_Flip(ecran);


}

void gestionRegle(int grille[X][Y])
{

    int i, j;

    for(i=0; i<X; i++)
        for(j=0; j<Y; j++)
        {

            if(grille[i][j] == 0)
            {
                    if(gestionRegle_cellule(grille, i, j) == 3)
                        grille[i][j] = 1;
            }
            else if(grille[i][j] == 1 || grille[i][j] == 2)
                grille[i][j]++;
            else if(grille[i][j] == 3)
                if(gestionRegle_cellule(grille, i, j) != 2 && gestionRegle_cellule(grille, i, j) != 3)
                    grille[i][j] = 0;

        }

}

int gestionRegle_cellule(int grille[X][Y], int i, int j)
{

    int v = 0, t, u;

    for(t=-1;t<2;t++)
        for(u=-1;u<2;u++)
            if(grille[i+t][j+u] >= 2 && i+t > -1 && j+u > -1 && i+t < X && j+u < Y && (t != 0 || u != 0))
                v++;

    return v;

}


#define X 50
#define Y 50
#define TAUX_INIT 10
#define TAILLE_PIX 4
#define V_MINI 1
#define V_MAX 10
#define TEMPS 1000

void initJeux(int grille[X][Y]);
void affichage(SDL_Surface *ecran, int grille[X][Y]);
void gestionRegle(int grille[X][Y]);
int gestionRegle_cellule(int grille[X][Y], int i, int j);


Si vous pourriez me dire comment réduire un peu le main(qui est assez volumineux) sa serait pas mal^^.
12 septembre 2011 à 14:48:13

J'ai une grande question sur le Game of Life, doit-on mettre à jour les cellules par ordre de lecture ou (du style, mettre directement à jour tab[y][x], puis tab[y][x+1], etc...) ou n'est-il pas plus intéressant de construire un nouveau tableau contenant les mises-à-jour?

Parce que, par exemple, dans le cas d'un:
x x
x x x
x x

si on met à jour la cellule [1][1] avant de mettre à jour la [1][2], les deux meurent. Mais si on les gère sans les mettre à jour dans le même tableau, la [1][1] meurt mais la [1][2] subsiste.

[FAIT][Défis] #2 : Le jeu de la vie !

× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
  • Editeur
  • Markdown