#include <curses.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#define EMPTY 0x32
#define ALIVE 0x42
#define BIRTH 0x62
#define DEATH 0x64
static char **local_screen;
static int cols, lines;
static unsigned int usec = 100000;
static WINDOW *this;
void alarm_handler(int);
void resize_array(int);
int main(int argc, char *argv[]) {
int i, j;
int ch;
char inputline[256];
FILE *stream;
signal(SIGWINCH, resize_array);
this = initscr();
noecho();
cols = COLS;
lines = LINES;
if((stream = fopen("life.txt", "r")) == NULL) {
perror("fopen()");
exit(1);
}
/* Get ready for calloc() and malloc() */
local_screen = calloc(cols, 4);
for(i = 0; i < cols; i++)
if((local_screen[i] = malloc(lines)) == NULL)
perror("malloc()");
for(j = 0; j < lines; j++) {
fgets(inputline, cols, stream);
for(i = 0; i < cols; i++) {
if(inputline[i] == '*') {
local_screen[i][j] = ALIVE;
mvaddch(j, i, '*');
}
else local_screen[i][j] = EMPTY;
}
}
fclose(stream);
refresh();
signal(SIGALRM, alarm_handler);
/* Event loop */
while(1) {
ch = getch();
switch(ch) {
case 0x72:
/* We need to start it running */
signal(SIGALRM, alarm_handler);
ualarm(usec, usec);
break;
case 0x73:
/* Need to stop execution */
signal(SIGALRM, SIG_IGN);
break;
case 0x2b:
/* Time to speed things up */
if(usec >= 10000) {
usec -= 5000;
}
ualarm(usec, usec);
break;
case 0x2d:
/* Slow down */
usec += 5000;
ualarm(usec, usec);
break;
case 0x71:
/* Time to quit */
clear();
endwin();
exit(0);
break;
}
}
clear();
endwin();
return 0;
}
void alarm_handler(int sig_num) {
int i, j;
int touching = 0;
for(j = 0; j < lines; j++) {
for(i = 0; i < cols; i++) {
if(((i - 1) > 0) && ((j - 1) > 0) && ((i + 1) < cols) &&
((j + 1) < lines)) {
/* We're in the middle. Check all around */
if(local_screen[i][j] == EMPTY) {
touching = 0;
if((local_screen[i - 1][j - 1] == ALIVE) ||
(local_screen[i - 1][j - 1] == DEATH)) touching++;
if((local_screen[i - 1][j] == ALIVE) ||
(local_screen[i - 1][j] == DEATH)) touching++;
if((local_screen[i - 1][j + 1] == ALIVE) ||
(local_screen[i - 1][j + 1] == DEATH)) touching++;
if((local_screen[i][j - 1] == ALIVE) ||
(local_screen[i][j - 1] == DEATH)) touching++;
if((local_screen[i][j + 1] == ALIVE) ||
(local_screen[i][j + 1] == DEATH)) touching++;
if((local_screen[i + 1][j - 1] == ALIVE) ||
(local_screen[i + 1][j - 1] == DEATH)) touching++;
if((local_screen[i + 1][j] == ALIVE) ||
(local_screen[i + 1][j] == DEATH)) touching++;
if((local_screen[i + 1][j + 1] == ALIVE) ||
(local_screen[i + 1][j + 1] == DEATH)) touching++;
/* Do we get an addition to the family? */
if(touching > 2) local_screen[i][j] = BIRTH;
}
else if(local_screen[i][j] == ALIVE) {
touching = 0;
if((local_screen[i - 1][j - 1] == ALIVE) ||
(local_screen[i - 1][j - 1] == DEATH)) touching++;
if((local_screen[i - 1][j] == ALIVE) ||
(local_screen[i - 1][j] == DEATH)) touching++;
if((local_screen[i - 1][j + 1] == ALIVE) ||
(local_screen[i - 1][j + 1] == DEATH)) touching++;
if((local_screen[i][j - 1] == ALIVE) ||
(local_screen[i][j - 1] == DEATH)) touching++;
if((local_screen[i][j + 1] == ALIVE) ||
(local_screen[i][j + 1] == DEATH)) touching++;
if((local_screen[i + 1][j - 1] == ALIVE) ||
(local_screen[i + 1][j - 1] == DEATH)) touching++;
if((local_screen[i + 1][j] == ALIVE) ||
(local_screen[i + 1][j] == DEATH)) touching++;
if((local_screen[i + 1][j + 1] == ALIVE) ||
(local_screen[i + 1][j + 1] == DEATH)) touching++;
/* Check if anyone is checking out */
if((touching < 2) || (touching > 3)) local_screen[i][j] = DEATH;
}
}
else if(((i - 1) < 0) && ((j - 1) < 0)) {
/* Upper left corner */
if(local_screen[i][j] == EMPTY) {
touching = 0;
if((local_screen[i][j + 1] == ALIVE) ||
(local_screen[i][j + 1] == DEATH)) touching++;
if((local_screen[i + 1][j] == ALIVE) ||
(local_screen[i + 1][j] == DEATH)) touching++;
if((local_screen[i + 1][j + 1] == ALIVE) ||
(local_screen[i + 1][j + 1] == DEATH)) touching++;
/* Do we get an addition to the family? */
if(touching > 2) local_screen[i][j] = BIRTH;
}
else if(local_screen[i][j] == ALIVE) {
touching = 0;
if((local_screen[i][j + 1] == ALIVE) ||
(local_screen[i][j + 1] == DEATH)) touching++;
if((local_screen[i + 1][j] == ALIVE) ||
(local_screen[i + 1][j] == DEATH)) touching++;
if((local_screen[i + 1][j + 1] == ALIVE) ||
(local_screen[i + 1][j + 1] == DEATH)) touching++;
/* Check if anyone is checking out */
if((touching < 2) || (touching > 3)) local_screen[i][j] = DEATH;
}
}
else if(((i - 1) < 0) && ((j + 1) >= lines)) {
/* Bottom left corner */
if(local_screen[i][j] == EMPTY) {
touching = 0;
if((local_screen[i][j - 1] == ALIVE) ||
(local_screen[i][j - 1] == DEATH)) touching++;
if((local_screen[i + 1][j - 1] == ALIVE) ||
(local_screen[i + 1][j - 1] == DEATH)) touching++;
if((local_screen[i + 1][j] == ALIVE) ||
(local_screen[i + 1][j] == DEATH)) touching++;
/* Do we get an addition to the family? */
if(touching > 2) local_screen[i][j] = BIRTH;
}
else if(local_screen[i][j] == ALIVE) {
touching = 0;
if((local_screen[i][j - 1] == ALIVE) ||
(local_screen[i][j - 1] == DEATH)) touching++;
if((local_screen[i + 1][j - 1] == ALIVE) ||
(local_screen[i + 1][j - 1] == DEATH)) touching++;
if((local_screen[i + 1][j] == ALIVE) ||
(local_screen[i + 1][j] == DEATH)) touching++;
/* Check if anyone is checking out */
if((touching < 2) || (touching > 3)) local_screen[i][j] = DEATH;
}
}
else if(((i + 1) >= cols) && ((j - 1) < 0)) {
/* Upper right corner */
if(local_screen[i][j] == EMPTY) {
touching = 0;
if((local_screen[i - 1][j] == ALIVE) ||
(local_screen[i - 1][j] == DEATH)) touching++;
if((local_screen[i - 1][j + 1] == ALIVE) ||
(local_screen[i - 1][j + 1] == DEATH)) touching++;
if((local_screen[i][j + 1] == ALIVE) ||
(local_screen[i][j + 1] == DEATH)) touching++;
/* Do we get an addition to the family? */
if(touching > 2) local_screen[i][j] = BIRTH;
}
else if(local_screen[i][j] == ALIVE) {
touching = 0;
if((local_screen[i - 1][j] == ALIVE) ||
(local_screen[i - 1][j] == DEATH)) touching++;
if((local_screen[i - 1][j + 1] == ALIVE) ||
(local_screen[i - 1][j + 1] == DEATH)) touching++;
if((local_screen[i][j + 1] == ALIVE) ||
(local_screen[i][j + 1] == DEATH)) touching++;
/* Check if anyone is checking out */
if((touching < 2) || (touching > 3)) local_screen[i][j] = DEATH;
}
}
else if(((i + 1) >= cols) && ((j + 1) >= lines)) {
/* Bottom right corner */
if(local_screen[i][j] == EMPTY) {
touching = 0;
if((local_screen[i - 1][j - 1] == ALIVE) ||
(local_screen[i - 1][j - 1] == DEATH)) touching++;
if((local_screen[i - 1][j] == ALIVE) ||
(local_screen[i - 1][j] == DEATH)) touching++;
if((local_screen[i][j - 1] == ALIVE) ||
(local_screen[i][j - 1] == DEATH)) touching++;
/* Do we get an addition to the family? */
if(touching > 2) local_screen[i][j] = BIRTH;
}
else if(local_screen[i][j] == ALIVE) {
touching = 0;
if((local_screen[i - 1][j - 1] == ALIVE) ||
(local_screen[i - 1][j - 1] == DEATH)) touching++;
if((local_screen[i - 1][j] == ALIVE) ||
(local_screen[i - 1][j] == DEATH)) touching++;
if((local_screen[i][j - 1] == ALIVE) ||
(local_screen[i][j - 1] == DEATH)) touching++;
/* Check if anyone is checking out */
if((touching < 2) || (touching > 3)) local_screen[i][j] = DEATH;
}
}
else if(((i - 1) < 0) && (!((j + 1) >= lines)) && (!((j - 1) < 0))) {
/* Left edge, not a corner */
if(local_screen[i][j] == EMPTY) {
touching = 0;
if((local_screen[i][j - 1] == ALIVE) ||
(local_screen[i][j - 1] == DEATH)) touching++;
if((local_screen[i][j + 1] == ALIVE) ||
(local_screen[i][j + 1] == DEATH)) touching++;
if((local_screen[i + 1][j - 1] == ALIVE) ||
(local_screen[i + 1][j - 1] == DEATH)) touching++;
if((local_screen[i + 1][j] == ALIVE) ||
(local_screen[i + 1][j] == DEATH)) touching++;
if((local_screen[i + 1][j + 1] == ALIVE) ||
(local_screen[i + 1][j + 1] == DEATH)) touching++;
/* Do we get an addition to the family? */
if(touching > 2) local_screen[i][j] = BIRTH;
}
else if(local_screen[i][j] == ALIVE) {
touching = 0;
if((local_screen[i][j - 1] == ALIVE) ||
(local_screen[i][j - 1] == DEATH)) touching++;
if((local_screen[i][j + 1] == ALIVE) ||
(local_screen[i][j + 1] == DEATH)) touching++;
if((local_screen[i + 1][j - 1] == ALIVE) ||
(local_screen[i + 1][j - 1] == DEATH)) touching++;
if((local_screen[i + 1][j] == ALIVE) ||
(local_screen[i + 1][j] == DEATH)) touching++;
if((local_screen[i + 1][j + 1] == ALIVE) ||
(local_screen[i + 1][j + 1] == DEATH)) touching++;
/* Check if anyone is checking out */
if((touching < 2) || (touching > 3)) local_screen[i][j] = DEATH;
}
}
else if(((i + 1) >= cols) && (!((j + 1) >= lines)) && (!((j - 1) < 0))) {
/* Right edge, not a corner */
if(local_screen[i][j] == EMPTY) {
touching = 0;
if((local_screen[i - 1][j - 1] == ALIVE) ||
(local_screen[i - 1][j - 1] == DEATH)) touching++;
if((local_screen[i - 1][j] == ALIVE) ||
(local_screen[i - 1][j] == DEATH)) touching++;
if((local_screen[i - 1][j + 1] == ALIVE) ||
(local_screen[i - 1][j + 1] == DEATH)) touching++;
if((local_screen[i][j - 1] == ALIVE) ||
(local_screen[i][j - 1] == DEATH)) touching++;
if((local_screen[i][j + 1] == ALIVE) ||
(local_screen[i][j + 1] == DEATH)) touching++;
/* Do we get an addition to the family? */
if(touching > 2) local_screen[i][j] = BIRTH;
}
else if(local_screen[i][j] == ALIVE) {
touching = 0;
if((local_screen[i - 1][j - 1] == ALIVE) ||
(local_screen[i - 1][j - 1] == DEATH)) touching++;
if((local_screen[i - 1][j] == ALIVE) ||
(local_screen[i - 1][j] == DEATH)) touching++;
if((local_screen[i - 1][j + 1] == ALIVE) ||
(local_screen[i - 1][j + 1] == DEATH)) touching++;
if((local_screen[i][j - 1] == ALIVE) ||
(local_screen[i][j - 1] == DEATH)) touching++;
if((local_screen[i][j + 1] == ALIVE) ||
(local_screen[i][j + 1] == DEATH)) touching++;
/* Check if anyone is checking out */
if((touching < 2) || (touching > 3)) local_screen[i][j] = DEATH;
}
}
else if(((j - 1) < 0) && (!((i + 1) >= cols)) && (!((i - 1) < 0))) {
/* Top edge, not a corner */
if(local_screen[i][j] == EMPTY) {
touching = 0;
if((local_screen[i - 1][j] == ALIVE) ||
(local_screen[i - 1][j] == DEATH)) touching++;
if((local_screen[i - 1][j + 1] == ALIVE) ||
(local_screen[i - 1][j + 1] == DEATH)) touching++;
if((local_screen[i][j + 1] == ALIVE) ||
(local_screen[i][j + 1] == DEATH)) touching++;
if((local_screen[i + 1][j] == ALIVE) ||
(local_screen[i + 1][j] == DEATH)) touching++;
if((local_screen[i + 1][j + 1] == ALIVE) ||
(local_screen[i + 1][j + 1] == DEATH)) touching++;
/* Do we get an addition to the family? */
if(touching > 2) local_screen[i][j] = BIRTH;
}
else if(local_screen[i][j] == ALIVE) {
touching = 0;
if((local_screen[i - 1][j] == ALIVE) ||
(local_screen[i - 1][j] == DEATH)) touching++;
if((local_screen[i - 1][j + 1] == ALIVE) ||
(local_screen[i - 1][j + 1] == DEATH)) touching++;
if((local_screen[i][j + 1] == ALIVE) ||
(local_screen[i][j + 1] == DEATH)) touching++;
if((local_screen[i + 1][j] == ALIVE) ||
(local_screen[i + 1][j] == DEATH)) touching++;
if((local_screen[i + 1][j + 1] == ALIVE) ||
(local_screen[i + 1][j + 1] == DEATH)) touching++;
/* Check if anyone is checking out */
if((touching < 2) || (touching > 3)) local_screen[i][j] = DEATH;
}
}
else {
/* Bottom edge, not a corner */
if(local_screen[i][j] == EMPTY) {
touching = 0;
if((local_screen[i - 1][j - 1] == ALIVE) ||
(local_screen[i - 1][j - 1] == DEATH)) touching++;
if((local_screen[i - 1][j] == ALIVE) ||
(local_screen[i - 1][j] == DEATH)) touching++;
if((local_screen[i][j - 1] == ALIVE) ||
(local_screen[i][j - 1] == DEATH)) touching++;
if((local_screen[i + 1][j - 1] == ALIVE) ||
(local_screen[i + 1][j - 1] == DEATH)) touching++;
if((local_screen[i + 1][j] == ALIVE) ||
(local_screen[i + 1][j] == DEATH)) touching++;
/* Do we get an addition to the family? */
if(touching > 2) local_screen[i][j] = BIRTH;
}
else if(local_screen[i][j] == ALIVE) {
touching = 0;
if((local_screen[i - 1][j - 1] == ALIVE) ||
(local_screen[i - 1][j - 1] == DEATH)) touching++;
if((local_screen[i - 1][j] == ALIVE) ||
(local_screen[i - 1][j] == DEATH)) touching++;
if((local_screen[i][j - 1] == ALIVE) ||
(local_screen[i][j - 1] == DEATH)) touching++;
if((local_screen[i + 1][j - 1] == ALIVE) ||
(local_screen[i + 1][j - 1] == DEATH)) touching++;
if((local_screen[i + 1][j] == ALIVE) ||
(local_screen[i + 1][j] == DEATH)) touching++;
/* Check if anyone is checking out */
if((touching < 2) || (touching > 3)) local_screen[i][j] = DEATH;
}
}
}
}
for(j = 0; j < lines; j++) {
for(i = 0; i < cols; i++)
if(local_screen[i][j] == BIRTH) {
local_screen[i][j] = ALIVE;
mvaddch(j, i, '*');
}
else if(local_screen[i][j] == DEATH) {
local_screen[i][j] = EMPTY;
mvaddch(j, i, ' ');
}
}
refresh();
signal(SIGALRM, alarm_handler);
}
void resize_array(int sig_num) {
int i, j, a, b, oldcols, oldlines;
char **temp;
#ifdef TIOCGWINSZ
struct winsize ws;
#else
#ifdef TIOCGSIZE
struct ttysize ts;
#endif
#endif
oldcols = cols;
oldlines = lines;
/* Get the new dimensions of the screen */
#ifdef TIOCGWINSZ
ioctl(1, TIOCGWINSZ, &ws);
cols = ws.ws_col;
lines = ws.ws_row;
#else
#ifdef TIOCGSIZE
ioctl(1, TIOCGSIZE, &ts);
cols = ts.ts_cols;
lines = ts.ts_lines;
#endif
#endif
clear();
if((cols >= oldcols) || (lines >= oldlines)) {
/* Need to malloc more space */
/* Get ready for calloc() and malloc() */
temp = calloc(oldcols, 4);
for(i = 0; i < oldcols; i++)
if((temp[i] = malloc(oldlines)) == NULL)
perror("malloc()");
/* Copy the old array */
for(i = 0; i < oldcols; i++)
for(j = 0; j < oldlines; j++)
temp[i][j] = local_screen[i][j];
/* Now free up our memory before malloc'ing more. Just easier */
for(i = 0; i < oldcols; i++)
free(local_screen[i]);
free(local_screen);
local_screen = calloc(cols, 4);
for(i = 0; i < cols; i++)
local_screen[i] = malloc(lines);
/* Zero the array out */
for(i = 0; i < cols; i++)
for(j = 0; j < lines; j++)
local_screen[i][j] = EMPTY;
/* Now copy back my data */
for(i = 0; i < oldcols; i++)
for(j = 0; j < oldlines; j++) {
local_screen[i][j] = temp[i][j];
}
/* Free up temp, then refresh the screen */
for(i = 0; i < oldcols; i++)
free(temp[i]);
free(temp);
/* Time to refresh */
for(i = 0; i < cols; i++)
for(j = 0; j < lines; j++) {
if(local_screen[i][j] == ALIVE) {
mvaddch(j, i, '*');
}
else if(local_screen[i][j] == EMPTY) {
mvaddch(j, i, ' ');
}
}
refresh();
}
}