/* --------------------------------------------------------------------------- Syn, by Allan Crossman: a cellulase model from Edinburgh iGEM 2011. If (only if) compiled with the Makefile, SDL graphics library is used. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2. --------------------------------------------------------------------------- */ #define VERSION "v10" // Bugfix in bioseinhib code (was using ints) // Ability to use user-specified seed. // Colours... #define GLU_R 0 #define GLU_G 255 #define GLU_B 255 #define EXO_R 255 #define EXO_G 255 #define EXO_B 255 #define ENDO_R 255 #define ENDO_G 255 #define ENDO_B 0 #define SUGAR_R 0 #define SUGAR_G 200 #define SUGAR_B 0 #define BOND_R 150 #define BOND_G 200 #define BOND_B 150 // Default settings. These can be changed via command-line arguments... #define DEFAULT_MARGIN 4 // Margin of nothingness. #define DEFAULT_ENZYMES 20 // Enzymes of each type on each side. #define DEFAULT_HALFWIDTH 155 // Simulation width. #define DEFAULT_HEIGHT 155 // Simulation height. #define DEFAULT_REPORTTICK 250 // How often to print count of glucose & cellobiose molecules. #define DEFAULT_BMPMAG 1 // Magnification in BMP files. #define DEFAULT_SDLTICK 1 // How often to refresh the screen in SDL mode. #define DEFAULT_SDLMAG 2 // Magnification in SDL windowed mode. #define DEFAULT_DELAY 20 // Wait this many milliseconds between SDL frames. #define DEFAULT_BIOSEINHIBLEFT (float) 1.0 // Strength of cellobiose inhibition #define DEFAULT_BIOSEINHIBRIGHT (float) 1.0 // in the 2 simulations. #define DEFAULT_ENDOREQLEFT 5 // Sugars needed on each side of a bond #define DEFAULT_ENDOREQRIGHT 5 // for endoglucanase to cut it. // When to end the simulation (0 for never)... #ifndef USE_SDL #define DEFAULT_ENDPOINT 20000 // ... in No-SDL mode. #else #define DEFAULT_ENDPOINT 0 // ... in SDL mode. #endif // How often to draw a .bmp file (0 for never)... #ifndef USE_SDL #define DEFAULT_BMPTICK 500 // ... in No-SDL mode. #else #define DEFAULT_BMPTICK 0 // ... in SDL mode. #endif // Default use of synergy. These can be changed with --bothsyn or --nosyn #define DEFAULT_SYNERGYLEFT 0 #define DEFAULT_SYNERGYRIGHT 1 #include #include #include #include #include #include #include #ifdef USE_SDL #include #endif #define EMPTY 0 #define SUGAR 1 #define BOND 2 #define ENDO 3 #define EXO 4 #define GLU 5 #ifdef USE_SDL #define setrgb(screen, x, y, red, green, blue) putpixel(screen, x, y, SDL_MapRGB(screen->format, red, green, blue)) #endif struct cellulase_struct { int x; int y; }; #ifdef USE_SDL // Some globals... SDL_Surface * virtue; // Main virtual screen. SDL_Event event; #endif // The main data array... char ** world; // A pixmap to draw to .bmp files if needed... char ** worldtodraw; // Cellulases... struct cellulase_struct * endo; struct cellulase_struct * exo; struct cellulase_struct * glu; // Options user can set via command line... int halfwidth = DEFAULT_HALFWIDTH; int width = DEFAULT_HALFWIDTH * 2; int height = DEFAULT_HEIGHT; int enzymes = DEFAULT_ENZYMES; int sdlmag = DEFAULT_SDLMAG; int bmpmag = DEFAULT_BMPMAG; int bmptick = DEFAULT_BMPTICK; int endpoint = DEFAULT_ENDPOINT; int reporttick = DEFAULT_REPORTTICK; int sdltick = DEFAULT_SDLTICK; int endoreqleft = DEFAULT_ENDOREQLEFT; int endoreqright = DEFAULT_ENDOREQRIGHT; int margin = DEFAULT_MARGIN; int delay = DEFAULT_DELAY; float bioseinhibleft = DEFAULT_BIOSEINHIBLEFT; float bioseinhibright = DEFAULT_BIOSEINHIBRIGHT; int synergyleft = DEFAULT_SYNERGYLEFT; int synergyright = DEFAULT_SYNERGYRIGHT; /* --------------- End of header. Start of code, functions, etc... --------------- */ // Exit cleanly, shutting down SDL. void cleanexit (int exitstatus) { #ifdef USE_SDL SDL_Quit(); #endif // If we ever use sound we must also do Mix_CloseAudio(); exit(exitstatus); } #ifdef USE_SDL // Manage relevant events. Should test for key presses here. void manageevents (void) { while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { cleanexit(0); } if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE) { cleanexit(0); } } return; } #endif // Random number between 0 and 1. float rnd (void) { return (float)rand() / RAND_MAX; } // Return integer between 0 and max inclusive. int intrnd (int max) { int result; result = rnd() * (max + 1); result %= max + 1; return result; } void randomwalk (struct cellulase_struct * c) { c->x += intrnd(2) - 1; c->y += intrnd(2) - 1; // Prevent enzymes falling off the left or right side... if (c->x == 0) c->x = 1; if (c->x == width - 1) c->x = width - 2; // Prevent enzymes crossing the centre... if (c->x == halfwidth - 1) c->x = halfwidth - 2; if (c->x == halfwidth) c->x = halfwidth + 1; // Prevent enzymes falling off the top or bottom... if (c->y == 0) c->y = 1; if (c->y == height - 1) c->y = height - 2; return; } // How many sugars to the left of this spot, plus 1 if there's a sugar on this spot // But zero if this spot is empty. Call with result = 0. int leftchain (int x, int y, int result) { if (x < 0 || x >= width || y < 0 || y >= height) return 0; if (world[x][y] == EMPTY) return 0; if (world[x][y] == BOND) result = 0 + leftchain(x - 1, y, result); if (world[x][y] == SUGAR) result = 1 + leftchain(x - 1, y, result); return result; } // How many sugars to the right of this spot, plus 1 if there's a sugar on this spot // But zero if this spot is empty. Call with result = 0. int rightchain (int x, int y, int result) { if (x < 0 || x >= width || y < 0 || y >= height) return 0; if (world[x][y] == EMPTY) return 0; if (world[x][y] == BOND) result = 0 + rightchain(x + 1, y, result); if (world[x][y] == SUGAR) result = 1 + rightchain(x + 1, y, result); return result; } #ifdef USE_SDL // Puts a pixel on the SDL surface. Surface should really be locked. // From Bill Kendrick's GPL game Vectoroids (http://www.newbreedsoftware.com/vectoroids) void putpixel(SDL_Surface * surface, int x, int y, Uint32 pixel) { int bpp; Uint8 * p; // Assuming the X/Y values are within the bounds of this surface... if (x >= 0 && y >= 0 && x < surface->w && y < surface->h) { // Determine bytes-per-pixel for the surface in question: */ bpp = surface->format->BytesPerPixel; // Set a pointer to the exact location in memory of the pixel // in question: p = (((Uint8 *) surface->pixels) + // Start at beginning of RAM (y * surface->pitch) + // Go down Y lines (x * bpp)); // Go in X pixels // Set the (correctly-sized) piece of data in the surface's RAM // to the pixel value sent in: if (bpp == 1) { *p = pixel; } else if (bpp == 2) { *(Uint16 *)p = pixel; } else if (bpp == 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; } } else if (bpp == 4) { *(Uint32 *)p = pixel; } } return; } #endif #ifdef USE_SDL // Pixel putting routine that scales stuff up... void drawmag (SDL_Surface * screen, int x, int y, int magnify, int red, int green, int blue) { int i; int j; for (i = 0; i < magnify; i++) { for (j = 0; j < magnify; j++) { setrgb(screen, x * magnify + i, y * magnify + j, red, green, blue); } } return; } #endif void drawbmp (char * filename, int magnify) { unsigned int headers[13]; FILE * outfile; int extrabytes; int paddedsize; int x; int y; int n; int i; int j; int red, green, blue; // First we need to update the pixmap, so we know what pixels to draw as enzymes... for (x = 0; x < width; x++) { for (y = 0; y < height; y++) { worldtodraw[x][y] = world[x][y]; } } for (n = 0; n < enzymes * 2; n++) { worldtodraw[endo[n].x][endo[n].y] = ENDO; worldtodraw[exo[n].x][exo[n].y] = EXO; worldtodraw[glu[n].x][glu[n].y] = GLU; } extrabytes = 4 - ((width * magnify * 3) % 4); // How many bytes of padding to add to each // horizontal line - the size of which must // be a multiple of 4 bytes. if (extrabytes == 4) extrabytes = 0; paddedsize = ((width * magnify * 3) + extrabytes) * height * magnify; // Headers... // Note that the "BM" identifier in bytes 0 and 1 is NOT included in these "headers". headers[0] = paddedsize + 54; // bfSize (whole file size) headers[1] = 0; // bfReserved (both) headers[2] = 54; // bfOffbits headers[3] = 40; // biSize headers[4] = width * magnify; // biWidth headers[5] = height * magnify; // biHeight // Would have biPlanes and biBitCount in position 6, but they're shorts. // It's easier to write them out separately (see below) than pretend // they're a single int, especially with endian issues... headers[7] = 0; // biCompression headers[8] = paddedsize; // biSizeImage headers[9] = 0; // biXPelsPerMeter headers[10] = 0; // biYPelsPerMeter headers[11] = 0; // biClrUsed headers[12] = 0; // biClrImportant outfile = fopen(filename, "wb"); // // Headers begin... // When printing ints and shorts, we write out 1 character at a time to avoid endian issues. // fprintf(outfile, "BM"); for (n = 0; n <= 5; n++) { fprintf(outfile, "%c", headers[n] & 0x000000FF); fprintf(outfile, "%c", (headers[n] & 0x0000FF00) >> 8); fprintf(outfile, "%c", (headers[n] & 0x00FF0000) >> 16); fprintf(outfile, "%c", (headers[n] & (unsigned int) 0xFF000000) >> 24); } // These next 4 characters are for the biPlanes and biBitCount fields. fprintf(outfile, "%c", 1); fprintf(outfile, "%c", 0); fprintf(outfile, "%c", 24); fprintf(outfile, "%c", 0); for (n = 7; n <= 12; n++) { fprintf(outfile, "%c", headers[n] & 0x000000FF); fprintf(outfile, "%c", (headers[n] & 0x0000FF00) >> 8); fprintf(outfile, "%c", (headers[n] & 0x00FF0000) >> 16); fprintf(outfile, "%c", (headers[n] & (unsigned int) 0xFF000000) >> 24); } // // Headers done, now write the data... // for (y = height - 1; y >= 0; y--) // BMP image format is written from bottom to top... { for (j = 0; j < magnify; j++) { for (x = 0; x < width; x++) { if (worldtodraw[x][y] == SUGAR) { red = SUGAR_R; green = SUGAR_G; blue = SUGAR_B; } else if (worldtodraw[x][y] == BOND) { red = BOND_R; green = BOND_G; blue = BOND_B; } else if (worldtodraw[x][y] == ENDO) { red = ENDO_R; green = ENDO_G; blue = ENDO_B; } else if (worldtodraw[x][y] == EXO) { red = EXO_R; green = EXO_G; blue = EXO_B; } else if (worldtodraw[x][y] == GLU) { red = GLU_R; green = GLU_G; blue = GLU_B; } else { red = 0; green = 0; blue = 0; } // Also, it's written in (b,g,r) format... for (i = 0; i < magnify; i++) { fprintf(outfile, "%c", blue); fprintf(outfile, "%c", green); fprintf(outfile, "%c", red); } } if (extrabytes) // See above - BMP lines must be of lengths divisible by 4. { for (n = 1; n <= extrabytes; n++) { fprintf(outfile, "%c", 0); } } } } fclose(outfile); return; } // Return 1 if the spot is the bond of a cellobiose molecule, return 0 otherwise. // Assumes bonds that aren't flanked by sugars can't exist. int is_cellobiose_bond (int x, int y) { if (x < 0 || x >= width || y < 0 || y >= height) return 0; if (world[x][y] != BOND) { return 0; } else { if (x > 1) { if (world[x - 2][y] == BOND) return 0; } if (x < width - 2) { if (world[x + 2][y] == BOND) return 0; } } return 1; } // Return 1 if the spot is a glucose sugar, return 0 otherwise. int is_glucose (int x, int y) { if (x < 0 || x >= width || y < 0 || y >= height) return 0; if (world[x][y] != SUGAR) { return 0; } else { if (x > 0) { if (world[x - 1][y] == BOND) return 0; } if (x < width - 1) { if (world[x + 1][y] == BOND) return 0; } } return 1; } int main (int argc, char * argv[]) { #ifdef USE_SDL char wintitle[200]; #endif char filename[200]; int x; int y; int n; float chance; int tick = 0; int glucoseleft = 0; int glucoseright = 0; int bioseleft = 0; int bioseright = 0; int totalsugars = 0; int seed; printf("\nSyn %s, a cellulose degradation model by Edinburgh iGEM\n", VERSION); seed = (int) time(NULL); // Command-line parsing... for (n = 1; n < argc; n++) { if (strcmp(argv[n], "--halfwidth") == 0 && n < argc - 1) { halfwidth = atoi(argv[n + 1]); if (halfwidth < 3) { fprintf(stderr, "Cannot set halfwidth < 3. Setting halfwidth = 3.\n"); halfwidth = 3; } width = halfwidth * 2; } if (strcmp(argv[n], "--height") == 0 && n < argc - 1) { height = atoi(argv[n + 1]); if (height < 3) { fprintf(stderr, "Cannot set height < 3. Setting height = 3.\n"); height = 3; } } if (strcmp(argv[n], "--enzymes") == 0 && n < argc - 1) { enzymes = atoi(argv[n + 1]); if (enzymes < 1) { fprintf(stderr, "Cannot set enzymes < 1. Setting enzmyes = 1.\n"); enzymes = 1; } } if (strcmp(argv[n], "--bmpmag") == 0 && n < argc - 1) { bmpmag = atoi(argv[n + 1]); if (bmpmag < 1) { fprintf(stderr, "Cannot set bmpmag < 1. Setting bmpmag = 1.\n"); bmpmag = 1; } } if (strcmp(argv[n], "--sdlmag") == 0 && n < argc - 1) { sdlmag = atoi(argv[n + 1]); if (sdlmag < 1) { fprintf(stderr, "Cannot set sdlmag < 1. Setting sdlmag = 1.\n"); sdlmag = 1; } } if (strcmp(argv[n], "--bmptick") == 0 && n < argc - 1) { bmptick = atoi(argv[n + 1]); } if (strcmp(argv[n], "--endpoint") == 0 && n < argc - 1) { endpoint = atoi(argv[n + 1]); } if (strcmp(argv[n], "--reporttick") == 0 && n < argc - 1) { reporttick = atoi(argv[n + 1]); } if (strcmp(argv[n], "--sdltick") == 0 && n < argc - 1) { sdltick = atoi(argv[n + 1]); } if (strcmp(argv[n], "--endoreqleft") == 0 && n < argc - 1) { endoreqleft = atoi(argv[n + 1]); if (endoreqleft < 1) { fprintf(stderr, "Cannot set endoreqleft < 1. Setting endoreqleft = 1.\n"); endoreqleft = 1; } } if (strcmp(argv[n], "--endoreqright") == 0 && n < argc - 1) { endoreqright = atoi(argv[n + 1]); if (endoreqright < 1) { fprintf(stderr, "Cannot set endoreqright < 1. Setting endoreqright = 1.\n"); endoreqright = 1; } } if (strcmp(argv[n], "--margin") == 0 && n < argc - 1) { margin = atoi(argv[n + 1]); if (margin < 1) { fprintf(stderr, "Cannot set margin < 1. Setting margin = 1.\n"); margin = 1; } } if (strcmp(argv[n], "--delay") == 0 && n < argc - 1) { delay = atoi(argv[n + 1]); } if (strcmp(argv[n], "--bioseinhibleft") == 0 && n < argc - 1) { bioseinhibleft = atof(argv[n + 1]); // Note use of atof() } if (strcmp(argv[n], "--bioseinhibright") == 0 && n < argc - 1) { bioseinhibright = atof(argv[n + 1]); // Note use of atof() } if (strcmp(argv[n], "--nosyn") == 0) { synergyleft = 0; synergyright = 0; } if (strcmp(argv[n], "--bothsyn") == 0) { synergyleft = 1; synergyright = 1; } if (strcmp(argv[n], "--seed") == 0 && n < argc - 1) { seed = atoi(argv[n + 1]); } } srand(seed); printf("Seed = %d\n", seed); endo = malloc(enzymes * 2 * sizeof(struct cellulase_struct)); exo = malloc(enzymes * 2 * sizeof(struct cellulase_struct)); glu = malloc(enzymes * 2 * sizeof(struct cellulase_struct)); // See comp.lang.c FAQ 6.16 for how to dynamically allocate a 2D array. world = malloc(width * sizeof(char*)); worldtodraw = malloc(width * sizeof(char*)); if (endo == NULL || exo == NULL || glu == NULL || world == NULL || worldtodraw == NULL) { printf("Memory allocation failed!\n"); return 1; } for (n = 0; n < width; n++) { world[n] = malloc(height * sizeof(char)); worldtodraw[n] = malloc(height * sizeof(char)); if (world[n] == NULL || worldtodraw[n] == NULL) { printf("Memory allocation failed!\n"); return 1; } } // Clear the world... for (x = 0; x < width; x++) { for (y = 0; y < height; y++) { world[x][y] = EMPTY; } } // Set up the cellulose... for (x = margin + 1; x < halfwidth - (margin + 1); x += 2) { for (y = margin; y < height - margin; y += 2) { // Left side... world[x][y] = BOND; world[x + 1][y] = SUGAR; world[x - 1][y] = SUGAR; // Right side... world[(width - 1) - x][y] = BOND; world[(width - 1) - (x + 1)][y] = SUGAR; world[(width - 1) - (x - 1)][y] = SUGAR; } } // How many sugars are there on each side, anyway? for (x = 0; x < halfwidth; x++) { for (y = 0; y < height; y++) { if (world[x][y] == SUGAR) totalsugars++; } } // Place the enzymes in random spots... // Cellulases on left side get assigned to 0 <= n <= enzymes - 1 for (n = 0; n < enzymes; n++) { endo[n].x = intrnd(halfwidth - 3) + 1; // i.e. don't put things on the very edge. endo[n].y = intrnd(height - 3) + 1; exo[n].x = intrnd(halfwidth - 3) + 1; exo[n].y = intrnd(height - 3) + 1; glu[n].x = intrnd(halfwidth - 3) + 1; glu[n].y = intrnd(height - 3) + 1; } // Cellulases on left side get assigned to enzymes <= n <= enzymes * 2 - 1 for (n = enzymes; n < enzymes * 2; n++) { endo[n].x = intrnd(halfwidth - 3) + 1 + halfwidth; endo[n].y = intrnd(height - 3) + 1; exo[n].x = intrnd(halfwidth - 3) + 1 + halfwidth; exo[n].y = intrnd(height - 3) + 1; glu[n].x = intrnd(halfwidth - 3) + 1 + halfwidth; glu[n].y = intrnd(height - 3) + 1; } #ifdef USE_SDL // Start SDL and set up the screen... if (SDL_Init(SDL_INIT_VIDEO) < 0) { fprintf(stderr, "\nFatal error: Unable to initialize SDL!\n\n"); exit(EXIT_FAILURE); } virtue = SDL_SetVideoMode(width * sdlmag, height * sdlmag, 0, SDL_ANYFORMAT); if (virtue == NULL) { fprintf(stderr, "\nFatal error: Unable to create virtual screen!\n\n"); exit(EXIT_FAILURE); } #endif printf("\nTotal sugars present per side: %d\n", totalsugars); printf("\nIteration <--Glucose <--Cellobiose Glucose--> Cellobiose-->\n"); while (tick <= endpoint || endpoint == 0) { if (tick % reporttick == 0) { printf("%9d%12d%15d%12d%15d\n", tick, glucoseleft, bioseleft, glucoseright, bioseright); } if (bmptick) { if (tick % bmptick == 0 && tick) { sprintf(filename, "Syn-%05d.bmp", tick); drawbmp(filename, bmpmag); } } /* We now move the 3 enzyme types about and degrade appropriate bonds. Note that in the synergistic system, the order of the enzymes matters; in particular, if the Glu is 2 away from the Exo, it will automatically cut any cellobiose that the Exo creates on that side. This is sort of cheating, so it has been avoided by using the order Glu-Exo-Endo. */ // Do exoglucanase stuff... for (n = 0; n < enzymes * 2; n++) { // Movement... randomwalk(&exo[n]); // Cutting... if (world[exo[n].x][exo[n].y] == BOND) { if (leftchain(exo[n].x, exo[n].y, 0) == 2 || rightchain(exo[n].x, exo[n].y, 0) == 2) { // Inhibition if cellobiose present in the right spots... chance = 1.0; if (is_cellobiose_bond(exo[n].x - 6, exo[n].y)) chance -= (n < enzymes) ? bioseinhibleft : bioseinhibright; if (is_cellobiose_bond(exo[n].x + 6, exo[n].y)) chance -= (n < enzymes) ? bioseinhibleft : bioseinhibright; if (is_cellobiose_bond(exo[n].x - 4, exo[n].y)) chance -= (n < enzymes) ? bioseinhibleft : bioseinhibright; if (is_cellobiose_bond(exo[n].x + 4, exo[n].y)) chance -= (n < enzymes) ? bioseinhibleft : bioseinhibright; if (is_cellobiose_bond(exo[n].x - 2, exo[n].y - 2)) chance -= (n < enzymes) ? bioseinhibleft : bioseinhibright; if (is_cellobiose_bond(exo[n].x + 2, exo[n].y - 2)) chance -= (n < enzymes) ? bioseinhibleft : bioseinhibright; if (is_cellobiose_bond(exo[n].x - 2, exo[n].y + 2)) chance -= (n < enzymes) ? bioseinhibleft : bioseinhibright; if (is_cellobiose_bond(exo[n].x + 2, exo[n].y + 2)) chance -= (n < enzymes) ? bioseinhibleft : bioseinhibright; if (is_cellobiose_bond(exo[n].x, exo[n].y - 2)) chance -= (n < enzymes) ? bioseinhibleft : bioseinhibright; if (is_cellobiose_bond(exo[n].x, exo[n].y + 2)) chance -= (n < enzymes) ? bioseinhibleft : bioseinhibright; if (rnd() < chance) { world[exo[n].x][exo[n].y] = EMPTY; // Exo can produce both glucose and cellobiose. // Keep track of these... if (n < enzymes) { if (is_glucose(exo[n].x - 1, exo[n].y)) glucoseleft++; if (is_glucose(exo[n].x + 1, exo[n].y)) glucoseleft++; if (is_cellobiose_bond(exo[n].x - 2, exo[n].y)) bioseleft++; if (is_cellobiose_bond(exo[n].x + 2, exo[n].y)) bioseleft++; } else { if (is_glucose(exo[n].x - 1, exo[n].y)) glucoseright++; if (is_glucose(exo[n].x + 1, exo[n].y)) glucoseright++; if (is_cellobiose_bond(exo[n].x - 2, exo[n].y)) bioseright++; if (is_cellobiose_bond(exo[n].x + 2, exo[n].y)) bioseright++; } } } } } // Do endoglucanase stuff... for (n = 0; n < enzymes * 2; n++) { // Movement... if (n < enzymes) // Left side { if (synergyleft) { endo[n].x = exo[n].x + 1; endo[n].y = exo[n].y; } else { randomwalk(&endo[n]); } } else { // Right side if (synergyright) { endo[n].x = exo[n].x + 1; endo[n].y = exo[n].y; } else { randomwalk(&endo[n]); } } // Cutting... if (world[endo[n].x][endo[n].y] == BOND) { if ( leftchain(endo[n].x, endo[n].y, 0) >= (n < enzymes ? endoreqleft : endoreqright) && rightchain(endo[n].x, endo[n].y, 0) >= (n < enzymes ? endoreqleft : endoreqright) ) { world[endo[n].x][endo[n].y] = EMPTY; // Endo might produce both glucose and cellobiose (depending on ENDOREQ values). // Keep track of these... if (n < enzymes) { if (is_glucose(endo[n].x - 1, endo[n].y)) glucoseleft++; if (is_glucose(endo[n].x + 1, endo[n].y)) glucoseleft++; if (is_cellobiose_bond(endo[n].x - 2, endo[n].y)) bioseleft++; if (is_cellobiose_bond(endo[n].x + 2, endo[n].y)) bioseleft++; } else { if (is_glucose(endo[n].x - 1, endo[n].y)) glucoseright++; if (is_glucose(endo[n].x + 1, endo[n].y)) glucoseright++; if (is_cellobiose_bond(endo[n].x - 2, endo[n].y)) bioseright++; if (is_cellobiose_bond(endo[n].x + 2, endo[n].y)) bioseright++; } } } } // Do B-glucosidase stuff... for (n = 0; n < enzymes * 2; n++) { // Movement... if (n < enzymes) // Left side { if (synergyleft) { glu[n].x = exo[n].x - 1; glu[n].y = exo[n].y; } else { randomwalk(&glu[n]); } } else { // Right side if (synergyright) { glu[n].x = exo[n].x - 1; glu[n].y = exo[n].y; } else { randomwalk(&glu[n]); } } // Cutting... if (world[glu[n].x][glu[n].y] == BOND) { if (is_cellobiose_bond(glu[n].x, glu[n].y)) { world[glu[n].x][glu[n].y] = EMPTY; // Glu destroys a cellobiose to make 2 glucose. // Keep track of these... if (n < enzymes) { bioseleft--; glucoseleft += 2; } else { bioseright--; glucoseright += 2; } } } } #ifdef USE_SDL if (tick % sdltick == 0) { // Draw the world... for (x = 0; x < width; x++) { for (y = 0; y < height; y++) { if (world[x][y] == EMPTY) drawmag(virtue, x, y, sdlmag, 0, 0, 0); if (world[x][y] == SUGAR) drawmag(virtue, x, y, sdlmag, SUGAR_R, SUGAR_G, SUGAR_B); if (world[x][y] == BOND) drawmag(virtue, x, y, sdlmag, BOND_R, BOND_G, BOND_B); } } // Draw the enzymes... for (n = 0; n < enzymes * 2; n++) { drawmag(virtue, endo[n].x, endo[n].y, sdlmag, ENDO_R, ENDO_G, ENDO_B); drawmag(virtue, exo[n].x, exo[n].y, sdlmag, EXO_R, EXO_G, EXO_B); drawmag(virtue, glu[n].x, glu[n].y, sdlmag, GLU_R, GLU_G, GLU_B); } // Draw to the monitor... SDL_UpdateRect(virtue, 0, 0, 0, 0); manageevents(); SDL_Delay(delay); sprintf(wintitle, "i: %d | <--gluc: %d | <--biose: %d | gluc-->: %d | biose-->: %d", tick, glucoseleft, bioseleft, glucoseright, bioseright); SDL_WM_SetCaption(wintitle, wintitle); } #endif tick++; } return 0; }