Skip to content
Snippets Groups Projects
gol.c 2.66 KiB
#include "gol.h"
#include <stdlib.h>

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

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

	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));
	}
	return gameData;
}

void gol_free(gol_t *g)
{
	free(g->next);
	free(g->current);
	free(g);
}

int pMod(int x, int y)
{
	return (x + y) % y;
}

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;
}

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

/**
 * @brief iterate over each cell, and call callbacks
**/
void gol_each(gol_t *g, gol_print_colmn colmnFn, gol_print_ln lnFn)
{
	for (unsigned int row = 0; row < g->height; row++)
	{
		for (unsigned int colmn = 0; colmn < g->width; colmn++)
		{
#ifdef GOL_DEBUG
			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]);
			}
#endif
			colmnFn(getCell(g, row * g->width + colmn));
		}
		if (lnFn != NULL)
		{
			lnFn(row);
		}
	}
}

/**
 * @brief progress one timestep
 **/
void gol_tick(gol_t *g)
{
	for (unsigned int row = 0; row < g->height; row++)
	{
		for (unsigned int colmn = 0; colmn < g->width; colmn++)
		{
			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)
			{
				//living cell
				if (1 < sn && sn < 4)
				{
					g->next[d.quot] |= (1 << d.rem);
				}
			}
			else
			{
				//dead cell
				if (sn == 3)
				{
					g->next[d.quot] |= (1 << d.rem);
				}
			}
		}
	}
	unsigned int *tmp = g->current;
	g->current = g->next;
	g->next = tmp;
}