home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / PCTV3N3.ZIP / L1.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-26  |  8.1 KB  |  273 lines

  1. /* C++ Game of Life implementation for any mode for which mode set
  2.    and draw pixel functions can be provided. The cellmap stores the
  3.    neighbor count for each cell as well as the state of each cell;
  4.    this allows very fast next-state determination. Edges always wrap
  5.    in this implementation.
  6.    Tested with Borland C++ 3.0 in the large model. */
  7. #include <stdlib.h>
  8. #include <stdio.h>
  9. #include <iostream.h>
  10. #include <conio.h>
  11. #include <time.h>
  12. #include <dos.h>
  13. #include <bios.h>
  14. #include <mem.h>
  15.  
  16. #define ON_COLOR  15       // on-cell pixel color
  17. #define OFF_COLOR 0        // off-cell pixel color
  18. #define MSG_LINE  10       // row for text messages
  19. #define GENERATION_LINE 12 // row for generation # display
  20. #define LIMIT_18_HZ  0     // set 1 to to maximum frame rate = 18Hz
  21.  
  22. class cellmap {
  23. private:
  24.    unsigned char *cells;
  25.    unsigned char *temp_cells;
  26.    unsigned int width;
  27.    unsigned int height;
  28.    unsigned int length_in_bytes;
  29. public:
  30.    cellmap(unsigned int h, unsigned int v);
  31.    ~cellmap(void);
  32.    void set_cell(unsigned int x, unsigned int y);
  33.    void clear_cell(unsigned int x, unsigned int y);
  34.    int cell_state(int x, int y);
  35.    int count_neighbors(int x, int y);
  36.    void next_generation(void);
  37.    void init(void);
  38. };
  39.  
  40. extern void enter_display_mode(void);
  41. extern void exit_display_mode(void);
  42. extern void draw_pixel(unsigned int X, unsigned int Y,
  43.    unsigned int Color);
  44. extern void show_text(int x, int y, char *text);
  45.  
  46. /* Controls the size of the cell map. Must be within the
  47.    capabilities of the display mode, and must be limited
  48.    to leave room for text display at right. */
  49. unsigned int cellmap_width = 96;
  50. unsigned int cellmap_height = 96;
  51.  
  52. /* Width & height in pixels of each cell. */
  53. unsigned int magnifier = 2;
  54.  
  55. /* Randomizing seed */
  56. unsigned int seed;
  57.  
  58. void main()
  59. {
  60.    unsigned long generation = 0;
  61.    char gen_text[80];
  62.    long bios_time, start_bios_time;
  63.  
  64.    cellmap current_map(cellmap_height, cellmap_width);
  65.  
  66.    current_map.init();  // randomly initialize cell map
  67.  
  68.    enter_display_mode();
  69.  
  70.    // Keep recalculating and redisplaying generations until any key
  71.    // is pressed
  72.    show_text(0, MSG_LINE, "Generation: ");
  73.    start_bios_time = _bios_timeofday(_TIME_GETCLOCK, &bios_time);
  74.    do {
  75.       generation++;
  76.       sprintf(gen_text, "%10lu", generation);
  77.       show_text(1, GENERATION_LINE, gen_text);
  78.       // Recalculate and draw the next generation
  79.       current_map.next_generation();
  80. #if LIMIT_18_HZ
  81.       // Limit to a maximum of 18.2 frames/second, for visibility
  82.       do {
  83.          _bios_timeofday(_TIME_GETCLOCK, &bios_time);
  84.       } while (start_bios_time == bios_time);
  85.       start_bios_time = bios_time;
  86. #endif
  87.    } while (!kbhit());
  88.  
  89.    getch();    // clear keypress
  90.    exit_display_mode();
  91.    cout << "Total generations: " << generation << "\nSeed: " <<
  92.          seed << "\n";
  93. }
  94.  
  95. /* cellmap constructor. */
  96. cellmap::cellmap(unsigned int h, unsigned int w)
  97. {
  98.    width = w;
  99.    height = h;
  100.    length_in_bytes = w * h;
  101.    cells = new unsigned char[length_in_bytes];  // cell storage
  102.    temp_cells = new unsigned char[length_in_bytes]; // temp storage
  103.    if ( (cells == NULL) || (temp_cells == NULL) ) {
  104.       printf("Out of memory\n");
  105.       exit(1);
  106.    }
  107.    memset(cells, 0, length_in_bytes);  // clear all cells, to start
  108. }
  109.  
  110. /* cellmap destructor. */
  111. cellmap::~cellmap(void)
  112. {
  113.    delete[] cells;
  114.    delete[] temp_cells;
  115. }
  116.  
  117. /* Turns an off-cell on, incrementing the on-neighbor count for the
  118.    eight neighboring cells. */
  119. void cellmap::set_cell(unsigned int x, unsigned int y)
  120. {
  121.    unsigned int w = width, h = height;
  122.    int xoleft, xoright, yoabove, yobelow;
  123.    unsigned char *cell_ptr = cells + (y * w) + x;
  124.  
  125.    // Calculate the offsets to the eight neighboring cells,
  126.    // accounting for wrapping around at the edges of the cell map
  127.    if (x == 0)
  128.       xoleft = w - 1;
  129.    else
  130.       xoleft = -1;
  131.    if (y == 0)
  132.       yoabove = length_in_bytes - w;
  133.    else
  134.       yoabove = -w;
  135.    if (x == (w - 1))
  136.       xoright = -(w - 1);
  137.    else
  138.       xoright = 1;
  139.    if (y == (h - 1))
  140.       yobelow = -(length_in_bytes - w);
  141.    else
  142.       yobelow = w;
  143.  
  144.    *(cell_ptr) |= 0x01;
  145.    *(cell_ptr + yoabove + xoleft) += 2;
  146.    *(cell_ptr + yoabove) += 2;
  147.    *(cell_ptr + yoabove + xoright) += 2;
  148.    *(cell_ptr + xoleft) += 2;
  149.    *(cell_ptr + xoright) += 2;
  150.    *(cell_ptr + yobelow + xoleft) += 2;
  151.    *(cell_ptr + yobelow) += 2;
  152.    *(cell_ptr + yobelow + xoright) += 2;
  153. }
  154.  
  155. /* Turns an on-cell off, decrementing the on-neighbor count for the
  156.    eight neighboring cells. */
  157. void cellmap::clear_cell(unsigned int x, unsigned int y)
  158. {
  159.    unsigned int w = width, h = height;
  160.    int xoleft, xoright, yoabove, yobelow;
  161.    unsigned char *cell_ptr = cells + (y * w) + x;
  162.  
  163.    // Calculate the offsets to the eight neighboring cells,
  164.    // accounting for wrapping around at the edges of the cell map
  165.    if (x == 0)
  166.       xoleft = w - 1;
  167.    else
  168.       xoleft = -1;
  169.    if (y == 0)
  170.       yoabove = length_in_bytes - w;
  171.    else
  172.       yoabove = -w;
  173.    if (x == (w - 1))
  174.       xoright = -(w - 1);
  175.    else
  176.       xoright = 1;
  177.    if (y == (h - 1))
  178.       yobelow = -(length_in_bytes - w);
  179.    else
  180.       yobelow = w;
  181.  
  182.    *(cell_ptr) &= ~0x01;
  183.    *(cell_ptr + yoabove + xoleft) -= 2;
  184.    *(cell_ptr + yoabove ) -= 2;
  185.    *(cell_ptr + yoabove + xoright) -= 2;
  186.    *(cell_ptr + xoleft) -= 2;
  187.    *(cell_ptr + xoright) -= 2;
  188.    *(cell_ptr + yobelow + xoleft) -= 2;
  189.    *(cell_ptr + yobelow) -= 2;
  190.    *(cell_ptr + yobelow + xoright) -= 2;
  191. }
  192.  
  193. /* Returns cell state (1=on or 0=off). */
  194. int cellmap::cell_state(int x, int y)
  195. {
  196.    unsigned char *cell_ptr;
  197.  
  198.    cell_ptr = cells + (y * width) + x;
  199.    return *cell_ptr & 0x01;
  200. }
  201.  
  202. /* Calculates and displays the next generation of current_map */
  203. void cellmap::next_generation()
  204. {
  205.    unsigned int x, y, count;
  206.    unsigned int h = height, w = width;
  207.    unsigned char *cell_ptr, *row_cell_ptr;
  208.  
  209.    // Copy to temp map, so we can have an unaltered version from
  210.    // which to work
  211.    memcpy(temp_cells, cells, length_in_bytes);
  212.  
  213.    // Process all cells in the current cell map
  214.    cell_ptr = temp_cells;     // first cell in cell map
  215.    for (y=0; y<h; y++) {      // repeat for each row of cells
  216.       // Process all cells in the current row of the cell map
  217.       x = 0;
  218.       do {        // repeat for each cell in row
  219.          // Zip quickly through as many off-cells with no
  220.          // neighbors as possible
  221.          while (*cell_ptr == 0) {
  222.             cell_ptr++; // advance to the next cell
  223.             if (++x >= w) goto RowDone;
  224.          }
  225.          // Found a cell that's either on or has on-neighbors,
  226.          // so see if its state needs to be changed
  227.          count = *cell_ptr >> 1; // # of neighboring on-cells
  228.          if (*cell_ptr & 0x01) {
  229.             // Cell is on; turn it off if it doesn't have
  230.             // 2 or 3 neighbors
  231.             if ((count != 2) && (count != 3)) {
  232.                clear_cell(x, y);
  233.                draw_pixel(x, y, OFF_COLOR);
  234.             }
  235.          } else {
  236.             // Cell is off; turn it on if it has exactly 3 neighbors
  237.             if (count == 3) {
  238.                set_cell(x, y);
  239.                draw_pixel(x, y, ON_COLOR);
  240.             }
  241.          }
  242.          // Advance to the next cell
  243.          cell_ptr++; // advance to the next cell byte
  244.       } while (++x < w);
  245. RowDone:
  246.    }
  247. }
  248.  
  249. /* Randomly initializes the cellmap to about 50% on-pixels. */
  250. void cellmap::init()
  251. {
  252.    unsigned int x, y, init_length;
  253.  
  254.    // Get the seed; seed randomly if 0 entered
  255.    cout << "Seed (0 for random seed): ";
  256.    cin >> seed;
  257.    if (seed == 0) seed = (unsigned) time(NULL);
  258.  
  259.    // Randomly initialize the initial cell map to 50% on-pixels
  260.    // (actually generally fewer, because some coordinates will be
  261.    // randomly selected more than once)
  262.    cout << "Initializing...";
  263.    srand(seed);
  264.    init_length = (height * width) / 2;
  265.    do {
  266.       x = random(width);
  267.       y = random(height);
  268.       if (cell_state(x, y) == 0) {
  269.          set_cell(x, y);
  270.       }
  271.    } while (--init_length);
  272. }
  273.