I'm learning C, so as a practice problem I implemented Conway's Game of Life. For anyone unfamiliar, the problem is set out here. To summarize, there is a grid of "cells" that can be either alive or dead. This grid is updated in "steps". In each step, live cells with 2 or 3 live neighbors survive, dead cells with 3 live neighbors come alive, and live cells with less than 2 or more than 3 live neighbors die.
I'm mostly looking for C advice (anything I might be doing badly in terms of pointers, references, memory management etc.). That said, architecture and control flow critiques are 100% welcome as well.
One of the specific things I'm wondering about is my logic for not checking neighbors that don't exist on the edges (my implementation assumes cells that are off the board to be dead). Specifically, I'm wondering if there's a more elegant way to implement that than the way I've done it?
Code:
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include <time.h>
int i;
int j;
bool** emptyBoard();
void initialPosition(bool** board, char startPos[]);
void printArray(bool** board);
void freeArray(bool** board);
bool** step(bool** board);
void wait(float s);
int width = 50;
int height = 50;
void initialPosition(bool** emptyBoard, char startPos[] ) {
for(i=0; i < width; i++) {
for(j = 0; j < height; j++) {
*(emptyBoard[i] + j) = (bool) (startPos[(i * width) + j] - '0');
}
}
}
bool** emptyBoard() {
bool **board;//pointer to pointer
board = malloc(sizeof (bool *) * width);//array of pointers (each pointer to array of ints)
for (i = 0; i < width; i++) {
*(board + i) = malloc(sizeof (bool) * height);
}
for (i = 0; i < width; i++) {
for (j = 0; j < height; j++){
bool c = 0;
*(board[i] + j) = c;
}
}
return(board);
}
void printArray(bool** board) {
for (i = 0;i < width; i++) {
for (j = 0; j < height; j++){
if(*(*(board + i) + j) == 0) {
printf(" ");
} else {
printf(" o ");
}
//printf("%i ", *(*(board + i) + j));
}
printf("\n");
}
}
void freeArray(bool** board){
for (i = 0; i < width; i++) {
free(board[i]);
}
free(board);
}
bool** step(bool** board) {
bool** newBoard = emptyBoard();
int neighbors;
int k;
for(i=0; i < width; i++) {
for(j = 0; j < height; j++) {
neighbors = 0;
if(i > 0) {
if (*(*(board + i - 1) + j) == 1) {//i-1, j if i > 0
neighbors++;
}
if(j > 0) {//i-1, j if i > 0 and j > 0
if (*(*(board + i - 1) + j - 1) == 1) {
neighbors++;
}
}
if (j < width - 1) {
if (*(*(board + i - 1) + j + 1) == 1) {//i-1, j+1 if j > 0 and j < width - 1
neighbors++;
}
}
}
if(j > 0) {
if (*(*(board + i) + j - 1) == 1) {//i, j-1 if j > 0
neighbors++;
}
if (i < height - 1){
if (*(*(board + i + 1) + j - 1) == 1) {//i + 1, j -z if j > 0 and i < height - 1
neighbors++;
}
}
}
if(j < width - 1) {
if (*(*(board + i) + j + 1) == 1) {//i, j+1 if j < width -
neighbors++;
}
}
if(i < height - 1) {
if (*(*(board + i + 1) + j) == 1) {
neighbors++;
}
if(j < width - 1){
if (*(*(board + i + 1) + j + 1) == 1) {//if i < height - 1 and j < width - 1, i+1, j+1
neighbors++;
}
}
}
if (*(*(board + i) + j) == 0) {
if(neighbors == 3) {
*(*(newBoard + i) + j) = (bool) 1;
} else {
*(*(newBoard + i) + j) = (bool) 0;
}
} else if (*(*(board + i) + j) == 1) {
if(neighbors < 2) {
*(*(newBoard + i) + j) = (bool) 0;
} else if (neighbors == 2 || neighbors == 3) {
*(*(newBoard + i) + j) = (bool) 1;
} else if (neighbors > 3) {
*(*(newBoard + i) + j) = (bool) 0;
}
}
}
}
freeArray(board);
return(newBoard);
}
void wait(float s) {
int now = clock();
int then = clock() + (CLOCKS_PER_SEC * s);
while(clock() != then) {
}
}
int main() {
bool** board = emptyBoard();
printArray(board);
printf("--------------\n");
initialPosition(board, "0000000000000000000000000000000000000000000000000"
"0000000000000000000000000100000000000000000000000"
"0000000000000000000000010100000000000000000000000"
"0000000000000110000001100000000000011000000000000"
"0000000000001000100001100000000000011000000000000"
"0110000000010000010001100000000000000000000000000"
"0110000000010001011000010100000000000000000000000"
"0000000000010000010000000100000000000000000000000"
"0000000000001000100000000000000000000000000000000"
"0000000000000110000000000000000000000000000000000");
printArray(board);
while(true){
//sleep(1);
wait(0.25);
printf("\e[1;1H\e[2J");
board = step(board);
printArray(board);
}
freeArray(board);
}