~laumann/C

31a7f41346c3dd88cc061b01138d98e125352ae5 — Thomas Laumann 9 years ago 06ad629
Added conway
5 files changed, 268 insertions(+), 0 deletions(-)

A conway/Makefile
A conway/TODO
A conway/conway.c
D linkedlist/linkedlist
M tblj-yaml/notes.txt
A conway/Makefile => conway/Makefile +13 -0
@@ 0,0 1,13 @@
CC = gcc
CFLAGS = -Wall
RM = rm -rvf

OBJS = conway.o

conway: $(OBJS)
	$(CC) $(CFLAGS) $(OBJS) -o $@

clean:
	@$(RM) $(OBJS) conway *~

.PHONY: clean
\ No newline at end of file

A conway/TODO => conway/TODO +31 -0
@@ 0,0 1,31 @@
TODO:
	- Allow options --rows=<int>, --cols=<int> to indicate the size of the
	  world.
	- Create ncurses display.
	- Allow option --interval=<int> that sets the interval times.
	- Optimisation: Eliminate if's in calculating the sum... rather have
	  several for loops that each know what to do (without asking
	  questions).
	- Allow file (--init=<file>) to be specified in the input, in a certain
	  format.
	  
	  Example (the blinker):

	  5 5
	  0 0 0 0 0	The first two numbers indicate the rows (R) and columns
	  0 0 0 0 0	(C) respectively. Then should follow R lines of C
	  0 1 1 1 0	integers (0s or 1s), separated by spaces. Zero (0) means
	  0 0 0 0 0	"dead" and one (1) "alive". This makes up the initial
	  0 0 0 0 0	configuration.

	  Here's another example (the beacon):

	  4 4
	  1 1 0 0
	  1 0 0 0
	  0 0 0 1
	  0 0 1 1

DONE:
	- for every "timeslice", initialise a new array and fill it based on the
	  values of the old array, then replace the old array.

A conway/conway.c => conway/conway.c +196 -0
@@ 0,0 1,196 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define COLS	20
#define ROWS	10
#define INTERVAL 1000

int nrows = ROWS;
int ncols = COLS;

int interval = INTERVAL;

/**
 * Free an array
 */
#define free_ary(ary,rows)			\
	do {					\
		int i = 0;			\
		for ( ; i < rows; i++)		\
			free(ary[i]);		\
		free(ary);			\
	} while(0);

#define print_ary(ary,rows,cols)				\
	do {							\
		int i,j;					\
		for (i=0; i<rows; i++) {			\
			for (j=0; j<cols; j++)			\
				printf(" %d", ary[i][j]);	\
			printf("\n");				\
		}						\
	} while(0);

/** 
 * Allocate and return a pointer to a 2D array with dimensions specified by 
 * cols and rows - array is _not_ initialised.
 */
int **
alloc_ary(int rows, int cols)
{
	int i;
	int **array = calloc(rows, sizeof(int*));
	for (i=0; i<rows; i++)
		array[i] = calloc(cols, sizeof(int));
	
	return array;
}

/* List the eight neigbors 
 *   NW N NE    
 *   W  c  E    c = center 
 *   SW S SE
 *
 *   AL  A  AR  A = Above
 *   L   C  R   B = Below
 *   BL  B  BR  C = Center, L = Left, R = Right
 *    
 *   =>   which is x and which is y? 
 *
 *   (x-1,y-1) (x-1,y) (x-1, y+1)
 *   (x,  y-1) (x , y) (x,   y+1)
 *   (x+1,y-1) (x+1,y) (x+1, y+1)
 *   
 */
#define AL(ary,x,y) ((x>0 && y>0) ? ary[x-1][y-1] : 0)
#define A(ary,x,y) ((x>0) ? ary[x-1][y] : 0)
#define AR(ary,x,y) ((x>0 && y < ncols-1) ? ary[x-1][y+1] : 0)

#define L(ary,x,y) ((y>0) ? ary[x][y-1] : 0)
#define R(ary,x,y) ((y<ncols-1) ? ary[x][y+1] : 0)

#define BL(ary,x,y) ((x<nrows-1 && y>0) ? ary[x+1][y-1] : 0)
#define B(ary,x,y) ((x<nrows-1) ? ary[x+1][y] : 0)
#define BR(ary,x,y) ((x<nrows-1 && y<ncols-1) ? ary[x+1][y+1] : 0)

#define neighbor_sum(ary,x,y)			\
	AL(current,i,j)				\
	+ A(current,i,j)			\
	+ AR(current,i,j)			\
	+ L(current,i,j)			\
	+ R(current,i,j)			\
	+ BL(current,i,j)			\
	+ B(current,i,j)			\
	+ BR(current,i,j)			\

void
conway_timeslice(int **current, int **new, int rows, int cols)
{
	int i, j, sum;
	for (i=0; i<rows; i++) {
		for (j=0; j<cols; j++) {
			new[i][j] = current[i][j]; /* copy! */

			sum = neighbor_sum(current,i,j);

			/* Rule 1 + 3: He dies (under- and overpopulation) */
			if (current[i][j] && (sum < 2 || sum > 3))
				new[i][j] = 0;
			else if (sum == 3) /* dead */
				new[i][j] = 1;
		}
	}
}

const char conway_usage[] = "Usage: ./conway [options]\n\n"
	"Common options:\n"
	" -h,--help                  Print help information and exit.\n"
	" -i,--interval <millisecs>  Set the update interval.\n";

void
handle_cmd_args(int *argc, const char ***argv)
{
	while (*argc > 0) {
		const char *cmd = (*argv)[0];
		
		if (!strcmp(cmd, "--help") || !strcmp(cmd, "-h")) {
			printf("%s", conway_usage);
			exit(0);
		}
		else if (!strcmp(cmd, "--interval") || !strcmp(cmd, "-i")) {
			if (*argc < 2) {
				fprintf(stderr, "--interval requires an integer argument\n");
				exit(EXIT_FAILURE);
			}

			(*argc)--;
			(*argv)++;
			
			if (sscanf((*argv)[0], "%d", &interval) == EOF) {
				fprintf(stderr, "Error scanning integer value");
				exit(EXIT_FAILURE);
			}
			
			printf("interval = %d\n", interval);
		}

		(*argc)--;
		(*argv)++;
	}
}

/**
 * Conway's Game of Life.
 */
int main(int argc, char *argv[])
{
	argc--;
	argv++;
	handle_cmd_args(&argc, &argv);

	int **ary0 = alloc_ary(nrows, ncols);
	int **ary1 = alloc_ary(nrows, ncols);

	/* Build the beacon (period 2) 
	 * 0 0 0 0 0
	 * 0 1 1 0 0
	 * 0 1 0 0 0 
	 * 0 0 0 0 1
	 * 0 0 0 1 1
	 */
	ary0[1][1] = 1;
	ary0[1][2] = 1;
	ary0[2][1] = 1;

	ary0[4][4] = 1;
	ary0[3][4] = 1;
	ary0[4][3] = 1;

	int **current, **next;
	int aoeu = 0;

	print_ary(ary0, nrows, ncols);
	printf("\n");

	/* Now - run forever! Infinite loop? I don't have time for that! */
	for (;;) {
		if (aoeu) {
			current = ary1;
			next = ary0;
		} else {
			current = ary0;
			next = ary1;
		}

		conway_timeslice(current, next, nrows, ncols);
		aoeu = (aoeu) ? 0 : 1;

		print_ary(next, nrows, ncols);
		printf("\n");

		usleep(interval);
	}
	return 0;
}

D linkedlist/linkedlist => linkedlist/linkedlist +0 -0
M tblj-yaml/notes.txt => tblj-yaml/notes.txt +28 -0
@@ 1,3 1,31 @@
Quoth: "JSON's RFC4627 requires that mappings keys merely “SHOULD” be unique, while YAML insists they “MUST” be."

C2:
	(Collections)
	* YAML block collection use indentation for scope, and begin each entry on a new line
	* Block sequences indicate each entry with a dash and a space "- "
	* Mappings use a colon, space ": " to mark each 'key: value' pair
	* Comments begin with an octothorpe "#"

	(Flow styles)
	* flow sequence is written as a comma separated list within square brackets "[" e1, ..., en "]"
	* similarly, flow mapping uses curly braces "{" k1: v1, ..., kn: vn "}"

	(Structures)
	* three dashes "---" to separate directives from document content. Serves to signal the start of a document if no directives are present
	* Three dots "..." indicate the end of a document without starting a new one
	* Repeated nodes (objects) are first identified by an anchor "&", then referenced with "*" later
	* A question mark and space "?" indicate a complex mapping key. Within a block collection, key: value pairs can start immediately following the dash, colon, or question mark.

	(Scalars)
	* Scalar content can be written in block notation, using a literal style "|" where all line breaks are significant
	* Folded style is indicated by ">" where each line break is folded into a single space, unless it's an empty line, or more-indented
	* Flow scalars include the plain style and two quoted styles, where double-quoted style provides escape sequences.
	* Single quoted style is useful when escaping is not needed.
	* All flow scalars can span multiple lines; line breaks are always folded

	(Tags)

Representing native data structures:

YAML using three node kinds: sequence - an ordered series of entries; mapping - an unordered association of unique keys to values; and scalar - any datum with opaque structure presentable as a series of Unicode characters.