SHELL = /bin/bash
DESTDIR ?=
-
ETCDIR ?= $(DESTDIR)/etc/$(NAME)
USRDIR ?= $(DESTDIR)/usr
-BINDIR ?= $(USRDIR)/bin
-LIBDIR ?= $(USRDIR)/lib
-MANDIR ?= $(USRDIR)/share/man/man1
-DOCDIR ?= $(USRDIR)/share/doc/$(NAME)
+
+PREFIX ?= $(USRDIR)
+BINDIR ?= $(PREFIX)/bin
+LIBDIR ?= $(PREFIX)/lib
+SHAREDIR ?= $(PREFIX)/share
+INCLUDE ?= $(PREFIX)/include
+MANDIR ?= $(SHAREDIR)/man
+MAN1DIR ?= $(MANDIR)/man1
+DOCDIR ?= $(PREFIX)/doc/$(NAME)
SRCDIR ?= ./src
OBJDIR ?= ./obj
SRC ?= $(wildcard $(SRCDIR)/*.c)
HDR ?= $(wildcard $(SRCDIR)/*.h)
OBJ ?= $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SRC))
+LIBNAME ?= lib$(NAME)
+LIB ?= $(BUILD)/$(LIBNAME).so
+STATIC ?= $(BUILD)/$(LIBNAME).a
+
TAR ?= $(BUILD)/$(NAME)-$(VER).tar.gz
MANPAGE ?= $(patsubst $(SRCDIR)/%.1,$(BUILD)/%.1.gz,$(MAN))
DOC ?= README LICENSE
-CC ?= gcc
-ZIP ?= gzip
+CC = gcc
+AR = ar
+LD = ld
+ZIP = gzip
+RM = rm -f
+
CFLAGS += -O2 -pipe
-WARNINGS ?= -Wall -Wextra -Wpedantic
-CPPFLAGS += -I $(SRCDIR)
-LDFLAGS += -L $(SRCDIR)
+CPPFLAGS += -I$(SRCDIR) -I$(BUILD)
+LDFLAGS += -L$(SRCDIR) -L$(BUILD)
LDLIBS +=
-FLAGS ?= $(CPPFLAGS) $(CFLAGS) $(WARNINGS) $(LDFLAGS) $(LDLIBS)
+WARNINGS ?= -Wall -Wextra -Wpedantic
+
+FLAGS += $(CPPFLAGS) $(CFLAGS) $(WARNINGS) $(LDFLAGS) $(LDLIBS)
+DEBUGFLAGS += $(WARNINGS) $(CPPFLAGS) $(LDFLAGS) $(LDLIBS) -ggdb -Og -pipe
+RELEASEFLAGS = $(CPPFLAGS) $(LDFLAGS) $(LDLIBS) -O3 -pipe -DNDEBUG -DDONT_USE_VOL
all: $(BIN)
-release: CFLAGS = -O3 -pipe -DNDEBUG -DDONT_USE_VOL
-release: $(BIN)
+lib: $(LIB)
+
+static: $(STATIC)
+
+release: | $(BUILD)
+ $(MAKE) clean
+ $(CC) $(SRC) $(RELEASEFLAGS) -o $(BIN)-$(VER)
+ $(MAKE) tar
install: $(BIN) $(MANPAGE) $(DOC)
-mkdir -p $(BINDIR)
-mkdir -p $(DOCDIR)
install -CDm 644 -t $(DOCDIR) $(DOC)
-uninstall:
- -rm -rf $(BINDIR)/$(BIN) $(MANDIR)/$(MANPAGE) $(DOCDIR)
+install_lib:
+ -mkdir -p $(LIBDIR)
+ cp $(LIB) $(LIBDIR)
+ chmod 755 $(LIBDIR)/$(patsubst $(BUILD)/%,%,$(LIB))
+ -mkdir -p $(INCLUDE)
+ cp $(HDR) $(INCLUDE)
+ chmod 644 $(INCLUDE)/$(patsubst $(SRCDIR)/%,%,$(HDR))
+
+install_static:
+ -mkdir -p $(LIBDIR)
+ cp $(STATIC) $(LIBDIR)
+ chmod 755 $(LIBDIR)/$(patsubst $(BUILD)/%,%,$(STATIC))
+ -mkdir -p $(INCLUDE)
+ cp $(HDR) $(INCLUDE)
+ chmod 644 $(INCLUDE)/$(patsubst $(SRCDIR)/%,%,$(HDR))
-tar: $(SRC) $(HDR) $(MAN) $(DOC)
+uninstall:
+ $(RM) -r $(BINDIR)/$(patsubst $(BUILD)/%,%,$(BIN))
+ $(RM) -r $(MANDIR)/$(patsubst $(BUILD)/%,%,$(MANPAGE))
+ $(RM) -r $(INCLUDE)/$(patsubst $(SRC)/%,%,$(HDR))
+ $(RM) -r $(LIBDIR)/$(patsubst $(BUILD)/%,%,$(LIB))
+ $(RM) -r $(LIBDIR)/$(patsubst $(BUILD)/%,%,$(STATIC))
+ $(RM) -r $(DOCDIR)
+
+tar: $(SRC) $(HDR) $(MAN) $(DOC) | $(BUILD)
tar -I $(ZIP) -cvf $(TAR) $(SRC) $(HDR) $(MAN) $(DOC)
-$(BIN): $(OBJ)
+$(BIN): $(OBJ) | $(BUILD)
$(CC) $(OBJ) $(FLAGS) -o $(BIN)
-$(OBJDIR)/%.o: $(SRCDIR)/%.c $(HDR)
+$(LIB): $(SRC) $(HDR) | $(BUILD)
+ $(CC) $(SRC) $(FLAGS) -fPIC -shared -lc -o $(LIB)
+
+$(STATIC): $(OBJ) | $(BUILD)
+ $(AR) rcs $(STATIC) $(OBJ)
+
+$(OBJDIR)/%.o: $(SRCDIR)/%.c $(HDR) | $(OBJDIR)
$(CC) -c $(FLAGS) $< -o $@
clean:
- -rm -f $(BUILD)/* $(OBJDIR)/*
+ $(RM) $(BUILD)/* $(OBJDIR)/*
-debug: $(SRC)
- $(CC) $(SRC) $(FLAGS) -ggdb3 -Og -pipe -o $(BIN)-debug
+debug: | $(BUILD)
+ $(MAKE) clean
+ $(CC) $(SRC) $(DEBUGFLAGS) -o $(BIN)-debug
-$(MANPAGE): $(MAN)
+$(MANPAGE): $(MAN) | $(BUILD)
$(ZIP) -c $(MAN) > $(MANPAGE)
-$(SRCDIR) $(OBJDIR) $(BUILDIR):
+$(SRCDIR) $(OBJDIR) $(BUILD):
mkdir $@
-.PHONY: all release clean install tar uninstall debug test
+.PHONY: all release lib install_lib static install_static tar clean install uninstall debug
+
Download and extract source:
$ curl "https://download.huck.website/gol-[VERSION].tar.gz > gol.tar.gz
- $ tar -xzvf gol.tar.gz
- $ cd gol.tar.gz
+ $ tar -xzvf gol.tar.gz >
+ $ cd gol
Build and install:
$ make && sudo make install
$ gol -a
Change initial distribution weight:
$ gol -w [INT]
-E
+ Change time interval between steps:
+ $ gol -t [ms]
+ Use a file as input:
+ $gol -f [file]
+
+When using a file as input, gol uses any non-whitespace character as a live cell. If the given
+file is larger than the map, gol will simply fit what it can on the map.
#include "gol.h"
-
extern int row,col,step,ascii,color,weight,file;
extern char *filename;
return;
}
-void errorcheck(int err){
+void errorcheck(ERROR err){
if (errno != 0) {
fprintf(stderr,"\nERROR: %s\n",strerror(errno));
- exit(EXIT_FAILURE);
+ err |= SYS_ERR;
}
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"); }
-
- if ((err & FILE_ERR) != 0) { fprintf(stderr,"ERROR: Could not open file\n"); }
+ if ((err & FLAG_ERR) != 0) fprintf(stderr,"ERROR: Unknown Flag\n");
+ if ((err & STATE_ERR) != 0) fprintf(stderr,"ERROR: Could not determine cell state\n");
+ if ((err & FILE_ERR) != 0) fprintf(stderr,"ERROR: Could not open file\n");
exit(err);
}
int main(int argc, char *argv[]){
srand(time(NULL));
- int stop = 1;
row = 30;
col = 90;
step = 75000;
- ascii = 0;
weight = 5;
- file = 0;
filename = malloc(sizeof(char) * MAXLINE);
parseopts(argc,argv);
- struct map map = newmap();
+ MAP map = newmap();
if (file) {
mapfile(map,filename);
genmap(map);
}
- while (stop > 0){
- stop = updatemap(map);
+ while (1){
+ updatemap(map);
printdisplay(map);
usleep(step);
}
}
-void printdisplay(struct map map){
+void printdisplay(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 {
+ if (ascii){
printf("%c",map.line[r].cell[c].cellchar);
+ } else {
+ printf("%4s",map.line[r].cell[c].pixel);
}
}
putc('\n',stdout);
#include <wchar.h>
#define MAXLINE 10000
-#define VERSION "0.2.1"
+#define VERSION "0.2.2"
#define CLEAR "\e[1;1H\e[2J"
-enum {DIE = -1, DEAD = 0, ALIVE = 1, SPAWN = 1 << 1};
+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, FILE_ERR = 1 << 3};
+enum {
+ NO_ERR = 0,
+ SYS_ERR = 1,
+ FLAG_ERR = 1 << 1,
+ STATE_ERR = 1 << 2,
+ COLOR_ERR = 1 << 3,
+ FILE_ERR = 1 << 4
+};
+
+typedef int ERROR;
+typedef struct map MAP;
+struct map { struct line *line; };
+struct line { struct cell *cell; };
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 errorcheck(ERROR);
void parseopts(int,char **);
void help(void);
-void printdisplay(struct map);
+void printdisplay(MAP);
/* map.c */
-void genmap(struct map);
-void mapfile(struct map, char *);
-int updatemap(struct map);
-int numneighbor(struct map,int,int);
-int checkstate(struct map,int,int);
+void genmap(MAP);
+void mapfile(MAP, char *);
+void updatemap(MAP);
+int numneighbor(MAP,int,int);
+int checkstate(MAP,int,int);
char statechar(int);
char *statecell(int);
/* struct.c */
struct map newmap(void);
-void freemap(struct map);
+void freemap(MAP);
extern int row,col,weight;
-void genmap(struct map map){
+void genmap(MAP map){
int rnd = 0;
for (int r = 0; r < row; r++){
for (int c = 0; c < col; c++){
return;
}
-void mapfile(struct map map, char *file){
+void mapfile(MAP map, char *file){
FILE *fp = fopen(file, "r");
if (!fp) errorcheck(FILE_ERR);
return;
}
-int updatemap(struct map map){
- int n = 0;
- struct map tmp = newmap();
+void updatemap(MAP map){
+ MAP tmp = newmap();
/* non edges */
for (int r = 0; r < row-1; r++){
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++; }
}
}
/* left/right side */
- for (int r = 0; r < row -1; r++){
+ for (int r = 0; r < row - 1; r++){
int state = checkstate(map,r,0);
tmp.line[r].cell[col-1].state = state;
tmp.line[r].cell[col-1].cellchar = statechar(state);
strncpy(tmp.line[r].cell[col-1].pixel,statecell(state),4);
- if (state > DEAD){ n++; }
}
- /* top/bottom */
- for (int c = 0; c < col -1; c++){
+ /* top/bottom row */
+ for (int c = 0; c < col - 1; c++){
int state = checkstate(map,0,c);
tmp.line[row-1].cell[c].state = state;
tmp.line[row-1].cell[c].cellchar = statechar(state);
strncpy(tmp.line[row-1].cell[c].pixel,statecell(state),4);
- if (state > DEAD){ n++; }
}
/* copy to map */
}
}
- return n;
+ return;
}
-int checkstate(struct map map,int r, int c){
+int checkstate(MAP map,int r, int c){
int state = 0;
int n = numneighbor(map, r, c);
}
-int numneighbor(struct map map, int r, int c){
+int numneighbor(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 */
+ 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/bottom 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 */
+ 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-2].cell[c+1].state > DEAD) n++;
+ if (map.line[r+1].cell[c].state > DEAD) n++;
+ if (map.line[row-2].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-2].cell[c-1].state > DEAD) n++;
+ /* left/right 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 ++;
+ 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-2].state > DEAD) n++;
+ if (map.line[r].cell[col-2].state > DEAD) n++;
+ if (map.line[r-1].cell[col-2].state > DEAD) n++;
}
return n;
}
return tmp;
}
-
-void freemap(struct map map){
+void freemap(MAP map){
for (int r = 0; r < row; r++){
for (int c = 0; c < col; c++){
free(map.line[r].cell);