gol

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

commit b9104dd02549f3e28fd2be0fa526b77e2d505de7
parent d46d4807e8318027f45798e84b770d627db7aa88
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Sun, 12 Jun 2022 16: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 | 2+-
Minclude/display.h | 28++++++++++++++++------------
Minclude/pattern.h | 21++++++++++++++-------
Msrc/display.c | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Msrc/game.c | 28++++++++++++++++++++--------
Msrc/window.c | 12++++--------
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);