forked from len0rd/rockbox
Some improvements to rocklife (FS#10087, but slightly less paranoid). Main improvement is that the file loading will not lead to stack overflow or illegal memory access.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20610 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
64f4b87a72
commit
b549ce9193
1 changed files with 113 additions and 95 deletions
|
|
@ -82,61 +82,82 @@ PLUGIN_HEADER
|
||||||
const struct button_mapping *plugin_contexts[]
|
const struct button_mapping *plugin_contexts[]
|
||||||
= {generic_directions, generic_actions};
|
= {generic_directions, generic_actions};
|
||||||
|
|
||||||
unsigned char grid_a[LCD_WIDTH][LCD_HEIGHT];
|
#define GRID_W LCD_WIDTH
|
||||||
unsigned char grid_b[LCD_WIDTH][LCD_HEIGHT];
|
#define GRID_H LCD_HEIGHT
|
||||||
|
|
||||||
|
unsigned char grid_a[GRID_W][GRID_H];
|
||||||
|
unsigned char grid_b[GRID_W][GRID_H];
|
||||||
int generation = 0;
|
int generation = 0;
|
||||||
int population = 0;
|
int population = 0;
|
||||||
int status_line = 0;
|
int status_line = 0;
|
||||||
char buf[30];
|
char buf[30];
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool is_valid_cell(int x, int y) {
|
||||||
|
return (x >= 0 && x < GRID_W
|
||||||
|
&& y >= 0 && y < GRID_H);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void set_cell_age(int x, int y, unsigned char age, char *pgrid) {
|
||||||
|
pgrid[x+y*GRID_W] = age;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void set_cell(int x, int y, char *pgrid) {
|
static inline void set_cell(int x, int y, char *pgrid) {
|
||||||
pgrid[x+y*LCD_WIDTH]=1;
|
set_cell_age(x, y, 1, pgrid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned char get_cell(int x, int y, char *pgrid) {
|
||||||
|
if (x < 0)
|
||||||
|
x += GRID_W;
|
||||||
|
else if (x >= GRID_W)
|
||||||
|
x -= GRID_W;
|
||||||
|
|
||||||
|
if (y < 0)
|
||||||
|
y += GRID_H;
|
||||||
|
else if (y >= GRID_H)
|
||||||
|
y -= GRID_H;
|
||||||
|
|
||||||
|
return pgrid[x+y*GRID_W];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clear grid */
|
/* clear grid */
|
||||||
void init_grid(char *pgrid){
|
void init_grid(char *pgrid){
|
||||||
int x, y;
|
memset(pgrid, 0, GRID_W * GRID_H);
|
||||||
|
|
||||||
for(y=0; y<LCD_HEIGHT; y++){
|
|
||||||
for(x=0; x<LCD_WIDTH; x++){
|
|
||||||
pgrid[x+y*LCD_WIDTH] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*fill grid with pattern from file (viewer mode)*/
|
/*fill grid with pattern from file (viewer mode)*/
|
||||||
static bool load_cellfile(const char *file, char *pgrid){
|
static bool load_cellfile(const char *file, char *pgrid){
|
||||||
int fd, file_size;
|
int fd;
|
||||||
fd = rb->open(file, O_RDONLY);
|
fd = rb->open(file, O_RDONLY);
|
||||||
if (fd==-1)
|
if (fd==-1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
file_size = rb->filesize(fd);
|
init_grid(pgrid);
|
||||||
if (file_size==-1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
char buf1[file_size];
|
char c;
|
||||||
int i, j, k, xmid, ymid;
|
int nc, x, y, xmid, ymid;
|
||||||
j=0;
|
x=0;
|
||||||
k=0;
|
y=0;
|
||||||
xmid = (LCD_WIDTH>>1) - 2;
|
xmid = (GRID_W>>1) - 2;
|
||||||
ymid = (LCD_HEIGHT>>1) - 2;
|
ymid = (GRID_H>>1) - 2;
|
||||||
|
|
||||||
rb->read(fd, buf1, file_size - 1);
|
while (true) {
|
||||||
|
nc = read(fd, &c, 1);
|
||||||
|
if (nc <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
for(i=0; i<file_size; i++){
|
switch(c) {
|
||||||
|
|
||||||
switch(buf1[i]){
|
|
||||||
case '.':
|
case '.':
|
||||||
j++;
|
x++;
|
||||||
break;
|
break;
|
||||||
case 'O':
|
case 'O':
|
||||||
set_cell(xmid + j, ymid + k, pgrid);
|
if (is_valid_cell(xmid + x, ymid + y))
|
||||||
j++;
|
set_cell(xmid + x, ymid + y, pgrid);
|
||||||
|
x++;
|
||||||
break;
|
break;
|
||||||
case '\n':
|
case '\n':
|
||||||
k++;
|
y++;
|
||||||
j=0;
|
x=0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
@ -151,7 +172,7 @@ static void setup_grid(char *pgrid, int pattern){
|
||||||
int n, max;
|
int n, max;
|
||||||
int xmid, ymid;
|
int xmid, ymid;
|
||||||
|
|
||||||
max = LCD_HEIGHT*LCD_WIDTH;
|
max = GRID_W * GRID_H;
|
||||||
|
|
||||||
switch(pattern){
|
switch(pattern){
|
||||||
case PATTERN_RANDOM:
|
case PATTERN_RANDOM:
|
||||||
|
|
@ -174,8 +195,8 @@ static void setup_grid(char *pgrid, int pattern){
|
||||||
|
|
||||||
case PATTERN_GROWTH_1:
|
case PATTERN_GROWTH_1:
|
||||||
rb->splash(HZ, "Growth");
|
rb->splash(HZ, "Growth");
|
||||||
xmid = (LCD_WIDTH>>1) - 2;
|
xmid = (GRID_W>>1) - 2;
|
||||||
ymid = (LCD_HEIGHT>>1) - 2;
|
ymid = (GRID_H>>1) - 2;
|
||||||
set_cell(xmid + 6, ymid + 0 , pgrid);
|
set_cell(xmid + 6, ymid + 0 , pgrid);
|
||||||
set_cell(xmid + 4, ymid + 1 , pgrid);
|
set_cell(xmid + 4, ymid + 1 , pgrid);
|
||||||
set_cell(xmid + 6, ymid + 1 , pgrid);
|
set_cell(xmid + 6, ymid + 1 , pgrid);
|
||||||
|
|
@ -189,8 +210,8 @@ static void setup_grid(char *pgrid, int pattern){
|
||||||
break;
|
break;
|
||||||
case PATTERN_ACORN:
|
case PATTERN_ACORN:
|
||||||
rb->splash(HZ, "Acorn");
|
rb->splash(HZ, "Acorn");
|
||||||
xmid = (LCD_WIDTH>>1) - 3;
|
xmid = (GRID_W>>1) - 3;
|
||||||
ymid = (LCD_HEIGHT>>1) - 1;
|
ymid = (GRID_H>>1) - 1;
|
||||||
set_cell(xmid + 1, ymid + 0 , pgrid);
|
set_cell(xmid + 1, ymid + 0 , pgrid);
|
||||||
set_cell(xmid + 3, ymid + 1 , pgrid);
|
set_cell(xmid + 3, ymid + 1 , pgrid);
|
||||||
set_cell(xmid + 0, ymid + 2 , pgrid);
|
set_cell(xmid + 0, ymid + 2 , pgrid);
|
||||||
|
|
@ -201,8 +222,8 @@ static void setup_grid(char *pgrid, int pattern){
|
||||||
break;
|
break;
|
||||||
case PATTERN_GROWTH_2:
|
case PATTERN_GROWTH_2:
|
||||||
rb->splash(HZ, "Growth 2");
|
rb->splash(HZ, "Growth 2");
|
||||||
xmid = (LCD_WIDTH>>1) - 4;
|
xmid = (GRID_W>>1) - 4;
|
||||||
ymid = (LCD_HEIGHT>>1) - 1;
|
ymid = (GRID_H>>1) - 1;
|
||||||
set_cell(xmid + 0, ymid + 0 , pgrid);
|
set_cell(xmid + 0, ymid + 0 , pgrid);
|
||||||
set_cell(xmid + 1, ymid + 0 , pgrid);
|
set_cell(xmid + 1, ymid + 0 , pgrid);
|
||||||
set_cell(xmid + 2, ymid + 0 , pgrid);
|
set_cell(xmid + 2, ymid + 0 , pgrid);
|
||||||
|
|
@ -262,14 +283,12 @@ static void setup_grid(char *pgrid, int pattern){
|
||||||
/* display grid */
|
/* display grid */
|
||||||
static void show_grid(char *pgrid){
|
static void show_grid(char *pgrid){
|
||||||
int x, y;
|
int x, y;
|
||||||
int m;
|
|
||||||
unsigned char age;
|
unsigned char age;
|
||||||
|
|
||||||
rb->lcd_clear_display();
|
rb->lcd_clear_display();
|
||||||
for(y=0; y<LCD_HEIGHT; y++){
|
for(y=0; y<GRID_H; y++){
|
||||||
for(x=0; x<LCD_WIDTH; x++){
|
for(x=0; x<GRID_W; x++){
|
||||||
m = y*LCD_WIDTH+x;
|
age = get_cell(x, y, pgrid);
|
||||||
age = pgrid[m];
|
|
||||||
if(age){
|
if(age){
|
||||||
#if LCD_DEPTH >= 16
|
#if LCD_DEPTH >= 16
|
||||||
rb->lcd_set_foreground( LCD_RGBPACK( age, age, age ));
|
rb->lcd_set_foreground( LCD_RGBPACK( age, age, age ));
|
||||||
|
|
@ -291,11 +310,18 @@ static void show_grid(char *pgrid){
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* check state of cell depending on the number of neighbours */
|
/* Calculates whether the cell will be alive in the next generation.
|
||||||
static inline int check_cell(unsigned char *n){
|
n is the array with 9 elements that represent the cell itself and its
|
||||||
int sum;
|
neighborhood like this (the cell itself is n[4]):
|
||||||
|
0 1 2
|
||||||
|
3 4 5
|
||||||
|
6 7 8
|
||||||
|
*/
|
||||||
|
static inline bool check_cell(unsigned char *n)
|
||||||
|
{
|
||||||
int empty_cells = 0;
|
int empty_cells = 0;
|
||||||
unsigned char live = 0;
|
int alive_cells;
|
||||||
|
bool result;
|
||||||
|
|
||||||
/* count empty neighbour cells */
|
/* count empty neighbour cells */
|
||||||
if(n[0]==0) empty_cells++;
|
if(n[0]==0) empty_cells++;
|
||||||
|
|
@ -308,38 +334,32 @@ static inline int check_cell(unsigned char *n){
|
||||||
if(n[8]==0) empty_cells++;
|
if(n[8]==0) empty_cells++;
|
||||||
|
|
||||||
/* now we build the number of non-zero neighbours :-P */
|
/* now we build the number of non-zero neighbours :-P */
|
||||||
sum = 8 - empty_cells;
|
alive_cells = 8 - empty_cells;
|
||||||
|
|
||||||
/* 1st and 2nd rule*/
|
if (n[4]) {
|
||||||
if (n[4] && (sum<2 || sum>3))
|
/* If the cell is alive, it stays alive iff it has 2 or 3 alive neighbours */
|
||||||
live = false;
|
result = (alive_cells==2 || alive_cells==3);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* If the cell is dead, it gets alive iff it has 3 alive neighbours */
|
||||||
|
result = (alive_cells==3);
|
||||||
|
}
|
||||||
|
|
||||||
/* 3rd rule */
|
return result;
|
||||||
if (n[4] && (sum==2 || sum==3))
|
|
||||||
live = true;
|
|
||||||
|
|
||||||
/* 4rd rule */
|
|
||||||
if (!n[4] && sum==3)
|
|
||||||
live = true;
|
|
||||||
|
|
||||||
return live;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate the next generation of cells
|
/* Calculate the next generation of cells
|
||||||
*
|
*
|
||||||
* The borders of the grid are connected to their opposite sides.
|
* The borders of the grid are connected to their opposite sides.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* To avoid multiplications while accessing data in the 2-d grid
|
* To avoid multiplications while accessing data in the 2-d grid
|
||||||
* (pgrid) we try to re-use previously accessed neighbourhood
|
* (pgrid) we try to re-use previously accessed neighbourhood
|
||||||
* information which is stored in an 3x3 array.
|
* information which is stored in an 3x3 array.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
static void next_generation(char *pgrid, char *pnext_grid){
|
static void next_generation(char *pgrid, char *pnext_grid){
|
||||||
int x, y;
|
int x, y;
|
||||||
unsigned char cell;
|
bool cell;
|
||||||
int age;
|
unsigned char age;
|
||||||
int m;
|
|
||||||
unsigned char n[9];
|
unsigned char n[9];
|
||||||
|
|
||||||
rb->memset(n, 0, sizeof(n));
|
rb->memset(n, 0, sizeof(n));
|
||||||
|
|
@ -357,31 +377,33 @@ static void next_generation(char *pgrid, char *pnext_grid){
|
||||||
population = 0;
|
population = 0;
|
||||||
|
|
||||||
/* go through the grid */
|
/* go through the grid */
|
||||||
for(y=0; y<LCD_HEIGHT; y++){
|
for(y=0; y<GRID_H; y++){
|
||||||
for(x=0; x<LCD_WIDTH; x++){
|
for(x=0; x<GRID_W; x++){
|
||||||
if(y==0 && x==0){
|
if(y==0 && x==0){
|
||||||
/* first cell in first row, we have to load all neighbours */
|
/* first cell in first row, we have to load all neighbours */
|
||||||
n[0] = pgrid[((x+LCD_WIDTH-1)%LCD_WIDTH)+((y+LCD_HEIGHT-1)%LCD_HEIGHT)*LCD_WIDTH];
|
n[0] = get_cell(x-1, y-1, pgrid);
|
||||||
n[1] = pgrid[((x )%LCD_WIDTH)+((y+LCD_HEIGHT-1)%LCD_HEIGHT)*LCD_WIDTH];
|
n[1] = get_cell(x, y-1, pgrid);
|
||||||
n[2] = pgrid[((x +1)%LCD_WIDTH)+((y+LCD_HEIGHT-1)%LCD_HEIGHT)*LCD_WIDTH];
|
n[2] = get_cell(x+1, y-1, pgrid);
|
||||||
n[3] = pgrid[((x+LCD_WIDTH-1)%LCD_WIDTH)+((y )%LCD_HEIGHT)*LCD_WIDTH];
|
n[3] = get_cell(x-1, y, pgrid);
|
||||||
n[5] = pgrid[((x +1)%LCD_WIDTH)+((y )%LCD_HEIGHT)*LCD_WIDTH];
|
n[4] = get_cell(x, y, pgrid);
|
||||||
n[6] = pgrid[((x+LCD_WIDTH-1)%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH];
|
n[5] = get_cell(x+1, y, pgrid);
|
||||||
n[7] = pgrid[((x )%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH];
|
n[6] = get_cell(x-1, y+1, pgrid);
|
||||||
n[8] = pgrid[((x +1)%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH];
|
n[7] = get_cell(x, y+1, pgrid);
|
||||||
|
n[8] = get_cell(x+1, y+1, pgrid);
|
||||||
} else {
|
} else {
|
||||||
if(x==0){
|
if(x==0){
|
||||||
/* beginning of a row, copy what we know about our predecessor,
|
/* beginning of a row, copy what we know about our predecessor,
|
||||||
0, 1, 3 are known, 2, 5, 6, 7, 8 have to be loaded
|
0, 1, 3, 4 are known, 2, 5, 6, 7, 8 have to be loaded
|
||||||
*/
|
*/
|
||||||
n[0] = n[4];
|
n[0] = n[4];
|
||||||
n[1] = n[5];
|
n[1] = n[5];
|
||||||
n[2] = pgrid[((x +1)%LCD_WIDTH)+((y+LCD_HEIGHT-1)%LCD_HEIGHT)*LCD_WIDTH];
|
n[2] = get_cell(x+1, y-1, pgrid);
|
||||||
n[3] = n[7];
|
n[3] = n[7];
|
||||||
n[5] = pgrid[((x +1)%LCD_WIDTH)+((y )%LCD_HEIGHT)*LCD_WIDTH];
|
n[4] = n[8];
|
||||||
n[6] = pgrid[((x+LCD_WIDTH-1)%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH];
|
n[5] = get_cell(x+1, y, pgrid);
|
||||||
n[7] = pgrid[((x )%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH];
|
n[6] = get_cell(x-1, y+1, pgrid);
|
||||||
n[8] = pgrid[((x +1)%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH];
|
n[7] = get_cell(x, y+1, pgrid);
|
||||||
|
n[8] = get_cell(x+1, y+1, pgrid);
|
||||||
} else {
|
} else {
|
||||||
/* we are moving right in a row,
|
/* we are moving right in a row,
|
||||||
* copy what we know about the neighbours on our left side,
|
* copy what we know about the neighbours on our left side,
|
||||||
|
|
@ -389,19 +411,17 @@ static void next_generation(char *pgrid, char *pnext_grid){
|
||||||
*/
|
*/
|
||||||
n[0] = n[1];
|
n[0] = n[1];
|
||||||
n[1] = n[2];
|
n[1] = n[2];
|
||||||
n[2] = pgrid[((x +1)%LCD_WIDTH)+((y+LCD_HEIGHT-1)%LCD_HEIGHT)*LCD_WIDTH];
|
n[2] = get_cell(x+1, y-1, pgrid);
|
||||||
n[3] = n[4];
|
n[3] = n[4];
|
||||||
n[5] = pgrid[((x +1)%LCD_WIDTH)+((y )%LCD_HEIGHT)*LCD_WIDTH];
|
n[4] = n[5];
|
||||||
|
n[5] = get_cell(x+1, y, pgrid);
|
||||||
n[6] = n[7];
|
n[6] = n[7];
|
||||||
n[7] = n[8];
|
n[7] = n[8];
|
||||||
n[8] = pgrid[((x +1)%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH];
|
n[8] = get_cell(x+1, y+1, pgrid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m = x+y*LCD_WIDTH;
|
|
||||||
|
|
||||||
/* how old is our cell? */
|
/* how old is our cell? */
|
||||||
n[4] = pgrid[m];
|
|
||||||
age = n[4];
|
age = n[4];
|
||||||
|
|
||||||
/* calculate the cell based on given neighbour information */
|
/* calculate the cell based on given neighbour information */
|
||||||
|
|
@ -411,14 +431,12 @@ static void next_generation(char *pgrid, char *pnext_grid){
|
||||||
if(cell){
|
if(cell){
|
||||||
population++;
|
population++;
|
||||||
/* prevent overflow */
|
/* prevent overflow */
|
||||||
if(age>252){
|
if(age<252)
|
||||||
pnext_grid[m] = 252;
|
age++;
|
||||||
} else {
|
set_cell_age(x, y, age, pnext_grid);
|
||||||
pnext_grid[m] = age + 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
pnext_grid[m] = 0;
|
set_cell_age(x, y, 0, pnext_grid);
|
||||||
#if 0
|
#if 0
|
||||||
DEBUGF("x=%d,y=%d\n", x, y);
|
DEBUGF("x=%d,y=%d\n", x, y);
|
||||||
DEBUGF("cell: %d\n", cell);
|
DEBUGF("cell: %d\n", cell);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue