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 22:54:34 2014 +0000
Revision:
3:860ae49fedb7
Parent:
2:c11005ab38db
Remove some of the debug stuff.

Who changed what in which revision?

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