Skip to content

Commit

Permalink
add readme
Browse files Browse the repository at this point in the history
  • Loading branch information
qnkhuat committed Dec 31, 2020
1 parent 3b9a003 commit 617bd95
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 41 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
*.swp
*.swo

voila.c

# open sources
repos

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
lifeterm: lifeterm.c
$(CC) lifeterm.c -g -o lifeterm.out -Wall -Wextra -pedantic -std=c99
$(CC) lifeterm.c -g -o lifeterm -Wall -Wextra -pedantic -std=c99

38 changes: 29 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,33 @@
# Conway game of life editor on terminal
# LifeTerm
Game of life editor right on your terminal because who is web browser or app these days? 🤷

### TO DO:
- [x] Prune the current voila.c
- [ ] Convert voila to draw form a matrix
- [ ] Press space to change state of a matrix
- [ ] Update rules
- [ ] Control buttons : p-play/pause. n-next. r-reload. q-quit
This is completely work in progress there are tons of thing to improve.
![](./assets/earther.png)

# How to
### RUN
> The grid is based on the screen of your terminal, so make sure you larger your screen before run
`./lifeterm`

### Keymap
| Key | Description |
|----------|---------------------------|
| w, a, s, d | Game style: move one step |
| W, A, S, D | Game style: move 10 steps |
| h, j, k, l | Vim style: move on step |
| H, J, K, L | Vim style: move on step |
| Arrows | Move on step |
| x, space | Spawn/Kill a cell |
| u, n | Next generation |
| r, R | Refresh |
| q | Quit |

### Additional features
- [ ] Load saved game from file csv?
### Font
For the best experience, Use the font [square](/assets/square.ttf) on your terminal, It has square cells.

It's the current limitation of this program since it's a text editor base.

# Todo
- [ ] Square grid cell
- [ ] Add load/save game
- [ ] Infinite grid / Dynamic size grid
Binary file added assets/earther.mov
Binary file not shown.
Binary file added assets/earther.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added lifeterm
Binary file not shown.
160 changes: 131 additions & 29 deletions lifeterm.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@

#define CTRL_KEY(k) ((k) & 0x1f) // & in this line is bitwise-AND operator


/*** Prototypes ***/

void editorRefreshScreen();

enum editorKey {
ARROW_LEFT = 1000,
ARROW_RIGHT, // = 1001 by convention
Expand All @@ -21,14 +26,22 @@ enum editorKey {
A_UPPER,
D_UPPER,
W_UPPER,
S_UPPER
S_UPPER,
STEP,
PLAY,
MARK,
ERASE,
QUIT
};

/*** data ***/
struct editorConfig {
int cx, cy;
int screenrows;
int screencols;
int gridrows;
int gridcols;
int playing;
int **grid;
struct termios orig_termios;
};
Expand Down Expand Up @@ -100,6 +113,11 @@ int editorReadKey() {
case 'A': return A_UPPER;
case 'S': return S_UPPER;
case 'D': return D_UPPER;
case 'K': return W_UPPER;
case 'H': return A_UPPER;
case 'J': return S_UPPER;
case 'L': return D_UPPER;

case 'w': return ARROW_UP;
case 'a': return ARROW_LEFT;
case 's': return ARROW_DOWN;
Expand All @@ -108,10 +126,19 @@ int editorReadKey() {
case 'h': return ARROW_LEFT;
case 'j': return ARROW_DOWN;
case 'l': return ARROW_RIGHT;
case 'K': return W_UPPER;
case 'H': return A_UPPER;
case 'J': return S_UPPER;
case 'L': return D_UPPER;


case ' ':
case 'x':
return MARK;

case 'n':
case 'u': return STEP;
//case 'p': return PLAY;
case 'r': return ERASE;

case 'Q':
case 'q': return QUIT;
}

if (c == '\x1b') {
Expand Down Expand Up @@ -192,6 +219,69 @@ void abFree(struct abuf *ab){
free(ab->b);
}

/*** grid operations ***/
void gridMark(){
E.grid[E.cy][E.cx] ^= 1;
}

void gridErase(){
// TODO : use memset to set values not for loop
for (int row = 0; row < E.gridrows; row++){
for (int col = 0; col < E.gridcols; col++){
E.grid[row][col] = 0;
}
}
}

void gridUpdate(){
/***
* 1. Any live cell with fewer than two live neighbours dies, as if by underpopulation.
* 2. Any live cell with two or three live neighbours lives on to the next generation.
* 3. Any live cell with more than three live neighbours dies, as if by overpopulation.
* 4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
***/
// TODO: optimize this to not use 2 fors
int tempGrid[E.gridrows][E.gridcols];
for (int row = 0; row < E.gridrows; row++){
for (int col = 0; col < E.gridcols; col++){
tempGrid[row][col] = E.grid[row][col];
}
}


// TODO: fix to handle case at edges
for (int col = 1; col < E.gridcols-1; col++){
for (int row = 1; row < E.gridrows-1; row++){
int count = tempGrid[row - 1][col - 1] + \
tempGrid[row - 1][col] + \
tempGrid[row - 1][col + 1] + \
tempGrid[row][col - 1] + \
tempGrid[row][col + 1] + \
tempGrid[row + 1][col - 1] + \
tempGrid[row + 1][col] + \
tempGrid[row + 1][col + 1];
if(count< 2)
E.grid[row][col] = 0;
else if(count == 3)
E.grid[row][col] = 1;
else if(count > 3)
E.grid[row][col] = 0;
}
}
}


void gridPlay(){
while(1){
int c = editorReadKey();
if (c == PLAY){
gridUpdate();
editorRefreshScreen();
//sleep(0.1);
break;
}
}
}

/*** input ***/

Expand All @@ -207,7 +297,7 @@ void editorMoveCursor(int key){
if(E.cy!=0) E.cy--;
break;
case ARROW_DOWN:
if (E.cy != E.screenrows-1) E.cy++;
if (E.cy != E.gridrows-1) E.cy++;
break;
case A_UPPER:
if (E.cx -10 <= 0) E.cx = 0;
Expand All @@ -222,7 +312,7 @@ void editorMoveCursor(int key){
else E.cy-=10;
break;
case S_UPPER:
if (E.cy + 10 >= E.screenrows) E.cy = E.screenrows-1;
if (E.cy + 10 >= E.screenrows) E.cy = E.gridrows-1;
else E.cy+=10;
break;
}
Expand All @@ -232,10 +322,14 @@ void editorProcessKeypress(){
int c = editorReadKey();

switch(c){
case QUIT:
case CTRL_KEY('q'):
clearScreen();
exit(0);
break;
case ERASE:
gridErase();
break;
case ARROW_LEFT:
case ARROW_RIGHT:
case ARROW_UP:
Expand All @@ -246,6 +340,18 @@ void editorProcessKeypress(){
case D_UPPER:
editorMoveCursor(c);
break;

case MARK:
gridMark();
break;
case STEP:
gridUpdate();
break;

case PLAY:
gridPlay();
break;

}

}
Expand All @@ -265,23 +371,11 @@ void editorDrawWelcomeMsg(struct abuf *ab){
abAppend(ab, welcome, welcomelen); // say welcome to users
}

//void editorDrawRows(struct abuf *ab){
// for(int y=0; y < E.screenrows; y++){
// if (y==E.screenrows / 3)
// editorDrawWelcomeMsg(ab);
// else{
// abAppend(ab, "~", 1);
// }
// abAppend(ab, "\x1b[K", 3); // clear the current line
// if (y < E.screenrows) abAppend(ab, "\r\n", 2);
// }
//}

void editorDrawStatusBar(struct abuf *ab) {
abAppend(ab, "\x1b[7m", 4);// switch to inverted color
char status[120], rstatus[120];

int len = snprintf(status, sizeof(status), "This is the status bar");
int len = snprintf(status, sizeof(status), "press q to quit --- wasd|hjkl|ARROWS to navigate (upper case to move faster) --- x|space to mark --- u|n to update");
int rlen = snprintf(rstatus, sizeof(rstatus), "%d-%d",E.cx + 1, E.cy + 1);
if (len > E.screencols) len = E.screencols;
abAppend(ab, status, len);
Expand All @@ -300,12 +394,15 @@ void editorDrawStatusBar(struct abuf *ab) {


void editorDrawGrid(struct abuf *ab) {
for (int row = 0; row < E.screenrows; row++){
for (int col = 0; col < E.screencols; col++){
E.grid[row][col] = 1;
char c[1] = {E.grid[row][col]}; // convert to char
abAppend(ab, E.grid[row][col], 1);
//printf("%s", c);
for (int row = 0; row < E.gridrows; row++){
for (int col = 0; col < E.gridcols; col++){
if (E.grid[row][col] == 1){
abAppend(ab, "\x1b[7m", 4);// switch to inverted color
abAppend(ab, " ", 1);
abAppend(ab, "\x1b[m", 3);// switch back to normal color
}
else
abAppend(ab, " ", 1);
}
abAppend(ab, "\r\n", 2);
}
Expand Down Expand Up @@ -337,12 +434,17 @@ void initEditor(){
if (getWindowSize(&E.screenrows, &E.screencols) == -1 ) die("WindowSize");
E.cx = 0;
E.cy = 0;
E.playing = 0;
E.gridrows = E.screenrows - 1; // status bar
E.gridcols = E.screencols;

// init grid
E.grid = malloc(E.screenrows * sizeof(int *));
for(int i = 0; i < E.screencols; i++) {
E.grid[i] = malloc(E.screencols * sizeof(int));
E.grid = malloc(E.gridrows* sizeof(int *));
for(int i = 0; i < E.gridcols; i++) {
E.grid[i] = malloc(E.gridcols* sizeof(int));
}

gridErase();

}

Expand Down
4 changes: 2 additions & 2 deletions run.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
make
clear
if [ $? -eq 0 ]; then ./lifeterm.out lifeterm.c; fi
make
if [ $? -eq 0 ]; then ./lifeterm; fi

0 comments on commit 617bd95

Please sign in to comment.