Skip to content
Snippets Groups Projects
gol.c 2.66 KiB
Newer Older
clemo's avatar
clemo committed
#include "gol.h"
#include <stdlib.h>

#ifdef GOL_DEBUG
#include <stdio.h>
#endif

/**
clemo's avatar
clemo committed
 * @param int width
 * @param int height
clemo's avatar
clemo committed
 */
clemo's avatar
clemo committed
gol_t *gol_setup(int width, int height)
clemo's avatar
clemo committed
{
clemo's avatar
clemo committed
	div_t bytes = div(width * height, 8);
	gol_t *gameData = calloc(sizeof(gol_t), 1);
clemo's avatar
clemo committed
	gameData->width = width;
	gameData->height = height;
clemo's avatar
clemo committed

	if (bytes.rem == 0)
	{
		gameData->next = calloc(bytes.quot, sizeof(int));
		gameData->current = calloc(bytes.quot, sizeof(int));
	}
	else
	{
		gameData->next = calloc(bytes.quot + 1, sizeof(int));
		gameData->current = calloc(bytes.quot + 1, sizeof(int));
	}
clemo's avatar
clemo committed
	return gameData;
}
clemo's avatar
clemo committed

void gol_free(gol_t *g)
clemo's avatar
clemo committed
{
clemo's avatar
clemo committed
	free(g->next);
	free(g->current);
	free(g);
clemo's avatar
clemo committed
}

clemo's avatar
clemo committed
int pMod(int x, int y)
clemo's avatar
clemo committed
{
clemo's avatar
clemo committed
	return (x + y) % y;
clemo's avatar
clemo committed
}
clemo's avatar
clemo committed

int getCell(gol_t *g, int cell)
{
	cell = pMod(cell, g->width * g->height);
	div_t d = div(cell, 8);
	return g->current[d.quot] & (1 << (d.rem)) ? 1 : 0;
}
clemo's avatar
clemo committed

clemo's avatar
clemo committed
int sumNeighbours(gol_t *g, int cell)
{
	int sum = 0;
	div_t row = div(cell, g->width);
clemo's avatar
clemo committed
	//left
clemo's avatar
clemo committed
	int lcell = cell - 1;
	if (row.rem == 0)
clemo's avatar
clemo committed
	{
clemo's avatar
clemo committed
		lcell += g->width;
clemo's avatar
clemo committed
	}
	//right
clemo's avatar
clemo committed
	int rcell = cell + 1;
	if (row.rem == (g->width - 1))
clemo's avatar
clemo committed
	{
clemo's avatar
clemo committed
		rcell -= g->width;
clemo's avatar
clemo committed
	}
	//up - left
clemo's avatar
clemo committed
	sum += getCell(g, lcell - g->width);
clemo's avatar
clemo committed
	//up
clemo's avatar
clemo committed
	sum += getCell(g, cell - g->width);
clemo's avatar
clemo committed
	//up -right
clemo's avatar
clemo committed
	sum += getCell(g, rcell - g->width);
	//left
	sum += getCell(g, lcell);
clemo's avatar
clemo committed
	//right
clemo's avatar
clemo committed
	sum += getCell(g, rcell);
clemo's avatar
clemo committed
	//down-left
clemo's avatar
clemo committed
	sum += getCell(g, lcell + g->width);
	//down
	sum += getCell(g, cell + g->width);
	//down -right
	sum += getCell(g, rcell + g->width);
clemo's avatar
clemo committed
	return sum;
}
clemo's avatar
clemo committed

/**
 * @brief iterate over each cell, and call callbacks
**/
void gol_each(gol_t *g, gol_print_colmn colmnFn, gol_print_ln lnFn)
clemo's avatar
clemo committed
{
	for (unsigned int row = 0; row < g->height; row++)
	{
		for (unsigned int colmn = 0; colmn < g->width; colmn++)
		{
#ifdef GOL_DEBUG
clemo's avatar
clemo committed
			if ((row * g->width + colmn) % 8 == 0)
			{
				printf("\t<%d:%d>(%d) %d: ", row, colmn, row * g->width + colmn, g->current[(row * g->width + colmn) / 8]);
			}
clemo's avatar
clemo committed
#endif
clemo's avatar
clemo committed
			colmnFn(getCell(g, row * g->width + colmn));
		}
		if (lnFn != NULL)
		{
			lnFn(row);
clemo's avatar
clemo committed
		}
	}
}
clemo's avatar
clemo committed

/**
 * @brief progress one timestep
 **/
void gol_tick(gol_t *g)
clemo's avatar
clemo committed
{
	for (unsigned int row = 0; row < g->height; row++)
	{
		for (unsigned int colmn = 0; colmn < g->width; colmn++)
		{
clemo's avatar
clemo committed
			int cell = (row * g->width) + colmn;
			div_t d = div(cell, 8);
			if (d.rem == 0)
			{
				g->next[d.quot] = 0;
			}
			const unsigned int sn = sumNeighbours(g, cell);
			if (getCell(g, cell) == 1)
clemo's avatar
clemo committed
			{
clemo's avatar
clemo committed
				//living cell
				if (1 < sn && sn < 4)
clemo's avatar
clemo committed
				{
clemo's avatar
clemo committed
					g->next[d.quot] |= (1 << d.rem);
clemo's avatar
clemo committed
				}
clemo's avatar
clemo committed
			}
			else
			{
				//dead cell
				if (sn == 3)
clemo's avatar
clemo committed
				{
clemo's avatar
clemo committed
					g->next[d.quot] |= (1 << d.rem);
clemo's avatar
clemo committed
				}
			}
		}
	}
	unsigned int *tmp = g->current;
	g->current = g->next;
	g->next = tmp;
}