gol

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

commitb9104dd02549f3e28fd2be0fa526b77e2d505de7
parentd46d4807e8318027f45798e84b770d627db7aa88
authorDimitrije Dobrota <mail@dimitrijedobrota.com>
dateSun, 12 Jun 2022 14:42:46 +0200

Documentation for display.c and pattern.h. - Exclude uthash.h from the documentation - Move display_status() to game.c - Declutter game.c using static global variables representing a game state

Diffstat:
MDoxyfile|+-
Minclude/display.h|++++++++++++++++------------
Minclude/pattern.h|++++++++++++++-------
Msrc/display.c|+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/game.c|++++++++++++++++++++--------
Msrc/window.c|++++--------

6 files changed, 126 insertions(+), 56 deletions(-)


diff --git a/Doxyfile b/Doxyfile

@@ -920,7 +920,7 @@ RECURSIVE = NO

# Note that relative paths are relative to the directory from which doxygen is
# run.
EXCLUDE =
EXCLUDE = include/uthash.h
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded

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

@@ -23,21 +23,28 @@ extern window_T MAIN_w;

typedef int (*input_f)(int);
/*
* @breaf A item in a menu
*
* It's intended to be used with display_menu().
*/
struct menu_T {
void (*callback)(char *, int);
char *name;
void (*callback)(char *, int); ///< function called when item is selected
char *name; ///< name of the menu item
};
/*
* @breaf A item in a interactive menu
*
* It's intended to be used with display_imenu().
*/
struct imenu_T {
char *message;
int size;
input_f crit;
char *buffer;
char *message; ///< prompt for the user
int size; ///< max number of characters required
input_f crit; ///< function that check the validity of a character
char *buffer; ///< place where read character are stored
};
extern int screen_offset_x, screen_offset_y;
extern int wrap;
int input(WINDOW *win, char *buffer, int size, input_f crit);
int display_start(void);

@@ -46,9 +53,6 @@ int display_stop(void);

void display_menu(window_T wind, char *name, struct menu_T *items, int size,
int title);
int display_imenu(window_T wind, struct imenu_T *items, int size);
void display_status(window_T wind, unsigned long int generation, int gen_step,
int wrap, int height, int wight, int play, int dt,
int cursor_y, int cursor_x);
void display_patterns(window_T wind);
void handle_winch(int sig);

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

@@ -3,11 +3,15 @@

#include "stdlib.h"
/**
* @brief Structure representing one cell pattern to be used in a help menu
*/
typedef struct pattern_T {
char *cells;
char *name;
int height;
int width;
char *cells; ///< string where 1 represents a living cell and 0 a dead one,
/// space is used to detonate a new row
char *name; ///< name of the pattern
int height; ///< pattern height , used for cache, no need to fill manually
int width; ///< pattern width , used for cache, no need to fill manually
} * pattern_T;
struct pattern_T title = {

@@ -84,10 +88,13 @@ struct pattern_T methuselahs[] = {

{"00000010 11000000 01000111", "Diehard", 0},
};
/**
* @brief A structure representing a group of pattern_T of a certain category
*/
typedef struct pattern_group_T {
char *name;
pattern_T pattern;
int size;
char *name; ///< name of the group
struct pattern_T *pattern; ///< array of pattern_T that comprise a group
int size; ///< number of elements in a group
} pattern_group_T;
struct pattern_group_T pattern_groups[] = {

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

@@ -1,5 +1,16 @@

/**
* @file display.c
* @author Dimitrije Dobrota
* @date 12 June 2022
* @brief This file handles ncurses library and UI
*
* This file is the main link with ncurses interface. It is responsible for
* starting and stopping ncurses library as well as managing it's resources and
* handling terminal resize by rebuilding window_T binary tree. It exports
* window_T MAIN_w as the entery point for other windows and disiplay calls. It
* handles the display of menus and user input.
*/
#include <curses.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>

@@ -11,18 +22,33 @@

window_T MAIN_w = NULL;
/**
* @brief Offset the cursor for ncurses WINDOW*
*
* @param oy: real number representing offset along y axis
* @param ox: real number representing offset along x axis
*/
void cursor_offset(WINDOW *win, int oy, int ox) {
int y, x;
getyx(win, y, x);
wmove(win, y + oy, x + ox);
}
void print_pattern(WINDOW *win, pattern_T pattern, int *y, int x, int indent) {
/**
* @brief Print pattern_T
*
* @param y: pointer to int representing y cord where the pattern
* should be displayed. Will be inc read by the number of lines
* printed
* @param x: pointer to int representing x cord where the pattern
* should be displayed
*/
void print_pattern(WINDOW *win, pattern_T pattern, int *y, int x) {
(*y)++;
wmove(win, (*y)++, x + indent);
wmove(win, (*y)++, x);
for (char *c = pattern->cells; *c != '\0'; c++) {
if (*c == ' ') {
wmove(win, (*y)++, x + indent);
wmove(win, (*y)++, x);
continue;
}
int val = *c - '0';

@@ -31,20 +57,13 @@ void print_pattern(WINDOW *win, pattern_T pattern, int *y, int x, int indent) {

}
}
void display_status(window_T wind, unsigned long int gen, int gen_step,
int wrap, int height, int wight, int play, int dt,
int cursor_y, int cursor_x) {
WINDOW *win = window_win(wind);
wmove(win, 1, 1);
wprintw(win, " | %5s | ", play ? "play" : "pause");
wprintw(win, wrap ? "Size: %dx%d | " : "Size: unlimited | ", height, wight);
wprintw(win, "Generation: %10lu(+%d) | ", gen, gen_step);
wprintw(win, "dt: %4dms | ", dt);
wprintw(win, "Cursor: %4dx%-4d | ", cursor_y, cursor_x);
wrefresh(win);
}
/**
* @brief Get user input of different type up to the specified size
*
* @param buffer: buffer where the input will be stored
* @param size: maximum number of characters in the input
* @param crit: function that checks the validity of the character
*/
int input(WINDOW *win, char *buffer, int size, input_f crit) {
int CLINES = LINES, CCOLS = COLS;
int ch, read = strlen(buffer);

@@ -87,6 +106,10 @@ int input(WINDOW *win, char *buffer, int size, input_f crit) {

return 0;
}
/**
* @brief Given a array of struct imenu_T, display a menu where user will enter all of
* the information required from the array
*/
int display_imenu(window_T wind, struct imenu_T *items, int size) {
WINDOW *win;
int y_offset;

@@ -147,6 +170,9 @@ redraw:;

curs_set(0);
}
/**
* @brief Display the title of the game in the center of the screen if it can fit
*/
void display_title(window_T wind, int y) {
WINDOW *win = window_win(wind);
title.height = (!title.height) ? pattern_height(&title) : title.height;

@@ -154,10 +180,16 @@ void display_title(window_T wind, int y) {

int max_w = window_wight(wind);
if (title.width * 2 < max_w)
print_pattern(win, &title, &y, (max_w - title.width * 2) / 2, 0);
print_pattern(win, &title, &y, (max_w - title.width * 2) / 2);
wrefresh(win);
}
/**
* @brief Given a array of struct menu_T, display all menu items and allow user
* to chose one of them after which appropriate callback function will be called
*
* @param title: 1 if title should be displayed
*/
void display_menu(window_T wind, char *name, struct menu_T *items, int size,
int title) {
WINDOW *win;

@@ -224,6 +256,10 @@ redraw:;

}
}
/**
* @brief Initialize ncurses library and set colors based on display mode
* selected while compiling
*/
void curses_start(void) {
initscr();
window_settings(stdscr);

@@ -265,6 +301,11 @@ void curses_start(void) {

#endif
}
/**
* @brief Handle the reboiling of window_T binary tree after terminal resize
*
* This function MUST be called after a resize has been detected by any function
*/
void handle_winch(int sig) {
endwin();
refresh();

@@ -274,6 +315,9 @@ void handle_winch(int sig) {

window_update_children(MAIN_w);
}
/**
* @brief Start ncurses display and export MAIN_w
*/
int display_start(void) {
curses_start();
MAIN_w = window_init(window_new());

@@ -286,12 +330,19 @@ int display_start(void) {

return 1;
}
/**
* @brief Stop ncurses display and cleanup
*/
int display_stop(void) {
window_free(MAIN_w);
endwin();
return 1;
}
/**
* @brief Display help menu using all the patterns from all the groups in
* pattern_groups array
*/
void display_patterns(window_T wind) {
int y_start = 2, x_start = 2;
int indent = 2;

@@ -335,7 +386,7 @@ redraw:;

wattrset(win, 0);
if (p.height != 0) {
mvwprintw(win, y++, x, "- %s: ", p.name);
print_pattern(win, &p, &y, x, indent);
print_pattern(win, &p, &y, x + indent);
y += 2;
} else {
if (*p.name) {

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

@@ -26,10 +26,13 @@ int coordinate_wrap(int val, int offset, int max) {

return (val + offset + max) % max;
}
int win_height, win_width, height, width;
int screen_offset_x, screen_offset_y;
int cursor_offset_x, cursor_offset_y;
int wrap;
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;
coordinate_f cord;

@@ -117,6 +120,18 @@ void display_cursor(WINDOW *win) {

prev_x = cursor_offset_x;
}
void display_status(window_T wind) {
WINDOW *win = window_win(wind);
wmove(win, 1, 1);
wprintw(win, " %5s | ", play ? "play" : "pause");
wprintw(win, wrap ? "Size: %dx%d | " : "Size: unlimited | ", height, width);
wprintw(win, "Generation: %10lu(+%d) | ", gen, gen_step);
wprintw(win, "dt: %4dms | ", time_const);
wprintw(win, "Cursor: %4dx%-4d | ", cursor_offset_y, cursor_offset_x);
wrefresh(win);
}
int display_select(window_T wind) {
int CLINES = LINES, CCOLS = COLS;

@@ -232,7 +247,6 @@ void game(int s_h, int s_w, int mode_index) {

char *mode_name = evolution_names[mode_index];
int t_y = 0, t_x = 0, ct_x = 0, ct_y = 0;
int gen = 0, gen_step = 1, play = 0, time_const = 100, time_step = 1;
wrap = 1;
window_T status_w, screen_w, game_w;

@@ -314,9 +328,7 @@ redraw:;

gen += gen_step;
}
display_status(status_w, gen, gen_step, wrap, height, width, play,
time_const, cord(y_at(cursor_offset_y)),
cord(x_at(cursor_offset_x)));
display_status(status_w);
if (screen_change) {
display_game(game_w);

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

@@ -35,11 +35,10 @@ typedef struct T *T;

* children when a terminal resize occurs.
*/
struct window_T {
WINDOW
*win; ///< ncurses WINDOW* that represents current window_T on the screen
T c1; ///< left child, NULL if none
T c2; ///< right child, NULL if none
T sibling; ///< sibling, NULL if none
WINDOW *win; ///< ncurses WINDOW* that represents current window_T
T c1; ///< left child, NULL if none
T c2; ///< right child, NULL if none
T sibling; ///< sibling, NULL if none
int param[4]; ///< windows size and dimension, refer to macros
int mod[3]; ///< Information an recreating children

@@ -133,7 +132,6 @@ T window_init(T self) {

*
* Free the object itself and ncurses WINDOW* with delwin
*/
void window_free(T self) {
if (self == NULL)
return;

@@ -146,7 +144,6 @@ void window_free(T self) {

/**
* @brief Delete all children and subchildren of a window
*/
void window_unsplit(T self) {
window_free(self->c1);
window_free(self->c2);

@@ -315,7 +312,6 @@ void window_update_children(T self) {

* @brief Clear the current window, reset the setting, keep the border call
* ncurses refresh()
*/
void window_clear(T self) {
werase(self->win);
WINDOW_init(self->win, self->title);