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.
LifeRules.h@1:9e88d16ab21e, 2014-04-23 (annotated)
- 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?
User | Revision | Line number | New 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 |