diff options
Diffstat (limited to 'apps/plugins/rocklife.c')
-rw-r--r-- | apps/plugins/rocklife.c | 212 |
1 files changed, 115 insertions, 97 deletions
diff --git a/apps/plugins/rocklife.c b/apps/plugins/rocklife.c index 1929dbc564..2905ab53e2 100644 --- a/apps/plugins/rocklife.c +++ b/apps/plugins/rocklife.c | |||
@@ -82,61 +82,82 @@ PLUGIN_HEADER | |||
82 | const struct button_mapping *plugin_contexts[] | 82 | const struct button_mapping *plugin_contexts[] |
83 | = {generic_directions, generic_actions}; | 83 | = {generic_directions, generic_actions}; |
84 | 84 | ||
85 | unsigned char grid_a[LCD_WIDTH][LCD_HEIGHT]; | 85 | #define GRID_W LCD_WIDTH |
86 | unsigned char grid_b[LCD_WIDTH][LCD_HEIGHT]; | 86 | #define GRID_H LCD_HEIGHT |
87 | |||
88 | unsigned char grid_a[GRID_W][GRID_H]; | ||
89 | unsigned char grid_b[GRID_W][GRID_H]; | ||
87 | int generation = 0; | 90 | int generation = 0; |
88 | int population = 0; | 91 | int population = 0; |
89 | int status_line = 0; | 92 | int status_line = 0; |
90 | char buf[30]; | 93 | char buf[30]; |
91 | 94 | ||
92 | static inline void set_cell(int x, int y, char *pgrid){ | 95 | |
93 | pgrid[x+y*LCD_WIDTH]=1; | 96 | static inline bool is_valid_cell(int x, int y) { |
97 | return (x >= 0 && x < GRID_W | ||
98 | && y >= 0 && y < GRID_H); | ||
99 | } | ||
100 | |||
101 | static inline void set_cell_age(int x, int y, unsigned char age, char *pgrid) { | ||
102 | pgrid[x+y*GRID_W] = age; | ||
103 | } | ||
104 | |||
105 | static inline void set_cell(int x, int y, char *pgrid) { | ||
106 | set_cell_age(x, y, 1, pgrid); | ||
107 | } | ||
108 | |||
109 | static inline unsigned char get_cell(int x, int y, char *pgrid) { | ||
110 | if (x < 0) | ||
111 | x += GRID_W; | ||
112 | else if (x >= GRID_W) | ||
113 | x -= GRID_W; | ||
114 | |||
115 | if (y < 0) | ||
116 | y += GRID_H; | ||
117 | else if (y >= GRID_H) | ||
118 | y -= GRID_H; | ||
119 | |||
120 | return pgrid[x+y*GRID_W]; | ||
94 | } | 121 | } |
95 | 122 | ||
96 | /* clear grid */ | 123 | /* clear grid */ |
97 | void init_grid(char *pgrid){ | 124 | void init_grid(char *pgrid){ |
98 | int x, y; | 125 | memset(pgrid, 0, GRID_W * GRID_H); |
99 | |||
100 | for(y=0; y<LCD_HEIGHT; y++){ | ||
101 | for(x=0; x<LCD_WIDTH; x++){ | ||
102 | pgrid[x+y*LCD_WIDTH] = 0; | ||
103 | } | ||
104 | } | ||
105 | } | 126 | } |
106 | 127 | ||
107 | /*fill grid with pattern from file (viewer mode)*/ | 128 | /*fill grid with pattern from file (viewer mode)*/ |
108 | static bool load_cellfile(const char *file, char *pgrid){ | 129 | static bool load_cellfile(const char *file, char *pgrid){ |
109 | int fd, file_size; | 130 | int fd; |
110 | fd = rb->open(file, O_RDONLY); | 131 | fd = rb->open(file, O_RDONLY); |
111 | if (fd==-1) | 132 | if (fd==-1) |
112 | return false; | 133 | return false; |
134 | |||
135 | init_grid(pgrid); | ||
136 | |||
137 | char c; | ||
138 | int nc, x, y, xmid, ymid; | ||
139 | x=0; | ||
140 | y=0; | ||
141 | xmid = (GRID_W>>1) - 2; | ||
142 | ymid = (GRID_H>>1) - 2; | ||
143 | |||
144 | while (true) { | ||
145 | nc = read(fd, &c, 1); | ||
146 | if (nc <= 0) | ||
147 | break; | ||
113 | 148 | ||
114 | file_size = rb->filesize(fd); | 149 | switch(c) { |
115 | if (file_size==-1) | ||
116 | return false; | ||
117 | |||
118 | char buf1[file_size]; | ||
119 | int i, j, k, xmid, ymid; | ||
120 | j=0; | ||
121 | k=0; | ||
122 | xmid = (LCD_WIDTH>>1) - 2; | ||
123 | ymid = (LCD_HEIGHT>>1) - 2; | ||
124 | |||
125 | rb->read(fd, buf1, file_size - 1); | ||
126 | |||
127 | for(i=0; i<file_size; i++){ | ||
128 | |||
129 | switch(buf1[i]){ | ||
130 | case '.': | 150 | case '.': |
131 | j++; | 151 | x++; |
132 | break; | 152 | break; |
133 | case 'O': | 153 | case 'O': |
134 | set_cell(xmid + j, ymid + k, pgrid); | 154 | if (is_valid_cell(xmid + x, ymid + y)) |
135 | j++; | 155 | set_cell(xmid + x, ymid + y, pgrid); |
156 | x++; | ||
136 | break; | 157 | break; |
137 | case '\n': | 158 | case '\n': |
138 | k++; | 159 | y++; |
139 | j=0; | 160 | x=0; |
140 | break; | 161 | break; |
141 | default: | 162 | default: |
142 | break; | 163 | break; |
@@ -151,7 +172,7 @@ static void setup_grid(char *pgrid, int pattern){ | |||
151 | int n, max; | 172 | int n, max; |
152 | int xmid, ymid; | 173 | int xmid, ymid; |
153 | 174 | ||
154 | max = LCD_HEIGHT*LCD_WIDTH; | 175 | max = GRID_W * GRID_H; |
155 | 176 | ||
156 | switch(pattern){ | 177 | switch(pattern){ |
157 | case PATTERN_RANDOM: | 178 | case PATTERN_RANDOM: |
@@ -174,8 +195,8 @@ static void setup_grid(char *pgrid, int pattern){ | |||
174 | 195 | ||
175 | case PATTERN_GROWTH_1: | 196 | case PATTERN_GROWTH_1: |
176 | rb->splash(HZ, "Growth"); | 197 | rb->splash(HZ, "Growth"); |
177 | xmid = (LCD_WIDTH>>1) - 2; | 198 | xmid = (GRID_W>>1) - 2; |
178 | ymid = (LCD_HEIGHT>>1) - 2; | 199 | ymid = (GRID_H>>1) - 2; |
179 | set_cell(xmid + 6, ymid + 0 , pgrid); | 200 | set_cell(xmid + 6, ymid + 0 , pgrid); |
180 | set_cell(xmid + 4, ymid + 1 , pgrid); | 201 | set_cell(xmid + 4, ymid + 1 , pgrid); |
181 | set_cell(xmid + 6, ymid + 1 , pgrid); | 202 | set_cell(xmid + 6, ymid + 1 , pgrid); |
@@ -189,8 +210,8 @@ static void setup_grid(char *pgrid, int pattern){ | |||
189 | break; | 210 | break; |
190 | case PATTERN_ACORN: | 211 | case PATTERN_ACORN: |
191 | rb->splash(HZ, "Acorn"); | 212 | rb->splash(HZ, "Acorn"); |
192 | xmid = (LCD_WIDTH>>1) - 3; | 213 | xmid = (GRID_W>>1) - 3; |
193 | ymid = (LCD_HEIGHT>>1) - 1; | 214 | ymid = (GRID_H>>1) - 1; |
194 | set_cell(xmid + 1, ymid + 0 , pgrid); | 215 | set_cell(xmid + 1, ymid + 0 , pgrid); |
195 | set_cell(xmid + 3, ymid + 1 , pgrid); | 216 | set_cell(xmid + 3, ymid + 1 , pgrid); |
196 | set_cell(xmid + 0, ymid + 2 , pgrid); | 217 | set_cell(xmid + 0, ymid + 2 , pgrid); |
@@ -201,8 +222,8 @@ static void setup_grid(char *pgrid, int pattern){ | |||
201 | break; | 222 | break; |
202 | case PATTERN_GROWTH_2: | 223 | case PATTERN_GROWTH_2: |
203 | rb->splash(HZ, "Growth 2"); | 224 | rb->splash(HZ, "Growth 2"); |
204 | xmid = (LCD_WIDTH>>1) - 4; | 225 | xmid = (GRID_W>>1) - 4; |
205 | ymid = (LCD_HEIGHT>>1) - 1; | 226 | ymid = (GRID_H>>1) - 1; |
206 | set_cell(xmid + 0, ymid + 0 , pgrid); | 227 | set_cell(xmid + 0, ymid + 0 , pgrid); |
207 | set_cell(xmid + 1, ymid + 0 , pgrid); | 228 | set_cell(xmid + 1, ymid + 0 , pgrid); |
208 | set_cell(xmid + 2, ymid + 0 , pgrid); | 229 | set_cell(xmid + 2, ymid + 0 , pgrid); |
@@ -262,14 +283,12 @@ static void setup_grid(char *pgrid, int pattern){ | |||
262 | /* display grid */ | 283 | /* display grid */ |
263 | static void show_grid(char *pgrid){ | 284 | static void show_grid(char *pgrid){ |
264 | int x, y; | 285 | int x, y; |
265 | int m; | ||
266 | unsigned char age; | 286 | unsigned char age; |
267 | 287 | ||
268 | rb->lcd_clear_display(); | 288 | rb->lcd_clear_display(); |
269 | for(y=0; y<LCD_HEIGHT; y++){ | 289 | for(y=0; y<GRID_H; y++){ |
270 | for(x=0; x<LCD_WIDTH; x++){ | 290 | for(x=0; x<GRID_W; x++){ |
271 | m = y*LCD_WIDTH+x; | 291 | age = get_cell(x, y, pgrid); |
272 | age = pgrid[m]; | ||
273 | if(age){ | 292 | if(age){ |
274 | #if LCD_DEPTH >= 16 | 293 | #if LCD_DEPTH >= 16 |
275 | rb->lcd_set_foreground( LCD_RGBPACK( age, age, age )); | 294 | rb->lcd_set_foreground( LCD_RGBPACK( age, age, age )); |
@@ -291,11 +310,18 @@ static void show_grid(char *pgrid){ | |||
291 | } | 310 | } |
292 | 311 | ||
293 | 312 | ||
294 | /* check state of cell depending on the number of neighbours */ | 313 | /* Calculates whether the cell will be alive in the next generation. |
295 | static inline int check_cell(unsigned char *n){ | 314 | n is the array with 9 elements that represent the cell itself and its |
296 | int sum; | 315 | neighborhood like this (the cell itself is n[4]): |
316 | 0 1 2 | ||
317 | 3 4 5 | ||
318 | 6 7 8 | ||
319 | */ | ||
320 | static inline bool check_cell(unsigned char *n) | ||
321 | { | ||
297 | int empty_cells = 0; | 322 | int empty_cells = 0; |
298 | unsigned char live = 0; | 323 | int alive_cells; |
324 | bool result; | ||
299 | 325 | ||
300 | /* count empty neighbour cells */ | 326 | /* count empty neighbour cells */ |
301 | if(n[0]==0) empty_cells++; | 327 | if(n[0]==0) empty_cells++; |
@@ -308,38 +334,32 @@ static inline int check_cell(unsigned char *n){ | |||
308 | if(n[8]==0) empty_cells++; | 334 | if(n[8]==0) empty_cells++; |
309 | 335 | ||
310 | /* now we build the number of non-zero neighbours :-P */ | 336 | /* now we build the number of non-zero neighbours :-P */ |
311 | sum = 8 - empty_cells; | 337 | alive_cells = 8 - empty_cells; |
312 | 338 | ||
313 | /* 1st and 2nd rule*/ | 339 | if (n[4]) { |
314 | if (n[4] && (sum<2 || sum>3)) | 340 | /* If the cell is alive, it stays alive iff it has 2 or 3 alive neighbours */ |
315 | live = false; | 341 | result = (alive_cells==2 || alive_cells==3); |
316 | 342 | } | |
317 | /* 3rd rule */ | 343 | else { |
318 | if (n[4] && (sum==2 || sum==3)) | 344 | /* If the cell is dead, it gets alive iff it has 3 alive neighbours */ |
319 | live = true; | 345 | result = (alive_cells==3); |
320 | 346 | } | |
321 | /* 4rd rule */ | ||
322 | if (!n[4] && sum==3) | ||
323 | live = true; | ||
324 | 347 | ||
325 | return live; | 348 | return result; |
326 | } | 349 | } |
327 | 350 | ||
328 | /* Calculate the next generation of cells | 351 | /* Calculate the next generation of cells |
329 | * | 352 | * |
330 | * The borders of the grid are connected to their opposite sides. | 353 | * The borders of the grid are connected to their opposite sides. |
331 | * | 354 | * |
332 | * | ||
333 | * To avoid multiplications while accessing data in the 2-d grid | 355 | * To avoid multiplications while accessing data in the 2-d grid |
334 | * (pgrid) we try to re-use previously accessed neighbourhood | 356 | * (pgrid) we try to re-use previously accessed neighbourhood |
335 | * information which is stored in an 3x3 array. | 357 | * information which is stored in an 3x3 array. |
336 | * | ||
337 | */ | 358 | */ |
338 | static void next_generation(char *pgrid, char *pnext_grid){ | 359 | static void next_generation(char *pgrid, char *pnext_grid){ |
339 | int x, y; | 360 | int x, y; |
340 | unsigned char cell; | 361 | bool cell; |
341 | int age; | 362 | unsigned char age; |
342 | int m; | ||
343 | unsigned char n[9]; | 363 | unsigned char n[9]; |
344 | 364 | ||
345 | rb->memset(n, 0, sizeof(n)); | 365 | rb->memset(n, 0, sizeof(n)); |
@@ -357,31 +377,33 @@ static void next_generation(char *pgrid, char *pnext_grid){ | |||
357 | population = 0; | 377 | population = 0; |
358 | 378 | ||
359 | /* go through the grid */ | 379 | /* go through the grid */ |
360 | for(y=0; y<LCD_HEIGHT; y++){ | 380 | for(y=0; y<GRID_H; y++){ |
361 | for(x=0; x<LCD_WIDTH; x++){ | 381 | for(x=0; x<GRID_W; x++){ |
362 | if(y==0 && x==0){ | 382 | if(y==0 && x==0){ |
363 | /* first cell in first row, we have to load all neighbours */ | 383 | /* first cell in first row, we have to load all neighbours */ |
364 | n[0] = pgrid[((x+LCD_WIDTH-1)%LCD_WIDTH)+((y+LCD_HEIGHT-1)%LCD_HEIGHT)*LCD_WIDTH]; | 384 | n[0] = get_cell(x-1, y-1, pgrid); |
365 | n[1] = pgrid[((x )%LCD_WIDTH)+((y+LCD_HEIGHT-1)%LCD_HEIGHT)*LCD_WIDTH]; | 385 | n[1] = get_cell(x, y-1, pgrid); |
366 | n[2] = pgrid[((x +1)%LCD_WIDTH)+((y+LCD_HEIGHT-1)%LCD_HEIGHT)*LCD_WIDTH]; | 386 | n[2] = get_cell(x+1, y-1, pgrid); |
367 | n[3] = pgrid[((x+LCD_WIDTH-1)%LCD_WIDTH)+((y )%LCD_HEIGHT)*LCD_WIDTH]; | 387 | n[3] = get_cell(x-1, y, pgrid); |
368 | n[5] = pgrid[((x +1)%LCD_WIDTH)+((y )%LCD_HEIGHT)*LCD_WIDTH]; | 388 | n[4] = get_cell(x, y, pgrid); |
369 | n[6] = pgrid[((x+LCD_WIDTH-1)%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH]; | 389 | n[5] = get_cell(x+1, y, pgrid); |
370 | n[7] = pgrid[((x )%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH]; | 390 | n[6] = get_cell(x-1, y+1, pgrid); |
371 | n[8] = pgrid[((x +1)%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH]; | 391 | n[7] = get_cell(x, y+1, pgrid); |
392 | n[8] = get_cell(x+1, y+1, pgrid); | ||
372 | } else { | 393 | } else { |
373 | if(x==0){ | 394 | if(x==0){ |
374 | /* beginning of a row, copy what we know about our predecessor, | 395 | /* beginning of a row, copy what we know about our predecessor, |
375 | 0, 1, 3 are known, 2, 5, 6, 7, 8 have to be loaded | 396 | 0, 1, 3, 4 are known, 2, 5, 6, 7, 8 have to be loaded |
376 | */ | 397 | */ |
377 | n[0] = n[4]; | 398 | n[0] = n[4]; |
378 | n[1] = n[5]; | 399 | n[1] = n[5]; |
379 | n[2] = pgrid[((x +1)%LCD_WIDTH)+((y+LCD_HEIGHT-1)%LCD_HEIGHT)*LCD_WIDTH]; | 400 | n[2] = get_cell(x+1, y-1, pgrid); |
380 | n[3] = n[7]; | 401 | n[3] = n[7]; |
381 | n[5] = pgrid[((x +1)%LCD_WIDTH)+((y )%LCD_HEIGHT)*LCD_WIDTH]; | 402 | n[4] = n[8]; |
382 | n[6] = pgrid[((x+LCD_WIDTH-1)%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH]; | 403 | n[5] = get_cell(x+1, y, pgrid); |
383 | n[7] = pgrid[((x )%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH]; | 404 | n[6] = get_cell(x-1, y+1, pgrid); |
384 | n[8] = pgrid[((x +1)%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH]; | 405 | n[7] = get_cell(x, y+1, pgrid); |
406 | n[8] = get_cell(x+1, y+1, pgrid); | ||
385 | } else { | 407 | } else { |
386 | /* we are moving right in a row, | 408 | /* we are moving right in a row, |
387 | * copy what we know about the neighbours on our left side, | 409 | * copy what we know about the neighbours on our left side, |
@@ -389,19 +411,17 @@ static void next_generation(char *pgrid, char *pnext_grid){ | |||
389 | */ | 411 | */ |
390 | n[0] = n[1]; | 412 | n[0] = n[1]; |
391 | n[1] = n[2]; | 413 | n[1] = n[2]; |
392 | n[2] = pgrid[((x +1)%LCD_WIDTH)+((y+LCD_HEIGHT-1)%LCD_HEIGHT)*LCD_WIDTH]; | 414 | n[2] = get_cell(x+1, y-1, pgrid); |
393 | n[3] = n[4]; | 415 | n[3] = n[4]; |
394 | n[5] = pgrid[((x +1)%LCD_WIDTH)+((y )%LCD_HEIGHT)*LCD_WIDTH]; | 416 | n[4] = n[5]; |
417 | n[5] = get_cell(x+1, y, pgrid); | ||
395 | n[6] = n[7]; | 418 | n[6] = n[7]; |
396 | n[7] = n[8]; | 419 | n[7] = n[8]; |
397 | n[8] = pgrid[((x +1)%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH]; | 420 | n[8] = get_cell(x+1, y+1, pgrid); |
398 | } | 421 | } |
399 | } | 422 | } |
400 | 423 | ||
401 | m = x+y*LCD_WIDTH; | ||
402 | |||
403 | /* how old is our cell? */ | 424 | /* how old is our cell? */ |
404 | n[4] = pgrid[m]; | ||
405 | age = n[4]; | 425 | age = n[4]; |
406 | 426 | ||
407 | /* calculate the cell based on given neighbour information */ | 427 | /* calculate the cell based on given neighbour information */ |
@@ -411,14 +431,12 @@ static void next_generation(char *pgrid, char *pnext_grid){ | |||
411 | if(cell){ | 431 | if(cell){ |
412 | population++; | 432 | population++; |
413 | /* prevent overflow */ | 433 | /* prevent overflow */ |
414 | if(age>252){ | 434 | if(age<252) |
415 | pnext_grid[m] = 252; | 435 | age++; |
416 | } else { | 436 | set_cell_age(x, y, age, pnext_grid); |
417 | pnext_grid[m] = age + 1; | ||
418 | } | ||
419 | } | 437 | } |
420 | else | 438 | else |
421 | pnext_grid[m] = 0; | 439 | set_cell_age(x, y, 0, pnext_grid); |
422 | #if 0 | 440 | #if 0 |
423 | DEBUGF("x=%d,y=%d\n", x, y); | 441 | DEBUGF("x=%d,y=%d\n", x, y); |
424 | DEBUGF("cell: %d\n", cell); | 442 | DEBUGF("cell: %d\n", cell); |
@@ -465,7 +483,7 @@ enum plugin_status plugin_start(const void* parameter) | |||
465 | init_grid(pgrid); | 483 | init_grid(pgrid); |
466 | 484 | ||
467 | 485 | ||
468 | if( parameter == NULL ) | 486 | if( parameter == NULL ) |
469 | { | 487 | { |
470 | setup_grid(pgrid, pattern++); | 488 | setup_grid(pgrid, pattern++); |
471 | } | 489 | } |