Wireworld/C

From Rosetta Code
Revision as of 14:05, 20 October 2009 by rosettacode>Mwn3d (Moving from main task page to shorten it)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Evolution is key-driven instead of being time-driven: any key (except 'q' which terminates the program) evolves the system.

Library: OpenGL
Library: GLUT

<lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. include <GL/glut.h>
  3. include <assert.h>
  1. define WIDTH 20
  2. define HEIGHT 20
  3. define MAX_SIZE 256

// Pixels Per Point (every "point" is an "element" of the wireworld) int PPP = 10; int width = WIDTH, height = HEIGHT;

int win;

int fc = 0; char *field[2];


// free mem hook void freemem(void) {

 free(field[0]);
 free(field[1]);

}

// BLACK

  1. define EMPTY 0.0, 0.0, 0.0

// head WHITE

  1. define E_HEAD 1.0, 1.0, 1.0

// tail GRAY

  1. define E_TAIL 0.7, 0.7, 0.7

// conductor RED

  1. define CONDUCTOR 1.0, 0.0, 0.0
  1. define cEMPTY ' '
  2. define cHEAD 'H'
  3. define cTAIL 't'
  4. define cCONDUCTOR '.'

// GL coords are from -1 to 1

  1. define GLCOORD_X(a) ( (double)(2.0*(a))/(double)(width*PPP) - 1.0 )
  2. define GLCOORD_Y(a) ( (double)(2.0*(a))/(double)(height*PPP) - 1.0 )

// show wireworld void wireworld_show(void) {

 int j, i;
 glClearColor(EMPTY, 1.0);
 glClear(GL_COLOR_BUFFER_BIT);
 for(j=0; j < height; j++) {
   for(i=0; i < width; i++) {
     switch( *(field[fc%2] + j*width +  i) ) {
     case cTAIL:
       glColor3d(E_TAIL);
       break;
     case cHEAD:
       glColor3d(E_HEAD);
       break;
     case cCONDUCTOR:
       glColor3d(CONDUCTOR);
       break;
     default:
       glColor3d(EMPTY);
       break;
     }
     glRectd(GLCOORD_X(i*PPP), GLCOORD_Y(j*PPP), 
             GLCOORD_X((i+1)*PPP-1), GLCOORD_Y((j+1)*PPP-1));
   }
 }
 glFlush();

}


  1. define THIS(I,J) *(field[fc%2] + (I) + (J)*width)
  2. define NEXT(I,J) *(field[(fc+1)%2] + (I) + (J)*width)

int count_heads(int i, int j) {

 int e = 0;
 int ax, ay;
 for(ax=-1; ax <= 1; ax++) {
   for(ay=-1; ay <= 1; ay++) {
     if ( ((i+ax) < 0) || ( (j+ay) < 0) || ( (i+ax) >= width ) ||
          ( (j+ay) >= height ) ) continue;
     if ( (ax==0) && (ay==0) ) continue;
     if ( THIS(i+ax, j+ay) == cHEAD ) e++;
   }
 }
 return e;

}

void evolve_wireworld(void) {

 int j, i;
 int ehn;
 
 for(i=0; i < width; i++) {
   for(j=0; j < height; j++) {
     switch( THIS(i, j) )
     {
     case cHEAD:
       NEXT(i, j) = cTAIL;
       break;
     case cTAIL:
       NEXT(i, j) = cCONDUCTOR;
       break;
     case cCONDUCTOR:
       ehn = count_heads(i, j);
       if ( (ehn == 1) || (ehn == 2) )
         NEXT(i, j) = cHEAD;
       else
         NEXT(i, j) = cCONDUCTOR;
       break;
     default:
       NEXT(i, j) = THIS(i, j);
     }
   }
 }
 fc++;

}


// key hit void key_hit(unsigned char k, int x, int y) {

 if ( k == 'q' )
 {
   glFinish();
   glutDestroyWindow(win);
   exit(EXIT_SUCCESS);
 } else {
   evolve_wireworld();
   wireworld_show();
 }

}


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

 FILE *p;
 int i, j;


 if ( argc < 2 ) {
   fprintf(stderr, "specify a wireworld initial state\n");
   exit(EXIT_FAILURE);
 }


 if ( (p = fopen(argv[1], "r")) != NULL ) {
   field[0] = malloc(MAX_SIZE*MAX_SIZE*sizeof(char)); assert(field[0] != NULL); //lazy a-check
   field[1] = malloc(MAX_SIZE*MAX_SIZE*sizeof(char)); assert(field[1] != NULL);
   atexit(freemem);
   fc = 0;
   char buf[MAX_SIZE];
   j = 0;
   while( !feof(p) && fgets(buf, MAX_SIZE, p) && ( j < MAX_SIZE )) {
     for(i=0; (buf[i] != 0) && (buf[i] != 10) && (i < MAX_SIZE); i++ ) {
       *(field[fc%2] + j*width + i) = buf[i];
     }
     for( ; i < MAX_SIZE; i++) *(field[fc%2] + j*width + i) = 0;
     j++;
   }
   
   fclose(p);
   // no more error check :)
   glutInit(&argc, argv);
   win = glutCreateWindow("Wireworld");
   glutInitWindowPosition(0,0);
   glutInitWindowSize(width*PPP, height*PPP);
   glutDisplayFunc(wireworld_show);    
   glutKeyboardFunc(key_hit);
   // (-1,-1) from lower leftmost to upper leftmost corner
   float matrix[16] = {
     1, 0, 0, 0,
     0, -1, 0, 0,
     0, 0, 1, 0,
     0, 0, 0, 1
   };
   glLoadMatrixf(matrix);
   glutMainLoop();
 } else {
   fprintf(stderr, "cannot open %s\n", argv[1]);
   exit(EXIT_FAILURE);
 }
 exit(EXIT_SUCCESS);

}</lang>