From be302df582b43e5aee7518dd6603348053289f85 Mon Sep 17 00:00:00 2001 From: Huck Boles Date: Sun, 22 Jan 2023 13:02:01 -0600 Subject: [PATCH] resizable unicode --- .gitignore | 2 + src/function.c | 72 ++++++++++++++++++++++++ src/gol.c | 46 +++++++++++++++ src/gol.h | 50 +++++++++++++++++ src/map.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++ src/struct.c | 23 ++++++++ test/errortest.c | 6 ++ test/helptest.c | 5 ++ 8 files changed, 347 insertions(+) create mode 100644 src/function.c create mode 100644 src/gol.c create mode 100644 src/gol.h create mode 100644 src/map.c create mode 100644 src/struct.c create mode 100644 test/errortest.c create mode 100644 test/helptest.c diff --git a/.gitignore b/.gitignore index 291983f..5a1b38f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,7 @@ !README !LICENSE !Makefile +!src/ +!test/ !*.c !*.h diff --git a/src/function.c b/src/function.c new file mode 100644 index 0000000..8b867dd --- /dev/null +++ b/src/function.c @@ -0,0 +1,72 @@ +#include "gol.h" + + +extern int row,col,step,ascii,color,weight; + +void parseopts(int n, char **args){ + char c; + while ((c = getopt(n,args,"hVacy:x:t:w:")) != -1){ + switch (c) { + case 'h': + help(); + break; + case 'V': + printf("v%s\n",VERSION); + exit(0); + break; + case 'x': + col = strtol(optarg,NULL,10); + break; + case 'y': + row = strtol(optarg,NULL,10); + break; + case 't': + step = strtol(optarg,NULL,10); + break; + case 'w': + weight = strtol(optarg,NULL,10); + break; + case 'a': + ascii = 1; + break; + case '?': + fprintf(stderr, "\t%s\n",optarg); + errorcheck(FLAG_ERR); + break; + } + } + + return; +} + +void errorcheck(int err){ + if (errno != 0) { + fprintf(stderr,"\nERROR: %s\n",strerror(errno)); + exit(EXIT_FAILURE); + } + + if (err == NO_ERR) { return; } + + if ((err & FLAG_ERR) != 0) { + fprintf(stderr,"ERROR: Unknown Flag\n"); + printf("Use -h for help"); + } + + if ((err & STATE_ERR) != 0) { fprintf(stderr,"ERROR: Could not determine cell state\n"); } + + exit(err); +} + +void help(){ + printf("Usage:\n"); + printf("\tgol [OPTIONS]"); + printf("Option flags:\n"); + printf("\t-x [INT]\tnumber of columns, default: 90\n"); + printf("\t-y [INT]\tnumber of rows, default: 30\n"); + printf("\t-a \tascii only mode\n"); + printf("\t-t [ms]\tamount of time to wait in ms between generations, default: 75000\n"); + printf("\t-V\tversion information\n"); + printf("\t-h\tshow this help\n"); + + exit(0); +} diff --git a/src/gol.c b/src/gol.c new file mode 100644 index 0000000..093a368 --- /dev/null +++ b/src/gol.c @@ -0,0 +1,46 @@ +#include "gol.h" + +int row,col,step,ascii,weight; + +int main(int argc, char *argv[]){ + srand(time(NULL)); + + int stop = 1; + row = 30; + col = 90; + step = 75000; + ascii = 0; + weight = 5; + + parseopts(argc,argv); + + struct map map = newmap(); + genmap(map); + + while (stop > 0){ + stop = updatemap(map); + printdisplay(map); + usleep(step); + } + + freemap(map); + + return 0; +} + + +void printdisplay(struct map map){ + printf("%s",CLEAR); + for (int r = 0; r < row; r++){ + for (int c = 0; c < col; c++){ + if (ascii == 0){ + printf("%4s",map.line[r].cell[c].pixel); + } else { + printf("%c",map.line[r].cell[c].cellchar); + } + } + putc('\n',stdout); + } + + return; +} diff --git a/src/gol.h b/src/gol.h new file mode 100644 index 0000000..517b808 --- /dev/null +++ b/src/gol.h @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAXLINE 10000 +#define VERSION "0.2.1" + +#define CLEAR "\e[1;1H\e[2J" + +enum {DIE = -1, DEAD = 0, ALIVE = 1, SPAWN = 1 << 1}; + +/* error codes */ +enum {NO_ERR = 0, FLAG_ERR = 1, STATE_ERR = 1 << 1, COLOR_ERR = 1 << 2}; + +struct cell { + char pixel[4]; + char cellchar; + int state; +}; + +struct line { + struct cell *cell; +}; + +struct map { + struct line *line; +}; + +/* main.c */ +void errorcheck(int); +void parseopts(int,char **); +void help(void); +void printdisplay(struct map); + +/* map.c */ +void genmap(struct map); +int updatemap(struct map); +int numneighbor(struct map,int,int); +int checkstate(struct map,int,int); +char statechar(int); +char *statecell(int); + +/* struct.c */ +struct map newmap(void); +void freemap(struct map); diff --git a/src/map.c b/src/map.c new file mode 100644 index 0000000..0e81cef --- /dev/null +++ b/src/map.c @@ -0,0 +1,143 @@ +#include "gol.h" + +extern int row,col,weight; + +void genmap(struct map map){ + int rnd = 0; + for (int r = 0; r < row; r++){ + for (int c = 0; c < col; c++){ + rnd = rand(); + if (rnd % weight == 0){ + map.line[r].cell[c].state = ALIVE; + } else { + map.line[r].cell[c].state = DEAD; + } + } + } + return; +} + +int updatemap(struct map map){ + int n = 0; + struct map tmp = newmap(); + + for (int r = 1; r < row-1; r++){ + for(int c = 1; c < col-1; c++){ + int state = checkstate(map,r,c); + tmp.line[r].cell[c].state = state; + tmp.line[r].cell[c].cellchar = statechar(state); + strncpy(tmp.line[r].cell[c].pixel,statecell(state),4); + if (state > DEAD){ n++; } + } + } + + for(int r = 0; r < row; r++){ + for (int c = 0; c < col; c++){ + map.line[r].cell[c] = tmp.line[r].cell[c]; + } + } + + return n; +} + +int checkstate(struct map map,int r, int c){ + int state = 0; + int n = numneighbor(map, r, c); + + if (map.line[r].cell[c].state < ALIVE) { + if (n == 3) { + state = SPAWN; + } else { + state = DEAD; + } + } else { + if (n > 1 && n < 4) { + state = ALIVE; + } else { + state = DIE; + } + } + + return state; +} + +char statechar(int state){ + switch (state) { + case (DIE): return ' '; + case (SPAWN): return '#'; + case (ALIVE): return '#'; + case (DEAD): return ' '; + default: + errorcheck(STATE_ERR); + return 'E'; + } +} + +char *statecell(int state){ + switch (state) { + case (DIE): return "\u25CC"; + case (SPAWN): return "\u25CB"; + case (ALIVE): return "\u25EF"; + case (DEAD): return "\u2002"; + default: + errorcheck(STATE_ERR); + return "X"; + } +} + + +int numneighbor(struct map map, int r, int c){ + int n = 0; + /* non-edges */ + if (r > 0 && r < row - 1 && c > 0 && c < col - 1){ + if (map.line[r+1].cell[c+1].state > DEAD) n ++; + if (map.line[r].cell[c+1].state > DEAD) n ++; + if (map.line[r-1].cell[c+1].state > DEAD) n ++; + if (map.line[r+1].cell[c].state > DEAD) n ++; + if (map.line[r-1].cell[c].state > DEAD) n ++; + if (map.line[r+1].cell[c-1].state > DEAD) n ++; + if (map.line[r].cell[c-1].state > DEAD) n ++; + if (map.line[r-1].cell[c-1].state > DEAD) n ++; + /* top row */ + } else if (r == 0 && c > 0 && c < col){ + if (map.line[r+1].cell[c+1].state > DEAD) n ++; + if (map.line[r].cell[c+1].state > DEAD) n ++; + if (map.line[row-1].cell[c+1].state > DEAD) n ++; + if (map.line[r+1].cell[c].state > DEAD) n ++; + if (map.line[row-1].cell[c].state > DEAD) n ++; + if (map.line[r+1].cell[c-1].state > DEAD) n ++; + if (map.line[r].cell[c-1].state > DEAD) n ++; + if (map.line[row-1].cell[c-1].state > DEAD) n ++; + /* bottom row */ + } else if (r == row - 1 && c > 0 && c < col){ + if (map.line[0].cell[c+1].state > DEAD) n ++; + if (map.line[r].cell[c+1].state > DEAD) n ++; + if (map.line[r-1].cell[c+1].state > DEAD) n ++; + if (map.line[0].cell[c].state > DEAD) n ++; + if (map.line[r-1].cell[c].state > DEAD) n ++; + if (map.line[0].cell[c-1].state > DEAD) n ++; + if (map.line[r].cell[c-1].state > DEAD) n ++; + if (map.line[r-1].cell[c-1].state > DEAD) n ++; + /* left side */ + } else if (r > 0 && r < row && c == 0){ + if (map.line[r+1].cell[c+1].state > DEAD) n ++; + if (map.line[r].cell[c+1].state > DEAD) n ++; + if (map.line[r-1].cell[c+1].state > DEAD) n ++; + if (map.line[r+1].cell[c].state > DEAD) n ++; + if (map.line[r-1].cell[c].state > DEAD) n ++; + if (map.line[r+1].cell[col-1].state > DEAD) n ++; + if (map.line[r].cell[col-1].state > DEAD) n ++; + if (map.line[r-1].cell[col-1].state > DEAD) n ++; + /* right side */ + } else if (r > 0 && r < row && c == col - 1){ + if (map.line[r+1].cell[0].state > DEAD) n ++; + if (map.line[r].cell[0].state > DEAD) n ++; + if (map.line[r-1].cell[0].state > DEAD) n ++; + if (map.line[r+1].cell[c].state > DEAD) n ++; + if (map.line[r-1].cell[c].state > DEAD) n ++; + if (map.line[r+1].cell[c-1].state > DEAD) n ++; + if (map.line[r].cell[c-1].state > DEAD) n ++; + if (map.line[r-1].cell[c-1].state > DEAD) n ++; + } + return n; +} diff --git a/src/struct.c b/src/struct.c new file mode 100644 index 0000000..213b4bf --- /dev/null +++ b/src/struct.c @@ -0,0 +1,23 @@ +#include "gol.h" + +extern int row,col; + +struct map newmap(void){ + struct map tmp; + tmp.line = malloc(row*col*sizeof(struct cell)); + for (int r = 0; r < row; r++){ + tmp.line[r].cell = malloc(sizeof(struct cell)*col); + } + return tmp; +} + + +void freemap(struct map map){ + for (int r = 0; r < row; r++){ + for (int c = 0; c < col; c++){ + free(map.line[r].cell); + } + } + free(map.line); + return; +} diff --git a/test/errortest.c b/test/errortest.c new file mode 100644 index 0000000..aa3500e --- /dev/null +++ b/test/errortest.c @@ -0,0 +1,6 @@ +#include "gol.h" + +int main(int argc, char **argv){ + errorcheck(NO_ERROR); + errorcheck(FLAG_ERROR); +} diff --git a/test/helptest.c b/test/helptest.c new file mode 100644 index 0000000..7495e93 --- /dev/null +++ b/test/helptest.c @@ -0,0 +1,5 @@ +#includ "gol.h" + +int main(int argc, char **argv){ + help(); +} -- 2.45.2