home *** CD-ROM | disk | FTP | other *** search
- /* cellmap class definition, constructor, copy_cells(), set_cell(),
- clear_cell(), cell_state(), count_neighbors(), and
- next_generation() for fast, hard-wired neighbor count approach.
- Otherwise, the same as Listing 1. */
-
- 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);
- int count_neighbors(int x, int y);
- void next_generation(cellmap& dest_map);
- };
-
- /* cellmap constructor. Pads around cell storage area with 1 extra
- byte, used for handling edge wrapping. */
- cellmap::cellmap(unsigned int h, unsigned int w)
- {
- width = w;
- width_in_bytes = ((w + 7) / 8) + 2; // pad each side with
- // 1 extra byte
- height = h;
- length_in_bytes = width_in_bytes * (h + 2); // pad top/bottom
- // with 1 extra byte
- cells = new unsigned char[length_in_bytes]; // cell storage
- memset(cells, 0, length_in_bytes); // clear all cells, to start
- }
-
- /* Copies one cellmap's cells to another cellmap. If wrapping is
- enabled, copies edge (wrap) bytes into opposite padding bytes in
- source first, so that the padding bytes off each edge have the
- same values as would be found by wrapping around to the opposite
- edge. Both cellmaps are assumed to be the same size. */
- void cellmap::copy_cells(cellmap &sourcemap)
- {
- unsigned char *cell_ptr;
- int i;
-
- #if WRAP_EDGES
- // Copy left and right edges into padding bytes on right and left
- cell_ptr = sourcemap.cells + width_in_bytes;
- for (i=0; i<height; i++) {
- *cell_ptr = *(cell_ptr + width_in_bytes - 2);
- *(cell_ptr + width_in_bytes - 1) = *(cell_ptr + 1);
- cell_ptr += width_in_bytes;
- }
- // Copy top and bottom edges into padding bytes on bottom and top
- memcpy(sourcemap.cells, sourcemap.cells + length_in_bytes -
- (width_in_bytes * 2), width_in_bytes);
- memcpy(sourcemap.cells + length_in_bytes - width_in_bytes,
- sourcemap.cells + width_in_bytes, width_in_bytes);
- #endif
- // Copy all cells to the destination
- memcpy(cells, sourcemap.cells, length_in_bytes);
- }
-
- /* Turns cell on. x and y are offset by 1 byte down and to the right,
- to compensate for the padding bytes around the cell map. */
- void cellmap::set_cell(unsigned int x, unsigned int y)
- {
- unsigned char *cell_ptr =
- cells + ((y + 1) * width_in_bytes) + ((x / 8) + 1);
-
- *(cell_ptr) |= 0x80 >> (x & 0x07);
- }
-
- /* Turns cell off. x and y are offset by 1 byte down and to the right,
- to compensate for the padding bytes around the cell map. */
- void cellmap::clear_cell(unsigned int x, unsigned int y)
- {
- unsigned char *cell_ptr =
- cells + ((y + 1) * width_in_bytes) + ((x / 8) + 1);
-
- *(cell_ptr) &= ~(0x80 >> (x & 0x07));
- }
-
- /* Returns cell state (1=on or 0=off). x and y are offset by 1 byte
- down and to the right, to compensate for the padding bytes around
- the cell map. */
- int cellmap::cell_state(int x, int y)
- {
- unsigned char *cell_ptr =
- cells + ((y + 1) * width_in_bytes) + ((x / 8) + 1);
-
- return (*cell_ptr & (0x80 >> (x & 0x07))) ? 1 : 0;
- }
-
- /* Counts the number of neighboring on-cells for specified cell. */
- int cellmap::count_neighbors(int x, int y)
- {
- unsigned char *cell_ptr, mask;
- unsigned int neighbor_count;
-
- // Point to upper left neighbor
- cell_ptr = cells + ((y * width_in_bytes) + ((x + 7) / 8));
- mask = 0x80 >> ((x - 1) & 0x07);
- // Count upper left neighbor
- neighbor_count = (*cell_ptr & mask) ? 1 : 0;
- // Count left neighbor
- if ((*(cell_ptr + width_in_bytes) & mask)) neighbor_count++;
- // Count lower left neighbor
- if ((*(cell_ptr + (width_in_bytes * 2)) & mask)) neighbor_count++;
-
- // Point to upper neighbor
- if ((mask >>= 1) == 0) {
- mask = 0x80;
- cell_ptr++;
- }
- // Count upper neighbor
- if ((*cell_ptr & mask)) neighbor_count++;
- // Count lower neighbor
- if ((*(cell_ptr + (width_in_bytes * 2)) & mask)) neighbor_count++;
-
- // Point to upper right neighbor
- if ((mask >>= 1) == 0) {
- mask = 0x80;
- cell_ptr++;
- }
- // Count upper right neighbor
- if ((*cell_ptr & mask)) neighbor_count++;
- // Count right neighbor
- if ((*(cell_ptr + width_in_bytes) & mask)) neighbor_count++;
- // Count lower right neighbor
- if ((*(cell_ptr + (width_in_bytes * 2)) & mask)) neighbor_count++;
-
- return neighbor_count;
- }
-
- /* Calculates the next generation of current_map and stores it in
- next_map. */
- void cellmap::next_generation(cellmap& next_map)
- {
- unsigned int x, y, neighbor_count;
-
- for (y=0; y<height; y++) {
- for (x=0; x<width; x++) {
- neighbor_count = count_neighbors(x, y);
- if (cell_state(x, y) == 1) {
- if ((neighbor_count != 2) && (neighbor_count != 3)) {
- next_map.clear_cell(x, y); // turn it off
- draw_pixel(x, y, OFF_COLOR);
- }
- } else {
- if (neighbor_count == 3) {
- next_map.set_cell(x, y); // turn it on
- draw_pixel(x, y, ON_COLOR);
- }
- }
- }
- }
- }