/* Implémentation en C++ du jeu de la vie pour tout mode dont les fonctions de configuration et d'affichage de pixels peuvent êtres fournies . Testé avec Borland C++ en modèle small. */ #include #include #include #include #include #include #include #include #define ON_COLOR 15 // couleur du pixel d'une cellule active #define OFF_COLOR 0 // couleur du pixel d'une cellule inactive #define MSG_LINE 10 // ligne pour les messages texte #define GENERATION_LINE 12 // colonne d'affichage de numéro #define LIMIT_18_HZ 1 // à 1 pour un rafraîchissement maximal = 18Hz #define WRAP_EDGES 1 // à 0 pour désactiver le bouclage // aux bords de la carte de cellules class cellmap { private: unsigned char *cells; unsigned int width; unsigned int width_in_bytes; unsigned int height; unsigned int length_in_bytes; public: cellmap(unsigned int h, unsigned int v); ~cellmap(void); void copy_cells(cellmap &sourcemap); void set_cell(unsigned int x, unsigned int y); void clear_cell(unsigned int x, unsigned int y); int cell_state(int x, int y); void next_generation(cellmap& dest_map); }; extern void enter_display_mode(void); extern void exit_display_mode(void); extern void draw_pixel(unsigned int X, unsigned int Y, unsigned int Color); extern void show_text(int x, int y, char *text); /* Contrôle la taille de la carte de cellule. Doit correspondre aux capacités du mode d'affichage et être limitée pour laisser de la place pour l'affichage du texte sur la droite. */ unsigned int cellmap_width = 96; unsigned int cellmap_height = 96; /* Largeur et hauteur en pixels de chaque cellule affichée à l'écran. */ unsigned int magnifier = 2; void main() { unsigned int init_length, x, y, seed; unsigned long generation = 0; char gen_text[80]; long bios_time, start_bios_time; cellmap current_map(cellmap_height, cellmap_width); cellmap next_map(cellmap_height, cellmap_width); // Récupère une valeur d'initialisation cout << "valeur d'initialisation (0 pour une valeur aléatoire): "; cin >> seed; if (seed == 0) seed = (unsigned) time(NULL); // Initialisation aléatoire de la carte de cellules cout << "Initialisation..."; srand(seed); init_length = (cellmap_height * cellmap_width) / 2; do { x = random(cellmap_width); y = random(cellmap_height); next_map.set_cell(x, y); } while (--init_length); current_map.copy_cells(next_map); // stocke la carte initiale dans current_map enter_display_mode(); // Ne calcule et réaffiche une génération que lorsque une touche est pressée show_text(0, MSG_LINE, "Generation: "); start_bios_time = _bios_timeofday(_TIME_GETCLOCK, &bios_time); do { generation++; sprintf(gen_text, "%10lu", generation); show_text(1, GENERATION_LINE, gen_text); // Recalcule et affiche la prochaine génération current_map.next_generation(next_map); // rafraîchit la carte courante current_map à nouveau current_map.copy_cells(next_map); #if LIMIT_18_HZ // Limite à maximum de 18.2 images par seconde, pour la visualisation do { _bios_timeofday(_TIME_GETCLOCK, &bios_time); } while (start_bios_time == bios_time); start_bios_time = bios_time; #endif } while (!kbhit()); getch(); // exit_display_mode();sort après une touche clavier cout << "Total de générations: " << generation << "\nValeur initiale: " << seed << "\n"; } /* Constructeur de l'objet cellmap . */ cellmap::cellmap(unsigned int h, unsigned int w) { width = w; width_in_bytes = (w + 7) / 8; height = h; length_in_bytes = width_in_bytes * h; cells = new unsigned char[length_in_bytes]; // stockage de la cellule memset(cells, 0, length_in_bytes); // rend les cellules inactives au démarrage } /* Destructeur de l'objet cellmap . */ cellmap::~cellmap(void) { delete[] cells; } /* Copie une cellule de la carte de cellule dans une autre carte. Ces deux cartes sont supposées avoir la même taille. */ void cellmap::copy_cells(cellmap &sourcemap) { memcpy(cells, sourcemap.cells, length_in_bytes); } /* Active les cellules. */ void cellmap::set_cell(unsigned int x, unsigned int y) { unsigned char *cell_ptr = cells + (y * width_in_bytes) + (x / 8); *(cell_ptr) |= 0x80 >> (x & 0x07); } /* Désactive les cellules. */ void cellmap::clear_cell(unsigned int x, unsigned int y) { unsigned char *cell_ptr = cells + (y * width_in_bytes) + (x / 8); *(cell_ptr) &= ~(0x80 >> (x & 0x07)); } /* Retourne l'état de la cellule (1=active ou 0=inactive), optionellement boucle sur le coté opposé */ int cellmap::cell_state(int x, int y) { unsigned char *cell_ptr; #if WRAP_EDGES while (x < 0) x += width; // boucle, si nécessaire while (x >= width) x -= width; while (y < 0) y += height; while (y >= height) y -= height; #else if ((x < 0) || (x >= width) || (y < 0) || (y >= height)) return 0; // retourne 0 si pas de bouclage #endif cell_ptr = cells + (y * width_in_bytes) + (x / 8); return (*cell_ptr & (0x80 >> (x & 0x07))) ? 1 : 0; } /* Calcule la prochaine generation de cellmap et la stocke dans next_map. */ void cellmap::next_generation(cellmap& next_map) { unsigned int x, y, neighbor_count; for (y=0; y