Conway's game of life - derived from another project, turned into a c++ class, and scaled to support up to a 480x272 display, or a lower resolution color display.

Dependents:   GameOfLife

Committer:
WiredHome
Date:
Wed Apr 23 11:40:10 2014 +0000
Revision:
1:9e88d16ab21e
Parent:
0:d43dc92ae767
Child:
2:c11005ab38db
Updated documentation.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
WiredHome 1:9e88d16ab21e 1 /// Conway's game of life
WiredHome 1:9e88d16ab21e 2 ///
WiredHome 1:9e88d16ab21e 3 /// http://en.wikipedia.org/wiki/Conway's_Game_of_Life
WiredHome 1:9e88d16ab21e 4 ///
WiredHome 1:9e88d16ab21e 5 /// A simple cellular automation where pixels are born, live, and die
WiredHome 1:9e88d16ab21e 6 /// following a simple set of rules. The oddest of the rules is that
WiredHome 1:9e88d16ab21e 7 /// it takes 3 to create birth of a new life...
WiredHome 1:9e88d16ab21e 8 ///
WiredHome 1:9e88d16ab21e 9 /// Early on (back in the 70's), computers were not accessible to
WiredHome 1:9e88d16ab21e 10 /// most, and yet somehow this simulation flourished. I was one of
WiredHome 1:9e88d16ab21e 11 /// many that used pencil and graph paper, chalk on a board and
WiredHome 1:9e88d16ab21e 12 /// even pennies on paper to simulate each cell. It was so much
WiredHome 1:9e88d16ab21e 13 /// more animated when I had access to an 8008 micro and a "TV
WiredHome 1:9e88d16ab21e 14 /// typewriter" interface.
WiredHome 1:9e88d16ab21e 15 ///
WiredHome 0:d43dc92ae767 16 #include "mbed.h"
WiredHome 0:d43dc92ae767 17
WiredHome 0:d43dc92ae767 18 // Defined and Derived values to check if it exceeds available memory
WiredHome 0:d43dc92ae767 19 #define FRAMES_PER_BIT 2 /* current and next life cycle */
WiredHome 0:d43dc92ae767 20
WiredHome 0:d43dc92ae767 21 //#if (LIFE_W * LIFE_H * BITS_PER_LIFE * FRAMES_PER_BIT / 8) > (BYTE_RSVD_RAM)
WiredHome 0:d43dc92ae767 22 //#error Bummer, can't make the lifemap that big
WiredHome 0:d43dc92ae767 23 //#endif
WiredHome 0:d43dc92ae767 24
WiredHome 0:d43dc92ae767 25
WiredHome 0:d43dc92ae767 26 class Life {
WiredHome 0:d43dc92ae767 27 public:
WiredHome 0:d43dc92ae767 28 typedef enum {
WiredHome 0:d43dc92ae767 29 monochrome, ///< life cycle is dead or living
WiredHome 0:d43dc92ae767 30 color ///< life cycle is dying to dead and birthing to living
WiredHome 0:d43dc92ae767 31 } Animation;
WiredHome 0:d43dc92ae767 32
WiredHome 0:d43dc92ae767 33 typedef enum {
WiredHome 0:d43dc92ae767 34 dead,
WiredHome 0:d43dc92ae767 35 living,
WiredHome 0:d43dc92ae767 36 dying,
WiredHome 0:d43dc92ae767 37 birthing
WiredHome 0:d43dc92ae767 38 } ValueOfLife;
WiredHome 0:d43dc92ae767 39
WiredHome 0:d43dc92ae767 40 /// constructor for the life
WiredHome 0:d43dc92ae767 41 ///
WiredHome 1:9e88d16ab21e 42 /// Constructor for the life object. The most important thing
WiredHome 1:9e88d16ab21e 43 /// when constructing life, is to have room for the occupants,
WiredHome 1:9e88d16ab21e 44 /// so take care that memory is actually available for the
WiredHome 1:9e88d16ab21e 45 /// life map on your system.
WiredHome 1:9e88d16ab21e 46 ///
WiredHome 1:9e88d16ab21e 47 /// The required memory in bits is:
WiredHome 1:9e88d16ab21e 48 ///
WiredHome 1:9e88d16ab21e 49 /// w * h * 2 * (animate == color) ? 2 : 1
WiredHome 1:9e88d16ab21e 50 ///
WiredHome 1:9e88d16ab21e 51 /// The '2' is because it keeps a current generation map and
WiredHome 1:9e88d16ab21e 52 /// a next generation map.
WiredHome 1:9e88d16ab21e 53 ///
WiredHome 1:9e88d16ab21e 54 /// As an example:
WiredHome 1:9e88d16ab21e 55 /// 480 * 272 * 2 * 1 => 261120 bits => 32640 bytes
WiredHome 1:9e88d16ab21e 56 ///
WiredHome 1:9e88d16ab21e 57 /// Fragments from a sample application you might find in main.cpp
WiredHome 1:9e88d16ab21e 58 /// are shown here, this one for the RA8875 display graphics
WiredHome 1:9e88d16ab21e 59 /// library. (see http://mbed.org/components/RA8875-Based-Display/)
WiredHome 0:d43dc92ae767 60 ///
WiredHome 1:9e88d16ab21e 61 /// @code
WiredHome 1:9e88d16ab21e 62 /// #define SCREEN_W 480
WiredHome 1:9e88d16ab21e 63 /// #define SCREEN_H 272
WiredHome 1:9e88d16ab21e 64 /// Life life(LIFE_W, LIFE_H, Life::monochrome);
WiredHome 1:9e88d16ab21e 65 /// RA8875 lcd(p5, p6, p7, p12, NC, "tft");
WiredHome 1:9e88d16ab21e 66 ///
WiredHome 1:9e88d16ab21e 67 /// // Where on screen do we locate it?
WiredHome 1:9e88d16ab21e 68 /// #define LIFE_OFFSET_X (SCREEN_W - LIFE_W)
WiredHome 1:9e88d16ab21e 69 /// #define LIFE_OFFSET_Y (SCREEN_H - LIFE_H)
WiredHome 1:9e88d16ab21e 70 ///
WiredHome 1:9e88d16ab21e 71 /// int main()
WiredHome 1:9e88d16ab21e 72 /// {
WiredHome 1:9e88d16ab21e 73 /// life.setbit(1,1, Life::living);
WiredHome 1:9e88d16ab21e 74 /// life.setbit(1,2, Life::living);
WiredHome 1:9e88d16ab21e 75 /// life.setbit(1,3, Life::living);
WiredHome 1:9e88d16ab21e 76 /// while(1) {
WiredHome 1:9e88d16ab21e 77 /// static uint16_t toggle = 0;
WiredHome 1:9e88d16ab21e 78 /// if ((++toggle & 1) == 0) {
WiredHome 1:9e88d16ab21e 79 /// life.GenerationStep();
WiredHome 1:9e88d16ab21e 80 /// } else {
WiredHome 1:9e88d16ab21e 81 /// life.UpdateLifeCycle();
WiredHome 1:9e88d16ab21e 82 /// }
WiredHome 1:9e88d16ab21e 83 /// ScreenUpdate();
WiredHome 1:9e88d16ab21e 84 /// }
WiredHome 1:9e88d16ab21e 85 /// }
WiredHome 1:9e88d16ab21e 86 ///
WiredHome 1:9e88d16ab21e 87 /// void ScreenUpdate()
WiredHome 1:9e88d16ab21e 88 /// {
WiredHome 1:9e88d16ab21e 89 /// lcd.window(LIFE_OFFSET_X, LIFE_OFFSET_Y, LIFE_W, LIFE_H);
WiredHome 1:9e88d16ab21e 90 /// lcd._StartGraphicsStream();
WiredHome 1:9e88d16ab21e 91 /// for (int j = 0; j < LIFE_H; j++) {
WiredHome 1:9e88d16ab21e 92 /// for (int i = 0; i < LIFE_W; i++) {
WiredHome 1:9e88d16ab21e 93 /// Life::ValueOfLife lifeState = life.getbit(i,j);
WiredHome 1:9e88d16ab21e 94 /// switch (lifeState) {
WiredHome 1:9e88d16ab21e 95 /// case Life::dead:
WiredHome 1:9e88d16ab21e 96 /// lcd._putp(Black);
WiredHome 1:9e88d16ab21e 97 /// break;
WiredHome 1:9e88d16ab21e 98 /// case Life::dying:
WiredHome 1:9e88d16ab21e 99 /// lcd._putp(RGB(64,0,0));
WiredHome 1:9e88d16ab21e 100 /// break;
WiredHome 1:9e88d16ab21e 101 /// case Life::living:
WiredHome 1:9e88d16ab21e 102 /// lcd._putp(Charcoal);
WiredHome 1:9e88d16ab21e 103 /// break;
WiredHome 1:9e88d16ab21e 104 /// case Life::birthing:
WiredHome 1:9e88d16ab21e 105 /// lcd._putp(Blue);
WiredHome 1:9e88d16ab21e 106 /// break;
WiredHome 1:9e88d16ab21e 107 /// default:
WiredHome 1:9e88d16ab21e 108 /// lcd._putp(Orange);
WiredHome 1:9e88d16ab21e 109 /// ERR(" lifeState = %d\r\n", lifeState);
WiredHome 1:9e88d16ab21e 110 /// break;
WiredHome 1:9e88d16ab21e 111 /// }
WiredHome 1:9e88d16ab21e 112 /// }
WiredHome 1:9e88d16ab21e 113 /// }
WiredHome 1:9e88d16ab21e 114 /// lcd._EndGraphicsStream();
WiredHome 1:9e88d16ab21e 115 /// lcd.WindowMax();
WiredHome 1:9e88d16ab21e 116 /// }
WiredHome 1:9e88d16ab21e 117 /// @endcode
WiredHome 1:9e88d16ab21e 118 ///
WiredHome 1:9e88d16ab21e 119 /// @param[in] w is the width of the life map in pixels, commonly
WiredHome 1:9e88d16ab21e 120 /// chosen to match the display device capability.
WiredHome 1:9e88d16ab21e 121 /// @param[in] h is the height of the life map in pixels, commonly
WiredHome 1:9e88d16ab21e 122 /// chosen to match the display device capability.
WiredHome 1:9e88d16ab21e 123 /// @param[in] animate is an optional parameter that can be either
WiredHome 1:9e88d16ab21e 124 /// 'monochrome' or 'color' (the default), which determines
WiredHome 1:9e88d16ab21e 125 /// if each life cycle has one step (e.g. from life directly
WiredHome 1:9e88d16ab21e 126 /// to death) or two steps (e.g. life to dying to death).
WiredHome 1:9e88d16ab21e 127 /// @param[in] pMap is an optional pointer to a block of memory to
WiredHome 1:9e88d16ab21e 128 /// host the life map. If not specified, it will assume
WiredHome 1:9e88d16ab21e 129 /// the memory space of an LPC1768 where the 32K Ethernet
WiredHome 1:9e88d16ab21e 130 /// buffers are not being used (and take that space for the
WiredHome 1:9e88d16ab21e 131 /// life map).
WiredHome 1:9e88d16ab21e 132 ///
WiredHome 1:9e88d16ab21e 133 Life(int w, int h, Animation animate = color, uint8_t * pMap = (uint8_t *)(0x2007C000));
WiredHome 0:d43dc92ae767 134
WiredHome 0:d43dc92ae767 135 /// sets a life value in the frame at location x,y.
WiredHome 0:d43dc92ae767 136 ///
WiredHome 1:9e88d16ab21e 137 /// @param[in] x is the x location in the life-map
WiredHome 1:9e88d16ab21e 138 /// @param[in] y is the y location in the life-map
WiredHome 1:9e88d16ab21e 139 /// @param[in] otherframe selects the next life-cycle of interest
WiredHome 1:9e88d16ab21e 140 /// @param[in] b is the value of life to assign to that location
WiredHome 0:d43dc92ae767 141 ///
WiredHome 0:d43dc92ae767 142 void setbit(int x, int y, ValueOfLife b, int otherframe = 0);
WiredHome 0:d43dc92ae767 143
WiredHome 0:d43dc92ae767 144 /// gets the life value from the specified location.
WiredHome 0:d43dc92ae767 145 ///
WiredHome 1:9e88d16ab21e 146 /// @param[in] x is the x location in the life-map
WiredHome 1:9e88d16ab21e 147 /// @param[in] y is the y location in the life-map
WiredHome 1:9e88d16ab21e 148 /// @param[in] otherframe selects the next life-cycle of interest
WiredHome 0:d43dc92ae767 149 /// @returns the value of life at that location.
WiredHome 0:d43dc92ae767 150 ///
WiredHome 0:d43dc92ae767 151 ValueOfLife getbit(int x, int y, int otherframe = 0);
WiredHome 0:d43dc92ae767 152
WiredHome 0:d43dc92ae767 153 /// Count and return the number of living neighbors.
WiredHome 0:d43dc92ae767 154 ///
WiredHome 1:9e88d16ab21e 155 /// @param[in] x is the x location in the life-map
WiredHome 1:9e88d16ab21e 156 /// @param[in] y is the y location in the life-map
WiredHome 0:d43dc92ae767 157 /// @returns the number of neighbors
WiredHome 0:d43dc92ae767 158 ///
WiredHome 0:d43dc92ae767 159 int CountNeighbors(int x, int y);
WiredHome 0:d43dc92ae767 160
WiredHome 0:d43dc92ae767 161 /// Destroy all life - typically at startup.
WiredHome 0:d43dc92ae767 162 ///
WiredHome 0:d43dc92ae767 163 void DestroyAllLife(void);
WiredHome 0:d43dc92ae767 164
WiredHome 0:d43dc92ae767 165 /// Step life forward by one generation
WiredHome 0:d43dc92ae767 166 ///
WiredHome 0:d43dc92ae767 167 void GenerationStep(void);
WiredHome 0:d43dc92ae767 168
WiredHome 0:d43dc92ae767 169 /// Update the life-cycle.
WiredHome 0:d43dc92ae767 170 ///
WiredHome 0:d43dc92ae767 171 /// This method applies partial step to a life cycle.
WiredHome 0:d43dc92ae767 172 /// It does this when the Life is set up for color mode
WiredHome 0:d43dc92ae767 173 /// where you can then see birthing and dying cells as
WiredHome 0:d43dc92ae767 174 /// a result of this method.
WiredHome 0:d43dc92ae767 175 ///
WiredHome 0:d43dc92ae767 176 void UpdateLifeCycle(void);
WiredHome 0:d43dc92ae767 177
WiredHome 0:d43dc92ae767 178 /// Apply the cycle of life to a cell.
WiredHome 0:d43dc92ae767 179 ///
WiredHome 0:d43dc92ae767 180 /// Based on the number of neighbors, and the current
WiredHome 0:d43dc92ae767 181 /// state of a cell, this determines whether the cell
WiredHome 0:d43dc92ae767 182 /// is born, lives, or dies.
WiredHome 0:d43dc92ae767 183 ///
WiredHome 1:9e88d16ab21e 184 /// @param[in] x is the x offset into the life map.
WiredHome 1:9e88d16ab21e 185 /// @param[in] y is the y offset into the life map.
WiredHome 1:9e88d16ab21e 186 /// @param[in] neighbors is the count of neighbors.
WiredHome 0:d43dc92ae767 187 ///
WiredHome 0:d43dc92ae767 188 void CycleOfLife(int x, int y, int neighbors);
WiredHome 0:d43dc92ae767 189
WiredHome 0:d43dc92ae767 190 private:
WiredHome 1:9e88d16ab21e 191 int LIFE_W; // dimensions of the life map
WiredHome 0:d43dc92ae767 192 int LIFE_H;
WiredHome 1:9e88d16ab21e 193 int maxX; // set max element for ease of iterations
WiredHome 0:d43dc92ae767 194 int maxY;
WiredHome 1:9e88d16ab21e 195 int frame; // the current life cycle
WiredHome 1:9e88d16ab21e 196 int animation; // mode - color or b&w
WiredHome 0:d43dc92ae767 197 uint8_t * pLifeMap;
WiredHome 0:d43dc92ae767 198 };
WiredHome 0:d43dc92ae767 199