commit 39fe329a074e151723156bcc186d6d8d15e0da58
parent 6049c8151ba0a9ce5ceb2e63e244c3d5df673cc2
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date: Sun, 19 Jun 2022 15:02:09 +0200
Documentation and general improvement
- Update README
- Update Doxygen settings
- Documentation for .h files
- Fixed spelling
Diffstat:
13 files changed, 142 insertions(+), 76 deletions(-)
diff --git a/Doxyfile b/Doxyfile
@@ -2196,7 +2196,7 @@ SEARCH_INCLUDES = YES
# preprocessor.
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
-INCLUDE_PATH =
+INCLUDE_PATH = ./include
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the
diff --git a/README.md b/README.md
@@ -1,36 +1,32 @@
- ____ __ _ _ __
- / ___| __ _ _ __ ___ ___ ___ / _| | | (_)/ _| ___
-| | _ / _` | '_ ` _ \ / _ \ / _ \| |_ | | | | |_ / _ \
-| |_| | (_| | | | | | | __/ | (_) | _| | |___| | _| __/
- \____|\__,_|_| |_| |_|\___| \___/|_| |_____|_|_| \___|
-
-
# Game of Life Simulation
This is an implementation of Conway's Game of Life in C for a university project
+
## About the Project
-This project is command line application written in C using the ncruses library
+This project is command line application written in C using the ncurses library
to display GUI in the terminal. Project works both on Unix and Windows systems.
Features:
-- Responsive:
- - Every menu and graphic is completely responsive
+- Graphics:
+ - Every menu is completely responsive
+ - Unicode and No Unicode mode
- Multiple game modes:
- Normal
- Coexistence
- Predator
- - Virus
- Unknown
+ - Virus
- Game:
- Custom display interval
- Custom speed
- Movable cursor
- Movable screen
- - Status line with basic information abut the game
+ - Optional mouse support in game
+ - Status line with information about the game
- Visual select mode
- Save/Load system:
@@ -45,12 +41,18 @@ Features:
- Information about the game
- Cheatsheet with common cell patterns
+- Documentation:
+ - html documentation using doxygen
+ - pdf documentation using doxygen and pdflatex
+
## Prerequisites
- C compiler
- Make
- ncurses (pdcurses on Windows)
+- doxygen and pdflatex (if you want to build documentation)
+
## How to build
@@ -77,9 +79,9 @@ To then run the program, type in
in the project directory.
To compile the debugging version of the executable, run `make DEBUG=Y`.
-
You can also give the optional parameter `NO_UNICODE=Y`, to build the executable without Unicode support.
+
## Running the project
In the `./bin` directory you will find the executable, and you can run it with
diff --git a/include/display.h b/include/display.h
@@ -1,14 +1,43 @@
+/**
+ * @file display.h
+ * @author Dimitrije Dobrota
+ * @date 19 June 2022
+ * @brief Methods and types for displaying UI
+ */
+
#ifndef DISPLAY_H
#define DISPLAY_H
#include "window.h"
-#define CHAR_BLANK " "
+#ifdef _WIN32
+#define is_term_resized(a, b) is_termresized()
+#define HANDLE_RESIZE \
+ { \
+ resize_term(0, 0); \
+ handle_winch(10); \
+ }
+#else
+#define HANDLE_RESIZE \
+ { handle_winch(10); }
+#endif
+
+/// Character representing dead cell
+#define CHAR_BLANK " "
+
+/// Character representing cursor
#define CHAR_CURSOR "<>"
+
+/// Character representing a living cell with a circle
#define CHAR_CIRCLE "\u26AB"
+
+/// Character representing a living cell with a square
#define CHAR_SQUARE "\u2B1B"
+
+/// Active representation of a living cell
#define CHAR_ACTIVE CHAR_CIRCLE
+/// Way of printing a cell based on Unicode support
#ifndef NO_UNICODE
#define print_cell(win, blank) \
if (val) \
@@ -24,8 +53,8 @@ extern mmask_t mbitmask;
typedef int (*input_f)(int);
-/*
- * @breaf A item in a menu
+/**
+ * @brief A item in a menu
*
* It's intended to be used with display_menu().
*/
@@ -34,16 +63,16 @@ struct menu_T {
char *name; ///< name of the menu item
};
-/*
- * @breaf A item in a interactive menu
+/**
+ * @brief A item in a interactive menu
*
* It's intended to be used with display_imenu().
*/
struct imenu_T {
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
+ 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
};
int input(WINDOW *win, char *buffer, int size, input_f crit);
diff --git a/include/file.h b/include/file.h
@@ -1,3 +1,10 @@
+/**
+ * @file file.h
+ * @author Dimitrije Dobrota
+ * @date 19 June 2022
+ * @brief File interface
+ */
+
#ifndef FILE_H
#define FILE_H
diff --git a/include/game.h b/include/game.h
@@ -1,3 +1,10 @@
+/**
+ * @file game.h
+ * @author Dimitrije Dobrota
+ * @date 19 June 2022
+ * @brief Game interface
+ */
+
#ifndef GAME_H
#define GAME_H
diff --git a/include/main.h b/include/main.h
@@ -1,9 +1,6 @@
#ifndef MAIN_H
#define MAIN_H
-
-extern struct window_T *menu_w;
-
void save(void);
void load_pattern(void);
void save_pattern(void);
diff --git a/include/pattern.h b/include/pattern.h
@@ -1,10 +1,17 @@
+/**
+ * @file pattern.h
+ * @author Dimitrije Dobrota
+ * @date 19 June 2022
+ * @brief Pattern interface and types
+ */
+
#ifndef PATTERN_H
#define PATTERN_H
#include "stdlib.h"
/**
- * @brief Structure representing one cell pattern to be used in a help menu
+ * @brief Structure representing one cell pattern to be used in the help menu
*/
typedef struct pattern_T {
char *cells; ///< string where 1 represents a living cell and 0 a dead one,
@@ -14,6 +21,7 @@ typedef struct pattern_T {
int width; ///< pattern width , used for cache, no need to fill manually
} * pattern_T;
+/// Game title using cells
struct pattern_T title = {
"011111000000000000000000000000000000000000000000010000000000000000000000 "
"100000100011000100001011111100000111100111111000010000000101111110111111 "
@@ -27,6 +35,7 @@ struct pattern_T title = {
0,
};
+/// Game keybindings
struct pattern_T games[] = {
{ "", "Game", 0, 0},
{ "p", "play/pause", 0, 0},
@@ -47,12 +56,13 @@ struct pattern_T games[] = {
{ "q", "cancel", 0, 0},
};
+/// Still cell patterns
struct pattern_T stills[] = {
{ "11 11", "block", 0, 0},
{ "1011 1101", "Snake", 0, 0},
{ "010 101 010", "Tub", 0, 0},
{ "110 101 010", "Boat", 0, 0},
- { "0110 1001 0110", "Behive", 0, 0},
+ { "0110 1001 0110", "Beehive", 0, 0},
{ "1100 1001 0011", "Carrier", 0, 0},
{ "11000 10011 01101", "Shillelagh", 0, 0},
{ "110 1001 1001 0110", "Pond", 0, 0},
@@ -62,6 +72,7 @@ struct pattern_T stills[] = {
{"00100 01010 01010 11011", "Hat", 0, 0},
};
+/// Oscillator cell patterns
struct pattern_T oscillators[] = {
{ "0111 1110", "Toad", 0, 0},
{ "010 010 010", "Blinker", 0, 0},
@@ -72,6 +83,7 @@ struct pattern_T oscillators[] = {
{"11000011 10100101 00100100 10100101 11000011", "Spark coil", 0, 0},
};
+/// Spaceship cell patterns
struct pattern_T spaceships[] = {
{ "010 001 111", "Glider", 0},
{ "01001 10000 10001 11110", "Lightweight", 0},
@@ -79,6 +91,7 @@ struct pattern_T spaceships[] = {
{"0001100 0100001 1000000 1000001 1111110", "Heavyweight", 0},
};
+/// Methuselah cell patterns
struct pattern_T methuselahs[] = {
{ "111 101 101", "Piheptomino", 0},
{ "1011 1110 0100", "B-Heptomino", 0},
@@ -97,6 +110,7 @@ typedef struct pattern_group_T {
int size; ///< number of elements in a group
} pattern_group_T;
+/// Pattern group containing all of the patterns for the help menu
struct pattern_group_T pattern_groups[] = {
{"Key bindings", games, sizeof(games) / sizeof(struct pattern_T)},
{ "Still", stills, sizeof(stills) / sizeof(struct pattern_T)},
@@ -105,8 +119,10 @@ struct pattern_group_T pattern_groups[] = {
{ "Methuselah", methuselahs, sizeof(methuselahs) / sizeof(struct pattern_T)},
};
+/// Size of pattern_groups
int pattern_groups_s = sizeof(pattern_groups) / sizeof(pattern_group_T);
+/// Get the pattern height
int pattern_height(pattern_T pattern) {
int count = 0;
for (char *p = pattern->cells; *p != '\0'; p++)
@@ -116,6 +132,7 @@ int pattern_height(pattern_T pattern) {
return count;
}
+/// Get the pattern width
int pattern_width(pattern_T pattern) {
int count = 0;
for (char *p = pattern->cells; *p != ' ' && *p != '\0'; p++)
diff --git a/include/utils.h b/include/utils.h
@@ -1,38 +1,38 @@
+/**
+ * @file utils.h
+ * @author Dimitrije Dobrota
+ * @date 19 June 2022
+ * @brief Common macros for use in other modules
+ */
+
#ifndef UTILS_H
#define UTILS_H
-#include <curses.h>
-
#include "display.h"
-#define MAX(a, b) ((a > b) ? a : b)
-#define MIN(a, b) ((a < b) ? a : b)
-#define CLAMP(a, x, y) ((a) = (MAX(x, MIN(a, y))))
+/// maximum of the two numbers
+#define MAX(a, b) ((a > b) ? a : b)
+
+/// minimum of the two numbers
+#define MIN(a, b) ((a < b) ? a : b)
+
+/// clamp the number a between x and y
+#define CLAMP(a, x, y) ((a) = (MAX(x, MIN(a, y))))
+
+/// clamp the value of a between x and y without assignment
#define ACLAMP(a, x, y) (MAX(x, MIN(a, y)))
-#define WCLAMP(a, x) ((a + x) % x)
-
-#ifdef _WIN32
-#define is_term_resized(a, b) is_termresized()
-#define usleep(a) _sleep(0.5)
-#define HANDLE_RESIZE \
- { \
- resize_term(0, 0); \
- handle_winch(10); \
- }
-#else
-#define HANDLE_RESIZE \
- { handle_winch(10); }
-#endif
+/// clamp with wrapping
+#define WCLAMP(a, x) ((a + x) % x)
+
+/// Check if compiled with Unicode support
#ifdef NO_UNICODE
#define UNICODE 0
#else
#define UNICODE 1
#endif
-#define MAX_SCREEN_H 512
-#define MAX_SCREEN_W 1888
-
+/// Check for memory error, and abort
#define MEM_CHECK(x) \
if ((x) == NULL) { \
display_stop(); \
@@ -40,6 +40,7 @@
abort(); \
}
+/// Check for file error, and abort
#define FILE_CHECK(x) \
if ((x) == NULL) { \
display_stop(); \
diff --git a/include/window.h b/include/window.h
@@ -1,3 +1,10 @@
+/**
+ * @file window.h
+ * @author Dimitrije Dobrota
+ * @date 19 June 2022
+ * @brief Window interface
+ */
+
#ifndef WINDOW_H
#define WINDOW_H
@@ -23,14 +30,14 @@ void window_settings(WINDOW *win);
void window_unsplit(T self);
void window_update_children(T self);
-// Setters and Gettern
+// Setters and Getters
T window_sibiling(T self);
WINDOW *window_win(T self);
int window_height(T self);
-int window_wight(T self);
+int window_width(T self);
int window_x(T self);
int window_y(T self);
void window_set_title(T self, char *title);
diff --git a/src/display.c b/src/display.c
@@ -7,7 +7,7 @@
* 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
+ * window_T MAIN_w as the entry point for other windows and display calls. It
* handles the display of menus and user input.
*/
#include <curses.h>
@@ -180,7 +180,7 @@ void display_title(window_T wind, int y) {
title.height = (!title.height) ? pattern_height(&title) : title.height;
title.width = (!title.width) ? pattern_width(&title) : title.width;
- int max_w = window_wight(wind);
+ int max_w = window_width(wind);
if (title.width * 2 < max_w)
print_pattern(win, &title, &y, (max_w - title.width * 2) / 2);
wrefresh(win);
@@ -391,7 +391,7 @@ void display_patterns(window_T wind) {
redraw:;
int CLINES = LINES, CCOLS = COLS;
WINDOW *win = window_win(wind);
- int ph = window_height(wind), pw = window_wight(wind);
+ int ph = window_height(wind), pw = window_width(wind);
int y, x, maxi, max_x;
x = x_start;
diff --git a/src/file.c b/src/file.c
@@ -5,7 +5,7 @@
* @brief This file contains functions for handling save files
*
* This file aims to provide a simple interface for interacting with the
- * filesystem on Linux and Windows systems. After proper game directory has been
+ * 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.
diff --git a/src/game.c b/src/game.c
@@ -219,7 +219,7 @@ int display_select(window_T wind) {
new = win;
}
- int ph = window_height(wind), pw = window_wight(wind) / 2;
+ int ph = window_height(wind), pw = window_width(wind) / 2;
nodelay(stdscr, 0);
while (TRUE) {
int start_i = MIN(cursor_offset_y, current_offset_y);
@@ -276,7 +276,7 @@ int display_select(window_T wind) {
toggleAt(cord(y_at(i)), cord(x_at(j)));
goto end;
- // confirm and save slection
+ // confirm and save selection
case '\n':
for_each_cell(start_i, end_i + 1, start_j, end_j + 1)
saveCell(cord(y_at(i)), cord(x_at(j)));
@@ -328,7 +328,7 @@ end:;
* This function is interactive:
* - Use p to play/pause the simulation
* - Use the arrow keys to move the screen around
- * - Use -/+ to decrease or increase the nums of evolutions before displaying
+ * - Use -/+ to decrease or increase the numbs of evolutions before displaying
* change
* - Use [/] to decrease or increase time wait before update
* - Use q or esc to return to the main menu
@@ -377,11 +377,11 @@ redraw:;
if (!wrap) {
game_w = window_center(screen_w, window_height(screen_w),
- window_wight(screen_w), mode_name);
+ window_width(screen_w), mode_name);
}
WINDOW *game_W = window_win(game_w);
- win_height = window_height(game_w), win_width = window_wight(game_w) / 2;
+ win_height = window_height(game_w), win_width = window_width(game_w) / 2;
window_clear(menu_w);
window_clear(screen_w);
@@ -466,7 +466,7 @@ redraw:;
gen_step--;
break;
- // change refreshrate
+ // change refresh rate
case ']':
time_const += time_step;
break;
@@ -626,7 +626,6 @@ redraw:;
}
end_t = clock();
}
- flushinp();
}
end:;
window_unsplit(menu_w);
diff --git a/src/window.c b/src/window.c
@@ -8,7 +8,7 @@
* tree of windows used for recalculating the ncurses WINDOW position in
* dimension when the terminal has been resized. It's possible to "split" the
* current window in two using a given ration or fixed size, as well as create
- * a centered subwindow. It makes some of the tree data accessible via function
+ * a centered sub-window. It makes some of the tree data accessible via function
* so that other functions can know about the sizes and adapt to them.
*/
@@ -47,9 +47,9 @@ struct window_T {
};
/**
- * @breif Apply settings, draw a border, print title for a give window
+ * @brief Apply settings, draw a border, print title for a give window
*
- * @param title: title to be prinded unless NULL
+ * @param title: title to be printed unless NULL
*/
void WINDOW_init(WINDOW *win, char *title) {
window_settings(win);
@@ -86,8 +86,8 @@ T window_sibiling(T self) { return self->sibling; }
/// Getter: return the height of the current window
int window_height(T self) { return H(self) - 2; }
-/// Getter: return the width of a current window
-int window_wight(T self) { return W(self) - 2; }
+/// Getter: return the of a current window
+int window_width(T self) { return W(self) - 2; }
/// Getter: return the x coordinate of the current window
int window_x(T self) { return X(self); }
@@ -104,7 +104,7 @@ void window_set_title(T self, char *title) { self->title = title; }
/**
* @brief create new ncurses WINDOW to the specification with default settings
*
- * New ncruses WINDOW is created with newwin and it should be deleted with
+ * New ncurses WINDOW is created with newwin and it should be deleted with
* delwin. Setting are applied with the call to WINDOW_INIT
*/
WINDOW *window_win_new(T self) {
@@ -148,7 +148,7 @@ void window_free(T self) {
}
/**
- * @brief Delete all children and subchildren of a window
+ * @brief Delete all children and sub-children of a window
*/
void window_unsplit(T self) {
window_free(self->c1);
@@ -162,7 +162,7 @@ void window_unsplit(T self) {
* children
*
* This function takes care of calculation for two windows in a given ration or
- * fixed size, and single subwindow.
+ * fixed size, and single sub-window.
* If a given windows has 2 children then they are split with the following
* rule:
* - If mod[0] is 0, two created windows will be side by side
@@ -234,7 +234,7 @@ void window_calc_children(T self) {
/**
* @brief Split the window in a given ration into two windows with a name
*
- * @param hor: should the split line be horizontal or verical
+ * @param hor: should the split line be horizontal or vertical
* @param a: ration of the first window
* @param b: ration of the second window
* @param name1: name of the first window
@@ -270,11 +270,11 @@ T window_split(T self, int hor, int a, int b, char *name1, char *name2) {
}
/**
- * @brief Create a subwindow that will be of a given size or made to fit it's
+ * @brief Create a sub-window that will be of a given size or made to fit it's
* parent
*
* @param h: desired height of a new window_T
- * @param w: desired width of a new window_T
+ * @param w: desired of a new window_T
* @param name: name of the new window_T
*/
T window_center(T self, int h, int w, char *name) {
@@ -294,7 +294,7 @@ T window_center(T self, int h, int w, char *name) {
}
/**
- * @brief Recursevly recalculate the size of each child and make new ncurses
+ * @brief Recursively recalculate the size of each child and make new ncurses
* WINDOW
*/
void window_update_children(T self) {
@@ -343,7 +343,7 @@ void window_settings(WINDOW *win) {
}
/**
- * @brief Check if cordinates are in the window
+ * @brief Check if coordinates are in the window
*/
int window_clicked(T self, int y, int x) {
if (x <= X(self) || y <= Y(self))
@@ -360,7 +360,7 @@ int window_clicked(T self, int y, int x) {
* text of len n will be centered
*
* @param y: y position
- * @n lenfth of the text to be centered
+ * @n length of the text to be centered
*/
void wcenter_horizontal(T window, int y, int n) {
wmove(window->win, y, (W(window) - n - 2) / 2 + 1);