gol

Implementation of Conway's Game of Life writen in C
git clone git://git.dimitrijedobrota.com/gol.git
Log | Files | Refs | README |

commitc3e7299cb951690a1f9db33d1d6b83d1efb43b5d
parent39fe329a074e151723156bcc186d6d8d15e0da58
authorDimitrije Dobrota <mail@dimitrijedobrota.com>
dateSun, 19 Jun 2022 17:29:56 +0200

General improvement - Better error checking - Better program termination - Specify default game values at runtime - Windows bug fixing

Diffstat:
Minclude/display.h|++--
Minclude/file.h|+-
Minclude/pattern.h|+-
Minclude/utils.h|++++++++++++++++-----------
Msrc/display.c|++++++++------------
Msrc/file.c|++++++++++++++++--------------
Msrc/game.c|++++++++++++++++++++++++++++--------------
Msrc/main.c|++++++--------------------

8 files changed, 78 insertions(+), 75 deletions(-)


diff --git a/include/display.h b/include/display.h

@@ -77,8 +77,8 @@ struct imenu_T {

int input(WINDOW *win, char *buffer, int size, input_f crit);
int display_start(void);
int display_stop(void);
void display_start(void);
void display_stop(void);
void display_menu(window_T wind, char *name, struct menu_T *items, int size,
int title);

diff --git a/include/file.h b/include/file.h

@@ -10,7 +10,7 @@

#include "display.h"
int file_setup(void);
void file_setup(void);
void load_files(void);
void free_files(void);
int file_select_extension(char *ext, char ***buffer);

diff --git a/include/pattern.h b/include/pattern.h

@@ -8,7 +8,7 @@

#ifndef PATTERN_H
#define PATTERN_H
#include "stdlib.h"
#include <stdlib.h>
/**
* @brief Structure representing one cell pattern to be used in the help menu

diff --git a/include/utils.h b/include/utils.h

@@ -8,7 +8,10 @@

#ifndef UTILS_H
#define UTILS_H
#include "display.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
/// maximum of the two numbers
#define MAX(a, b) ((a > b) ? a : b)

@@ -32,20 +35,22 @@

#define UNICODE 1
#endif
static void err(char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(1);
}
/// Check for memory error, and abort
#define MEM_CHECK(x) \
if ((x) == NULL) { \
display_stop(); \
printf("MEM ERROR"); \
abort(); \
}
if ((x) == NULL) \
err("MEMORY ERROR");
/// Check for file error, and abort
#define FILE_CHECK(x) \
if ((x) == NULL) { \
display_stop(); \
printf("FILE ERROR"); \
abort(); \
}
if ((x) == NULL) \
err("MEMORY ERROR");
#endif

diff --git a/src/display.c b/src/display.c

@@ -296,10 +296,14 @@ redraw:;

* selected while compiling
*/
void curses_start(void) {
initscr();
if (initscr() == NULL)
err("Fatal Error: initscr()");
window_settings(stdscr);
start_color();
if (!has_colors() || start_color() != OK)
err("Fatal Error: Terminal does not support colors");
use_default_colors();
curs_set(0);

@@ -357,25 +361,17 @@ void handle_winch(int sig) {

/**
* @brief Start ncurses display and export MAIN_w
*/
int display_start(void) {
void display_start(void) {
curses_start();
MAIN_w = window_init(window_new());
#ifdef _WIN32
resize_term(0, 0);
handle_winch(10);
#endif
return 1;
}
/**
* @brief Stop ncurses display and cleanup
*/
int display_stop(void) {
void display_stop(void) {
window_free(MAIN_w);
endwin();
return 1;
}
/**

diff --git a/src/file.c b/src/file.c

@@ -5,10 +5,10 @@

* @brief This file contains functions for handling save files
*
* This file aims to provide a simple interface for interacting with the
* file system on Linux and Windows systems. After proper game directory has been
* selected, functions implemented here will read the list of files, filter them
* based on the extension, create new files for storing a whole game or just a
* pattern.
* file system on Linux and Windows systems. After proper game directory has
* been selected, functions implemented here will read the list of files, filter
* them based on the extension, create new files for storing a whole game or
* just a pattern.
*/
#include <dirent.h>

@@ -46,7 +46,7 @@ int DirectoryExists(const char *path) {

* @brief Try to change the directory to SETTINGS_DIR, if it doesn't exist
* create it. Return 0 on failure.
*/
int file_setup(void) {
void file_setup(void) {
char *dir;
MEM_CHECK(dir = malloc(PATH_MAX * sizeof(char)));

@@ -59,17 +59,17 @@ int file_setup(void) {

if (!DirectoryExists(dir)) {
printf("Directory %s does not exists; Trying to create it...\n", dir);
if (MAKE_DIR(dir) != 0) {
printf("Cannot create the directory\n");
return 0;
}
if (MAKE_DIR(dir) != 0)
err("Cannot create the directory %s", dir);
}
if (chdir(dir) != 0) {
printf("Cannot change the directory\n");
return 0;
if (MAKE_DIR(dir) != 0)
err("Cannot change directory to %s", dir);
}
return 1;
free(dir);
}
typedef struct file_T *file_T;

@@ -95,8 +95,10 @@ file_T file_new(char *name) {

file_T f;
MEM_CHECK(f = calloc(1, sizeof(*f)));
if (name != NULL)
MEM_CHECK(f->name = strdup(name));
if (name != NULL) {
MEM_CHECK(f->name = malloc((strlen(name) + 1) * sizeof(char)));
strcpy(f->name, name);
}
return f;
}

@@ -275,7 +277,7 @@ void file_save_pattern(char *name, int index) {

FILE *f;
char *fname;
MEM_CHECK(fname = malloc((strlen(name) + 5) * sizeof(char)));
MEM_CHECK(fname = malloc((strlen(name) + 6) * sizeof(char)));
sprintf(fname, "%s.part", name);
FILE_CHECK(f = fopen(fname, "w"));

diff --git a/src/game.c b/src/game.c

@@ -20,6 +20,11 @@

#include "utils.h"
#include "window.h"
#define DEF_GEN_STEP 1
#define DEF_SCREEN_STEP 1
#define DEF_TIME_CONST 100
#define DEF_TIME_STEP 1
#ifdef _WIN32
#define TIME_MOD 1
#else

@@ -58,8 +63,10 @@ int height, width;

static int win_height, win_width;
static int screen_offset_x, screen_offset_y;
static int cursor_offset_x, cursor_offset_y;
static int wrap, gen = 0, gen_step = 1;
static int play = 0, time_const = 100, time_step = 1;
static int wrap, gen_step, screen_step;
static int play, time_const, time_step;
static unsigned gen;
#define y_at(y) y, screen_offset_y, height
#define x_at(x) x, screen_offset_x, width

@@ -183,10 +190,10 @@ void display_status(window_T wind) {

wmove(win, 1, 1);
wprintw(win, " %5s | ", play ? "play" : "pause");
wprintw(win, wrap ? "Size: %dx%d | " : "Size: unlimited | ", height, width);
wprintw(win, "Generation: %10d(+%d) | ", gen, gen_step);
wprintw(win, wrap ? "Size: %9dx%9d | " : "Size: unlimited | ", height, width);
wprintw(win, "Generation: %10u(+%d) | ", gen, gen_step);
wprintw(win, "dt: %4dms | ", time_const);
wprintw(win, "Cursor: %4dx%-4d | ", cord(y_at(cursor_offset_y)),
wprintw(win, "Cursor: %10dx%10d | ", cord(y_at(cursor_offset_y)),
cord(x_at(cursor_offset_x)));
wrefresh(win);
}

@@ -288,6 +295,7 @@ int display_select(window_T wind) {

case 'q':
case 'Q':
flushinp();
ret_value = 1;
goto end;
}
flushinp();

@@ -299,8 +307,11 @@ int display_select(window_T wind) {

overlay(win, new);
}
end:;
if (UNICODE)
delwin(new);
nodelay(stdscr, 1);
delwin(new);
return ret_value;
}

@@ -349,6 +360,10 @@ void game(int s_h, int s_w, int mode_index) {

window_T status_w, screen_w, game_w;
gen = 0;
gen_step = DEF_GEN_STEP, time_const = DEF_TIME_CONST;
time_step = DEF_TIME_STEP, screen_step = DEF_SCREEN_STEP;
reset_screen:
status_w = window_split(menu_w, 1, 3, 0, "Status", "Game");
screen_w = window_sibiling(status_w);

@@ -536,7 +551,6 @@ redraw:;

save_state();
goto reset_screen;
break;
// lead pattern
case 'l':

@@ -544,27 +558,27 @@ redraw:;

window_unsplit(menu_w);
setPosition(cord(y_at(cursor_offset_y)), cord(x_at(cursor_offset_x)));
load_pattern();
save_state();
goto reset_screen;
break;
// save game
case 'o':
case 'O':
window_unsplit(menu_w);
save();
save_state();
goto reset_screen;
break;
// help menu
case 'h':
case 'H':
window_unsplit(menu_w);
display_patterns(menu_w);
save_state();
goto reset_screen;
break;
// redraw screen
case 'r':

@@ -581,7 +595,7 @@ redraw:;

case KEY_END:
case KEY_HOME:
case KEY_LEFT:
screen_offset_x--;
screen_offset_x -= screen_step;
screen_change = 1;
break;
case KEY_A3:

@@ -589,7 +603,7 @@ redraw:;

case KEY_NPAGE:
case KEY_PPAGE:
case KEY_RIGHT:
screen_offset_x++;
screen_offset_x += screen_step;
screen_change = 1;
break;
}

@@ -600,7 +614,7 @@ redraw:;

case KEY_HOME:
case KEY_PPAGE:
case KEY_UP:
screen_offset_y--;
screen_offset_y -= screen_step;
screen_change = 1;
break;
case KEY_C1:

@@ -608,7 +622,7 @@ redraw:;

case KEY_DOWN:
case KEY_END:
case KEY_NPAGE:
screen_offset_y++;
screen_offset_y += screen_step;
screen_change = 1;
}

diff --git a/src/main.c b/src/main.c

@@ -17,8 +17,8 @@ window_T menu_w;

void settings(char *pass, int index) {
struct imenu_T imenu_items[] = {
{ "Number of rows", 6, isdigit, NULL},
{"Number of columns", 6, isdigit, NULL},
{ "Number of rows", 9, isdigit, NULL},
{"Number of columns", 9, isdigit, NULL},
};
int imenu_items_s = sizeof(imenu_items) / sizeof(struct imenu_T);

@@ -133,10 +133,7 @@ void help(char *pass, int index) {

display_patterns(menu_w);
}
void exitp(char *pass, int index) {
display_stop();
exit(0);
}
void exitp(char *pass, int index) { exit(0); }
struct menu_T menu_items[] = {
{mode_select, "Start"},

@@ -149,26 +146,15 @@ int menu_items_s = sizeof(menu_items) / sizeof(struct menu_T);

int main(void) {
setlocale(LC_ALL, "");
atexit(display_stop);
if (!file_setup()) {
printf("File setup error\n");
abort();
}
if (!display_start()) {
printf("Couldn't start the display!\n");
abort();
}
file_setup();
display_start();
menu_w = MAIN_w;
while (TRUE) {
display_menu(menu_w, "Main menu", menu_items, menu_items_s, 1);
}
if (!display_stop()) {
printf("Couldn't stop the display!\n");
abort();
}
return 0;
}