From 00f8b889420ad3c75fe1e86f011c4d92a966de3a Mon Sep 17 00:00:00 2001 From: Laurent Mazet Date: Tue, 27 Aug 2024 00:15:55 +0200 Subject: [PATCH 1/1] initial commit --- block.c | 187 ++++++++++++++++++++++++++++++++ block.h | 45 ++++++++ color.c | 121 +++++++++++++++++++++ color.h | 39 +++++++ constant.c | 78 ++++++++++++++ constant.h | 24 +++++ debug.c | 5 + debug.h | 21 ++++ display.c | 271 ++++++++++++++++++++++++++++++++++++++++++++++ display.h | 39 +++++++ function.c | 311 +++++++++++++++++++++++++++++++++++++++++++++++++++++ function.h | 54 ++++++++++ makefile | 190 ++++++++++++++++++++++++++++++++ reversi.c | 194 +++++++++++++++++++++++++++++++++ type.h | 28 +++++ 15 files changed, 1607 insertions(+) create mode 100644 block.c create mode 100644 block.h create mode 100644 color.c create mode 100644 color.h create mode 100644 constant.c create mode 100644 constant.h create mode 100644 debug.c create mode 100644 debug.h create mode 100644 display.c create mode 100644 display.h create mode 100644 function.c create mode 100644 function.h create mode 100644 makefile create mode 100644 reversi.c create mode 100644 type.h diff --git a/block.c b/block.c new file mode 100644 index 0000000..9c9fca8 --- /dev/null +++ b/block.c @@ -0,0 +1,187 @@ +#include + +#include "block.h" + +typedef enum { + _black = 0, + _blue, + _green, + _cyan, + _red, + _magenta, + _yellow, + _white +} _color_t; + +static int _color_num (int fg, int bg) +{ + return (1 << 6) | ((7 & bg) << 3) | (7 & fg); +} +static int _color_trans (_color_t c) +{ + int color; + switch (7 & c) { + case _black: + color = COLOR_BLACK; + break; + case _blue: + color = COLOR_BLUE; + break; + case _green: + color = COLOR_GREEN; + break; + case _cyan: + color = COLOR_CYAN; + break; + case _red: + color = COLOR_RED; + break; + case _magenta: + color = COLOR_MAGENTA; + break; + case _yellow: + color = COLOR_YELLOW; + break; + case _white: + color = COLOR_WHITE; + break; + } + return color; +} + +static void _init_color_pairs () { + int fg, bg; + for (bg = 0; bg < 8; bg++) { + for (fg = 0; fg < 8; fg ++) { + init_pair (_color_num (fg, bg), _color_trans (fg), _color_trans (bg)); + } + } +} + +void mvaddcb (int y, int x, cblock_t color) +{ + int init = 1; + if (init) { + _init_color_pairs (); + init = 0; + } + + int symb = ACS_CKBOARD; + switch (color) { + case black: + case gray: + case blue: + case green: + case cyan: + case red: + case magenta: + case brown: + symb = ' '; + break; + default: + symb = ACS_CKBOARD; + } + + int num; + switch (color) { + case black: + case darkgray: + num = _color_num (_white, _black); + break; + case gray: + case white: + num = _color_num (_white, _white); + break; + case darkerblue: + case darkblue: + num = _color_num (_blue, _black); + break; + case darkergreen: + case darkgreen: + num = _color_num (_green, _black); + break; + case darkercyan: + case darkcyan: + num = _color_num (_cyan, _black); + break; + case darkerred: + case darkred: + num = _color_num (_red, _black); + break; + case darkermagenta: + case darkmagenta: + num = _color_num (_magenta, _black); + break; + case darkbrown: + case darkeryellow: + num = _color_num (_yellow, _black); + break; + case blue: + case lightblue: + case lighterblue: + num = _color_num (_blue, _white); + break; + case green: + case lightgreen: + case lightergreen: + num = _color_num (_green, _white); + break; + case cyan: + case lightcyan: + case lightercyan: + num = _color_num (_cyan, _white); + break; + case red: + case lightred: + case lighterred: + num = _color_num (_red, _white); + break; + case magenta: + case lightmagenta: + case lightermagenta: + num = _color_num (_magenta, _white); + break; + case brown: + case darkyellow: + case yellow: + num = _color_num (_yellow, _white); + break; + //default: + // num = _color_num (_white, _black); + } + + int state; + switch (color) { + case blue: + case green: + case cyan: + case red: + case magenta: + case brown: + state = A_REVERSE; + break; + case white: + case darkblue: + case darkgreen: + case darkcyan: + case darkred: + case darkmagenta: + case darkeryellow: + case lighterblue: + case lightergreen: + case lightercyan: + case lighterred: + case lightermagenta: + case yellow: + state = A_BOLD; + break; + default: + state = A_NORMAL; + } + + attron (COLOR_PAIR (num) | state); + mvaddch (y, x, symb); + attroff (COLOR_PAIR (num) | state); +} + +/* vim: set ts=4 sw=4 et: */ diff --git a/block.h b/block.h new file mode 100644 index 0000000..481bcc5 --- /dev/null +++ b/block.h @@ -0,0 +1,45 @@ +#ifndef __BLOCK_H__ +#define __BLOCK_H__ + +typedef enum { + black, + darkgray, + gray, + white, + darkerblue, + darkblue, + blue, + lightblue, + lighterblue, + darkergreen, + darkgreen, + green, + lightgreen, + lightergreen, + darkercyan, + darkcyan, + cyan, + lightcyan, + lightercyan, + darkerred, + darkred, + red, + lightred, + lighterred, + darkermagenta, + darkmagenta, + magenta, + lightmagenta, + lightermagenta, + darkbrown, + brown, + darkeryellow, + darkyellow, + yellow, +} cblock_t; + +void mvaddcb (int y, int x, cblock_t color); + +#endif /* __BLOCK_H__ */ + +/* vim: set ts=4 sw=4 et: */ diff --git a/color.c b/color.c new file mode 100644 index 0000000..05e28fb --- /dev/null +++ b/color.c @@ -0,0 +1,121 @@ +#include + +#include "color.h" + +static void _init_color_pairs () { + init_pair (1, COLOR_WHITE, COLOR_BLACK); + init_pair (2, COLOR_BLUE, COLOR_BLACK); + init_pair (3, COLOR_GREEN, COLOR_BLACK); + init_pair (4, COLOR_CYAN, COLOR_BLACK); + init_pair (5, COLOR_RED, COLOR_BLACK); + init_pair (6, COLOR_MAGENTA, COLOR_BLACK); + init_pair (7, COLOR_YELLOW, COLOR_BLACK); + init_pair (8, COLOR_WHITE, COLOR_WHITE); + init_pair (9, COLOR_BLUE, COLOR_WHITE); + init_pair (10, COLOR_GREEN, COLOR_WHITE); + init_pair (11, COLOR_CYAN, COLOR_WHITE); + init_pair (12, COLOR_RED, COLOR_WHITE); + init_pair (13, COLOR_MAGENTA, COLOR_WHITE); + init_pair (14, COLOR_YELLOW, COLOR_WHITE); + init_pair (15, COLOR_BLACK, COLOR_WHITE); +} + +void setcolor (ctext_t color) +{ + static int init = 1; + if (init) { + _init_color_pairs (); + init = 0; + } + + attroff (A_BOLD); + + int num; + switch (color) { + case gray_black: + case white_black: + num = 1; + break; + case blue_black: + case lightblue_black: + num = 2; + break; + case green_black: + case lightgreen_black: + num = 3; + break; + case cyan_black: + case lightcyan_black: + num = 4; + break; + case red_black: + case lightred_black: + num = 5; + break; + case magenta_black: + case lightmagenta_black: + num = 6; + break; + case brown_black: + case yellow_black: + num = 7; + break; + case white_gray: + num = 8; + break; + case blue_gray: + case lightblue_gray: + num = 9; + break; + case green_gray: + case lightgreen_gray: + num = 10; + break; + case cyan_gray: + case lightcyan_gray: + num = 11; + break; + case red_gray: + case lightred_gray: + num = 12; + break; + case magenta_gray: + case lightmagenta_gray: + num = 13; + break; + case brown_gray: + case yellow_gray: + num = 14; + break; + case black_gray: + num = 15; + break; + } + + int state; + switch (color) { + case white_black: + case lightblue_black: + case lightgreen_black: + case lightcyan_black: + case lightred_black: + case lightmagenta_black: + case yellow_black: + case white_gray: + case lightblue_gray: + case lightgreen_gray: + case lightcyan_gray: + case lightred_gray: + case lightmagenta_gray: + case yellow_gray: + state = A_BOLD; + break; + default: + state = A_NORMAL; + } + + attron (COLOR_PAIR (num) | state); + +} + +/* vim: set ts=4 sw=4 et: */ diff --git a/color.h b/color.h new file mode 100644 index 0000000..0b2d25a --- /dev/null +++ b/color.h @@ -0,0 +1,39 @@ +#ifndef __COLOR_H__ +#define __COLOR_H__ + +typedef enum { + gray_black = 0, + blue_black, + green_black, + cyan_black, + red_black, + magenta_black, + brown_black, + white_black, + lightblue_black, + lightgreen_black, + lightcyan_black, + lightred_black, + lightmagenta_black, + yellow_black, + blue_gray, + green_gray, + cyan_gray, + red_gray, + magenta_gray, + brown_gray, + white_gray, + lightblue_gray, + lightgreen_gray, + lightcyan_gray, + lightred_gray, + lightmagenta_gray, + yellow_gray, + black_gray +} ctext_t; + +void setcolor (ctext_t color); + +#endif /* __COLOR_H__ */ + +/* vim: set ts=4 sw=4 et: */ diff --git a/constant.c b/constant.c new file mode 100644 index 0000000..3629180 --- /dev/null +++ b/constant.c @@ -0,0 +1,78 @@ +#include +#include + +#include "block.h" +#include "function.h" +#include "type.h" + +#include "constant.h" + +/* constants */ + +int height = 20; +int minwidth = 8; +int width = 10; +int maxwidth = 15; + +int nbdigit = 5; +int maxscor = 100000; +int nbholes = 2; + +int savelen = 12; +int xoffset = 1; +int yoffset = 1; + +/* blocks */ + +#define _nb_blocks_std 12 + +block_t _blocks_std[_nb_blocks_std] = { + {3, 3, yellow, " .... . "}, // F + {1, 5, blue, "...."}, // I + {2, 4, lightmagenta, ". . . .."}, // L + {2, 4, lightblue, " .... . "}, // N + {2, 3, lightgreen, " ....."}, // P + {3, 3, lightcyan, "... . . "}, // T + {3, 2, magenta, ". ...."}, // U + {3, 3, cyan, ". . ..."}, // V + {3, 3, lightergreen, ". .. .."}, // W + {3, 3, red, " . ... . "}, // X + {2, 4, darkblue, " ... . ."}, // Y + {3, 3, brown, ".. . .."}, // Z +}; + +block_t *getblocks (char *name, int *nb) +{ + block_t *pt = NULL; + + if (strcmp (name, "std") == 0) { + pt = _blocks_std; + *nb = _nb_blocks_std; + } + + return pt; +} + +/* board */ + +board_t *getboard (char *name) +{ + board_t *board = NULL; + + if (strcmp (name, "6x10") == 0) { + board = initboard (6, 10); + } else if (strcmp (name, "5x12") == 0) { + board = initboard (5, 12); + } else if (strcmp (name, "4x15") == 0) { + board = initboard (4, 15); + } else if (strcmp (name, "3x20") == 0) { + board = initboard (3, 20); + } else if (strcmp (name, "list") == 0) { + printf ("board: 6x10 5x12 4x15 3x20\n"); + board = (board_t *)(-1); + } + + return board; +} + +/* vim: set ts=4 sw=4 et: */ diff --git a/constant.h b/constant.h new file mode 100644 index 0000000..00de5ac --- /dev/null +++ b/constant.h @@ -0,0 +1,24 @@ +#ifndef __CONSTANT_H__ +#define __CONSTANT_H__ + +#include "type.h" + +/* global constants */ + +#ifndef __CONSTANT_C__ + +extern int savelen; +extern int xoffset; +extern int yoffset; + +#endif /* __CONSTANT_C__ */ + +/* block definitions */ + +block_t *getblocks (char *name, int *nb); + +board_t *getboard (char *name); + +#endif /* __CONSTANT_H__ */ + +/* vim: set ts=4 sw=4 et: */ diff --git a/debug.c b/debug.c new file mode 100644 index 0000000..b9eba44 --- /dev/null +++ b/debug.c @@ -0,0 +1,5 @@ +#include "debug.h" + +int verbose = 0; + +/* vim: set ts=4 sw=4 et: */ diff --git a/debug.h b/debug.h new file mode 100644 index 0000000..32dc0ca --- /dev/null +++ b/debug.h @@ -0,0 +1,21 @@ +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +/* constants */ + +#define DEBUG 3 +#define INFO 2 +#define WARNING 1 +#define ERROR 0 + +/* macros */ + +#define VERBOSE(level, statement...) do { if (level <= verbose) { statement; } } while(0) + +/* gobal variables */ + +extern int verbose; + +#endif /* __DEBUG_H__ */ + +/* vim: set ts=4 sw=4 et: */ diff --git a/display.c b/display.c new file mode 100644 index 0000000..f8d85a3 --- /dev/null +++ b/display.c @@ -0,0 +1,271 @@ +#include +#include +#include +#include + +#include "block.h" +#include "color.h" +#include "debug.h" +#include "function.h" +#include "type.h" + +#include "display.h" + +int _helpwindow (char *msg, int xoffset, int yoffset, int length) +{ + int i = 0; + int j = 0; + while ((msg) && (*msg != '\0')) { + if ((*msg == '\n') || (i == length)) { + i = 0; + j++; + } + if (*msg != '\n') { + mvaddch (yoffset + j, xoffset + i, *msg); + i++; + } + msg++; + } + return j; +} + +void _displaytitle (char *title, int xoffset, int yoffset) +{ + int i; + for (i = 0; title[i] != '\0'; i++) { + mvaddch (yoffset, xoffset + i, title[i]); + mvaddch (yoffset + 1, xoffset + i, ACS_HLINE); + } +} + +void _dobound (int xsize, int ysize, int xoffset, int yoffset) +{ + int i, j; + + for (i = 0; i < xsize; i++) { + mvaddch (yoffset - 1, xoffset + i, ACS_HLINE); + mvaddch (yoffset + ysize, xoffset + i, ACS_HLINE); + } + for (j = 0; j < ysize; j++) { + mvaddch (yoffset + j, xoffset - 1, ACS_VLINE); + mvaddch (yoffset + j, xoffset + xsize, ACS_VLINE); + } + mvaddch (yoffset - 1, xoffset - 1, ACS_ULCORNER); + mvaddch (yoffset + ysize, xoffset - 1, ACS_LLCORNER); + mvaddch (yoffset - 1, xoffset + xsize, ACS_URCORNER); + mvaddch (yoffset + ysize, xoffset + xsize, ACS_LRCORNER); +} + +int helpwindow (char *msg, int xoffset, int yoffset) +{ + _displaytitle ("Help message", xoffset, yoffset); + int length = strmaxlen (msg, '\n'); + int j = 2; + j += _helpwindow (msg, xoffset, yoffset + j, length); + + return j; +} + +void _put_color_block (int y, int x, char symb) +{ + switch (symb) { + case ' ': + mvaddcb (y, x, black); + break; + case '1': + mvaddcb (y, x, cyan); + break; + case '2': + mvaddcb (y, x, yellow); + break; + case '3': + mvaddcb (y, x, magenta); + break; + case '4': + mvaddcb (y, x, brown); + break; + case '5': + mvaddcb (y, x, blue); + break; + case '6': + mvaddcb (y, x, red); + break; + case '7': + mvaddcb (y, x, green); + break; + case '8': + mvaddcb (y, x, white); + break; + } +} + +void _element0 (board_t *board, int x, int y, int symb) +{ + _put_color_block (board->yoffset + y, board->xoffset + x, symb); +} + +void _element1 (board_t *board, int x, int y, int symb) +{ + _put_color_block (board->yoffset + y, board->xoffset + 2 * x, symb); + _put_color_block (board->yoffset + y, board->xoffset + 2 * x + 1, symb); +} + +void _element2 (board_t *board, int x, int y, int symb) +{ + _put_color_block (board->yoffset + 2 * y, board->xoffset + 2 * x, symb); + _put_color_block (board->yoffset + 2 * y, board->xoffset + 2 * x + 1, symb); + _put_color_block (board->yoffset + 2 * y + 1, board->xoffset + 2 * x, symb); + _put_color_block (board->yoffset + 2 * y + 1, board->xoffset + 2 * x + 1, symb); +} + +void _element3 (board_t *board, int x, int y, int symb) +{ + _put_color_block (board->yoffset + 2 * y, board->xoffset + 3 * x, symb); + _put_color_block (board->yoffset + 2 * y, board->xoffset + 3 * x + 1, symb); + _put_color_block (board->yoffset + 2 * y, board->xoffset + 3 * x + 2, symb); + _put_color_block (board->yoffset + 2 * y + 1, board->xoffset + 3 * x, symb); + _put_color_block (board->yoffset + 2 * y + 1, board->xoffset + 3 * x + 1, symb); + _put_color_block (board->yoffset + 2 * y + 1, board->xoffset + 3 * x + 2, symb); +} + +void _element (board_t *board, int x, int y, int symb) +{ + switch (board->scale) { + case 0: + _element0 (board, x, y, symb); + break; + case 1: + _element1 (board, x, y, symb); + break; + case 2: + _element2 (board, x, y, symb); + break; + case 3: + _element3 (board, x, y, symb); + break; + } +} + +void boardwindow (board_t *board, int mode) +{ + int i, j; + + setcolor (mode ? gray_black : black_gray); + _dobound (board->xsize, board->ysize, board->xoffset, board->yoffset); + setcolor (gray_black); + + for (i = 0; i < board->width; i++) { + for (j = 0; j < board->height; j++) { + _element (board, i, j, *getcell (board, i, j)); + } + } +} + +void displayblock (board_t *board, block_t *block, int x, int y) +{ + int i, j; + + if (x == -1) { + x = board->width / 2; + } + + if (y == -1) { + y = (board->height - block->height) / 2; + } + + for (i = 0; i < block->width; i++) { + for (j = 0; j < block->height; j++) { + if (*getcell (block, i, j) != ' ') { + _element (board, x - block->width / 2 + i, y + j, '0' + block->color); + } + } + } +} + +char *savewindow (int length, int xoffset, int yoffset) +{ + char *name = (char *) calloc (1, length + 1); + CHECKALLOC (name); + memset (name, ' ', length); + + setcolor (black_gray); + _dobound (length, 1, xoffset, yoffset); + setcolor (gray_black); + + int i = 0, j; + int stop = 0; + while (!stop) { + for (j = 0; j < length; j++) { + setcolor ((j == i) ? yellow_black : black_gray); + mvaddch (yoffset, xoffset + j, name[j]); + setcolor (gray_black); + } + int ch = getch (); + switch (ch) { + case '\n': + case '\r': + stop = 1; + break; + case KEY_BACKSPACE: + case KEY_DELETE: + case 127: + case '\b': + name[i] = ' '; + i--; + break; + case KEY_LEFT: + i--; + break; + case KEY_RIGHT: + i++; + break; + case KEY_ESC: + free (name); + name = NULL; + stop = 1; + break; + default: + if ((ch >= 32) && ( ch < 128)) { + name[i] = ch; + i++; + } + } + + if (i < 0) { + i = 0; + } + if (i >= length) { + i = length - 1; + } + } + + if (name) { + for (j = length - 1; j >= 0; j--) { + if (name[j] == ' ') { + name[j] = '\0'; + } + } + if (*name == '\0') { + free (name); + name = NULL; + } + } + + return name; +} + +void msgwindow (char *msg, int xoffset, int yoffset, int length) +{ + setcolor (gray_black); + _dobound ((length > 0) ? length : (int)strlen (msg), 1, xoffset, yoffset); + if (length > 0) { + int i; + for (i = 0; i < length; i++) { + mvaddch (yoffset, xoffset + i, ' '); + } + } + mvaddstr (yoffset, xoffset + ((length > 0) ? (length - (int)strlen (msg)) / 2 : 0), msg); + setcolor (black_gray); +} + +/* vim: set ts=4 sw=4 et: */ diff --git a/display.h b/display.h new file mode 100644 index 0000000..4cd615a --- /dev/null +++ b/display.h @@ -0,0 +1,39 @@ +#ifndef __DISPLAY_H__ +#define __DISPLAY_H__ + +#include "type.h" + +#define KEY_ESC 0x1b +#define KEY_DELETE 0x014a + +int _helpwindow (char *msg, int xoffset, int yoffset, int length); + +void _displaytitle (char *title, int xoffset, int yoffset); + +void _dobound (int xsize, int ysize, int xoffset, int yoffset); + +int helpwindow (char *msg, int xoffset, int yoffset); + +void _put_color_block (int y, int x, char symb); + +void _element0 (board_t *board, int x, int y, int symb); + +void _element1 (board_t *board, int x, int y, int symb); + +void _element2 (board_t *board, int x, int y, int symb); + +void _element3 (board_t *board, int x, int y, int symb); + +void _element (board_t *board, int x, int y, int symb); + +void boardwindow (board_t *board, int mode); + +void displayblock (board_t *board, block_t *block, int x, int y); + +char *savewindow (int length, int xoffset, int yoffset); + +void msgwindow (char *msg, int xoffset, int yoffset, int length); + +#endif /* __DISPLAY_H__ */ + +/* vim: set ts=4 sw=4 et: */ diff --git a/function.c b/function.c new file mode 100644 index 0000000..cfa5471 --- /dev/null +++ b/function.c @@ -0,0 +1,311 @@ +#include +#include +#include +#include + +#include "debug.h" +#include "type.h" + +#include "function.h" + +int strmaxlen (char *str, char ch) +{ + int len = 0; + char *end = NULL; + while ((end = strchr (str, ch)) != NULL) { + int l = (int)(end - str); + if (l > len) { + len = l; + } + str = end + 1; + } + return len; +} + +board_t *initboard (int width, int height) +{ + board_t *board = (board_t *) malloc (sizeof (board_t)); + CHECKALLOC (board); + board->tab = (char *) calloc (1, width * height + 1); + CHECKALLOC (board->tab); + memset (board->tab, ' ', width * height); + board->scale = 0; + board->xsize = board->width = width; + board->ysize = board->height = height; + board->xoffset = 0; + board->yoffset = 0; + board->current = -1; + board->next = -1; + return board; +} + +board_t *setscale (board_t *board, int scale) +{ + board->scale = scale; + switch (scale) { + case 0: + board->xsize = board->width; + board->ysize = board->height; + break; + case 1: + board->xsize = board->width * 2; + board->ysize = board->height; + break; + case 2: + board->xsize = board->width * 2; + board->ysize = board->height * 2; + break; + case 3: + board->xsize = board->width * 3; + board->ysize = board->height * 2; + break; + } + return board; +} + +void freeboard (board_t *board) +{ + if (board) { + free (board->tab); + } + free (board); +} + +int _makecomments (char *buffer, board_t *board) +{ + int i, j, l = 0; + for (j = 0; j < board->height; j++) { + l += sprintf (buffer + l, "rem: \""); + for (i = 0; i < board->width; i++) { + l += sprintf (buffer + l, "%c", *getcell (board, i, j)); + } + l += sprintf (buffer + l, "\"\n"); + } + return l; +} + +char *saveboard (board_t *board) +{ + int size = 6 * (8 + 3) + 8 + board->width * board->height + 1; + VERBOSE (INFO, size += board->height * (8 + board->width)); + + char *buffer = (char *) calloc (size, 1); + CHECKALLOC (buffer); + + int l = sprintf (buffer, "width: %d\n", board->width); + l += sprintf (buffer + l, "height: %d\n", board->height); + l += sprintf (buffer + l, "tab: \"%s\"\n", board->tab); + l += sprintf (buffer + l, "current: %d\n", board->current); + l += sprintf (buffer + l, "lines: %d\n", board->lines); + l += sprintf (buffer + l, "next: %d\n", board->next); + l += sprintf (buffer + l, "score: %d\n", board->score); + + VERBOSE (INFO, _makecomments (buffer + l, board)); + + return buffer; +} + +int writedata (char *filename, char *data) +{ + int ret = 0; + + FILE *fd = fopen (filename, "w"); + if (fd) { + size_t n = fwrite (data, strlen (data), 1, fd); + fclose (fd); + ret = (n == strlen (data)); + } else { + VERBOSE (WARNING, printf ("can't write file (%s)\n", filename)); + } + + return ret; +} + +char *readdata (char *filename) +{ + char *buffer = NULL; + FILE *fd = fopen (filename, "r"); + if (fd) { + fseek (fd, 0, SEEK_END); + int size = ftell (fd); + buffer = (char *) calloc (size + 1, 1); + CHECKALLOC (buffer); + + fseek (fd, 0, SEEK_SET); + int nb = fread (buffer, 1, size, fd); + if (nb != size) { + VERBOSE (WARNING, printf ("can't fully read file (%s)\n", filename)); + } + fclose (fd); + } + + return buffer; +} + +char *atos (char *str) +{ + char *ret = NULL; + + if (*str == '"') { + char *ptr = ++str; + while ((*ptr != '"') && (*ptr != '\0')) { + ptr++; + } + if (*ptr == '"') { + *ptr = '\0'; + ret = str; + } + } + + return ret; +} + +board_t *loadboard (char *str) +{ + int width = 0; + int height = 0; + char *tab = NULL; + int current = -1; + int lines = 0; + int next = -1; + int score = 0; + + char *saveptr1, *saveptr2; + + char *line = strtok_r (str, "\n", &saveptr1); + while (line) { + + char *keyword = strtok_r (line, ":", &saveptr2); + + char *value = line + strlen (keyword) + 1; + while (*value == ' ') { + value++; + } + + if (strcmp (keyword, "width") == 0) { + width = atoi (value); + } else if (strcmp (keyword, "height") == 0) { + height = atoi (value); + } else if (strcmp (keyword, "tab") == 0) { + tab = atos (value); + } else if (strcmp (keyword, "current") == 0) { + current = atoi (value); + } else if (strcmp (keyword, "lines") == 0) { + lines = atoi (value); + } else if (strcmp (keyword, "next") == 0) { + next = atoi (value); + } else if (strcmp (keyword, "score") == 0) { + score = atoi (value); + } else if (strcmp (keyword, "rem") == 0) { + /* nothing to do with remark */ + } else { + VERBOSE (WARNING, printf ("unknown keyword: %s\n", keyword)); + } + + line = strtok_r (NULL, "\n", &saveptr1); + } + + board_t *board = NULL; + if ((tab) && (strlen (tab) == (size_t)(width * height))) { + board = initboard (width, height); + memcpy (board->tab, tab, width * height); + board->current = current; + board->lines = lines; + board->next = next; + board->score = score; + } + + return board; +} + +block_t *initblock (int width, int height) +{ + block_t *block = (block_t *) malloc (sizeof (block_t)); + CHECKALLOC (block); + block->tab = (char *) calloc (1, width * height + 1); + CHECKALLOC (block->tab); + memset (block->tab, ' ', width * height); + block->width = width; + block->height = height; + return block; +} + +block_t *changeblock (block_t *dest, block_t *src) +{ + block_t *ret = NULL; + if (dest && src) { + free (dest->tab); + memcpy (dest, src, sizeof (block_t)); + dest->tab = strdup (src->tab); + CHECKALLOC (dest->tab); + ret = dest; + } + return ret; +} + +block_t *copyblock (block_t *block) +{ + block_t *newblock = initblock (block->width, block->height); + char *tab = newblock->tab; + memcpy (newblock, block, sizeof (block_t)); + newblock->tab = tab; + memcpy (newblock->tab, block->tab, block->width * block->height + 1); + return newblock; +} + +void freeblock (block_t *block) +{ + if (block) { + free (block->tab); + } + free (block); +} + +block_t *rotateblock (block_t *block, int rot) +{ + int i, j; + + rot = (rot > 0) ? rot % 4 : ((1 - rot / 4) * 4 + rot) % 4; + + block_t *newblock = NULL; + + switch (rot) { + case 0: + newblock = copyblock (block); + break; + case 1: + newblock = initblock (block->height, block->width); + newblock->color = block->color; + for (i = 0; i < block->width; i++) { + for (j = 0; j < block->height; j++) { + *getcell (newblock, block->height - 1 - j, i) = *getcell (block, i, j); + } + } + break; + case 2: + newblock = initblock (block->width, block->height); + newblock->color = block->color; + for (i = 0; i < block->width; i++) { + for (j = 0; j < block->height; j++) { + *getcell (newblock, block->width - 1 - i, block->height - 1 - j) = *getcell (block, i, j); + } + } + break; + case 3: + newblock = initblock (block->height, block->width); + newblock->color = block->color; + for (i = 0; i < block->width; i++) { + for (j = 0; j < block->height; j++) { + *getcell (newblock, j, block->width - 1 - i) = *getcell (block, i, j); + } + } + break; + } + + changeblock (block, newblock); + freeblock (newblock); + + return block; +} + +/* vim: set ts=4 sw=4 et: */ diff --git a/function.h b/function.h new file mode 100644 index 0000000..335fca6 --- /dev/null +++ b/function.h @@ -0,0 +1,54 @@ +#ifndef __FUNCTION_H__ +#define __FUNCTION_H__ + +#include + +#include "type.h" + +#define CHECKALLOC(ptr) \ + do { \ + if ((ptr) == NULL) { \ + VERBOSE (ERROR, fprintf (stderr, "can't get enough memory for '%s'\n", #ptr)); \ + exit (1); \ + } \ + } while (0) + +#define max(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a > _b ? _a : _b; }) + +#define min(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; }) + +#define getcell(b, x, y) ({ __typeof__ (b) _b = (b); int _x = (x), _y = (y);_b->tab + _x + _b->width * _y; }) + +int strmaxlen (char *str, char ch); + +board_t *initboard (int width, int height); + +board_t *setscale (board_t *board, int scale); + +void freeboard (board_t *board); + +int _makecomments (char *buffer, board_t *board); + +char *saveboard (board_t *board); + +int writedata (char *filename, char *data); + +char *readdata (char *filename); + +char *atos (char *str); + +board_t *loadboard (char *str); + +block_t *initblock (int width, int height); + +block_t *changeblock (block_t *dest, block_t *src); + +block_t *copyblock (block_t *block); + +void freeblock (block_t *block); + +block_t *rotateblock (block_t *block, int rot); + +#endif /* __FUNCTION_H__ */ + +/* vim: set ts=4 sw=4 et: */ diff --git a/makefile b/makefile new file mode 100644 index 0000000..f4e65d8 --- /dev/null +++ b/makefile @@ -0,0 +1,190 @@ +# Default flags + +CC = gcc + +#INCLUDES = -I../debug -D__MEMORY_ALLOCATION__ +INCLUDES = +OFLAGS = -O4 -Os +#OFLAGS = -O4 -ffast-math -finline-functions +#OFLAGS = -O4 -finline-functions +#OFLAGS += -mtune=pentium3 -mmmx -msse -msse2 -m3dnow +#OFLAGS += -minline-all-stringops -fsingle-precision-constant +#OFLAGS += -malign-double +CFLAGS += -W -Wall -Wextra -g +#CFLAGS += -std=c99 -D_XOPEN_SOURCE=500 +CFLAGS += $(OFLAGS) $(INCLUDES) $(OPTIONS) +LDFLAGS += -g $(LDOPTS) $(OPTIONS) + +LDOPT = linker +MV = mv +ifneq (, $(findstring linux, $(MAKE_HOST))) +# Linux +else ifneq (, $(findstring mingw, $(MAKE_HOST))) +# Windows MinGw +#LDLIBS += -lws2_32 +LDOPT = winlnk +else ifneq (, $(findstring cygwin, $(MAKE_HOST))) +# Windows CygWin +LDOPT = winlnk +else ifneq (, $(findstring msdos, $(MAKE_HOST))) +# MSDOS +LDOPT = doslnk +MV = move +endif + +# Targets + +ALLEXE = +ALLEXE += reversi + +SHELL = bash + +#MAKE = mingw32-make +MAKEFLAGS += -s +include $(wildcard .makefile) + +# Functions + +TITLE = echo -en "\033[0;1m$(strip $(1))\033[0;0m:\t" +PASS = echo -e "\033[1;32m$(strip $(1))\033[0;0m" +WARN = echo -e "\033[1;33m$(strip $(1))\033[0;0m" +FAIL = echo -e "\033[1;31m$(strip $(1))\033[0;0m" + +MKDIR = mkdir -p $(1) && chmod a+rx,go-w $(1) + +INSTALL = test -d `dirname $(2)` || $(call MKDIR, `dirname $(2)`) && cp -pa $(1) $(2) && chmod a+rX,go-w $(2) + +VALID = $(call TITLE, $(1)) && $(2) && $(call PASS, SUCCESS) || { $(call FAIL, FAILED); test; } + +GETCOMMENTS = awk '/\/\*\s*$(1):/,/\*\// { sub(/.*\/\*\s*$(1):/, ""); sub (/\s*\*\/.*/, ""); print } /\/\/\s*$(1):/ {sub (/.*\/\/\s*$(1):/, ""); print }' $(2) +#GETCOMMENTS = perl -- getcomments.pl -p='$(1):\s' -f='%' $(2) + +## Generic rules + +all: depends + $(MAKE) $(ALLEXE:%=%.exe) + +count: + wc $(wildcard *.c *.h) $(MAKEFILE_LIST) + +clean: + $(call TITLE, "Cleaning") + touch clean + rm -f clean $(wildcard *.d *.ld *.log *.o *.test *~ .exec_* gmon.out _) + $(call PASS, SUCCESS) + +depends: $(patsubst %.c, %.d, $(wildcard *.c)) $(patsubst %, %.ld, $(ALLEXE)) + +gcovs: + $(MAKE) $(addprefix gcov_,$(ALLEXE)) + +gprofs: + $(MAKE) $(addprefix gprof_,$(ALLEXE)) + +purge: clean + $(call TITLE, "Purging") + touch purge + rm -f purge $(ALLEXE:%=%.exe) + $(call PASS, SUCCESS) + +valgrinds: + $(MAKE) all + $(MAKE) $(addprefix valgrind_,$(ALLEXE)) + +wipe: purge + $(call TITLE, "Wiping") + touch wipe + rm -f wipe $(wildcard *.gcda *.gcno *.gcov *.glog) + $(call PASS, SUCCESS) + +tests: + -rm -f $(ALLEXE) + $(MAKE) all + $(MAKE) $(addprefix test_,$(ALLEXE)) + +## Main rules + +include $(wildcard *.d) +include $(wildcard *.ld) + +gcov_%: + $(MAKE) purge + $(MAKE) depends + OPTIONS="-coverage -O0" $(MAKE) ${@:gcov_%=%}.exe + $(MAKE) test_$(@:gcov_%=%) + gcov `sed -e 's/\.exe:/.c/;s/\.o/.c/g' $(@:gcov_%=%.ld)` + touch gcov + rm -f gcov $(wildcard *.gcda *.gcno) + $(MAKE) purge + grep '#####' *.c.gcov || true + +gprof_%: + $(MAKE) purge + $(MAKE) depends + OPTIONS="-pg" $(MAKE) ${@:gprof_%=%}.exe + $(MAKE) ${@:gprof_%=%}.test + IFS=$$'\n'; id=1; \ + for test in `cat ${@:gprof_%=%}.test | sed 's,${@:gprof_%=%}.exe,./${@:gprof_%=%}.exe,g'`; do \ + log=${@:gprof_%=%}.prof-$$id.glog; \ + $(call TITLE, test: $$test); \ + echo $$test > $$log; \ + eval $$test >> $$log; \ + [ $$? -eq 0 ] \ + && echo -e "\033[1;32mSUCCESS\033[0;0m" \ + || echo -e "\033[1;31mFAILED\033[0;0m"; \ + [ -f gmon.out ] && { gprof ${@:gprof_%=%}.exe gmon.out >> $$log; rm gmon.out; }; \ + let id++; \ + done; + $(MAKE) purge + +%.test: %.c + $(call TITLE, "Building $@") + $(call GETCOMMENTS,test, $<) > $@ + $(call PASS, SUCCESS) + -rm -f _ + +test_%: %.test %.exe + IFS=$$'\n'; RC=0; \ + for test in `cat $< | sed 's,${<:.test=.exe},$(VALGRIND) ./${<:.test=.exe},g'`; do \ + echo "=== $$test ==="; \ + eval $$test; \ + [ $$? -eq 0 ] && echo -e "\033[1;32mSUCCESS\033[0;0m" \ + || { echo -e "\033[1;31mFAILED\033[0;0m"; RC=1; }; \ + done; \ + test "$$RC" -ne 1 + +valgrind_%: %.exe + VALGRIND="valgrind -v --leak-check=full --log-fd=3"; \ + export VALGRIND; \ + $(MAKE) $(@:valgrind_%=test_%) 3>$@.log + +%.d: %.c + $(call TITLE, "Building $@") + $(CC) $(INCLUDES) -MM $< -o $@~ + echo ${<:.c=.o}: $(shell $(call GETCOMMENTS,depends, $<)) >> $@~ + $(MV) $@~ $@ + $(call PASS, SUCCESS) + +%.ld: %.c + $(call TITLE, "Building $@") + echo ${<:.c=.exe}: $(shell $(call GETCOMMENTS,$(LDOPT), $<) | awk '{for (i=1;i<=NF;i++) if ($$(i) ~ /.o$$/) printf " %s", $$(i)}') > $@ + $(call PASS, SUCCESS) + +%.o: %.c + $(call TITLE, "Building $@") + $(CC) $(CFLAGS) $(INCLUDES) $(shell $(call GETCOMMENTS,cflags, $<)) -c $< -o $@ + $(call PASS, SUCCESS) + + +%.exe: %.o %.d + $(call TITLE, "Building $@") + $(CC) $(LDFLAGS) $< $(shell $(call GETCOMMENTS,$(LDOPT), ${<:.o=.c})) $(LDLIBS) -o $@ + $(call PASS, SUCCESS) + +## Phony + +.PHONY: all clean count depends gcovs purge tests + +## Precious + +.PRECIOUS: %.d %.o diff --git a/reversi.c b/reversi.c new file mode 100644 index 0000000..26d193d --- /dev/null +++ b/reversi.c @@ -0,0 +1,194 @@ +/* depend: */ +/* cflags: */ +/* linker: block.o color.c constant.o debug.o display.o function.o -lcurses */ +/* doslnk: block.o color.c constant.o debug.o display.o function.o -lpdc~1 */ +/* winlnk: block.o color.c constant.o debug.o display.o function.o -lpdcurses */ + +#include +#include +#include + +#include "constant.h" +#include "debug.h" +#include "display.h" +#include "function.h" +#include "time.h" + +/* static variables */ +char *progname = NULL; +char *version = "0.1"; + +char *filename = NULL; +int scale = 1; +char *boardname = "6x10"; + +char *help = + " Move up cursor\n" + " Move left cursor\n" + " Move down cursor\n" + " Move right cursor\n" + " Hold/Release piece\n" + " Quit\n" + " Save file\n" + ; + +int usage (int ret) +{ + FILE *fd = ret ? stderr : stdout; + fprintf (fd, "usage: %s [-b] [-f file] [-h] [-s int] [-v int]\n", progname); + fprintf (fd, " -b: board form [6x10, 5x12, 4x15, 3x20] (%s)\n", boardname); + fprintf (fd, " -f: file name (%s)\n", (filename) ? filename : "none"); + fprintf (fd, " -h: help message\n"); + fprintf (fd, " -s: scale [0..3] (%d)\n", scale); + fprintf (fd, " -v: verbose level (%d)\n", verbose); + fprintf (fd, "%s version %s\n", progname, version); + + return ret; +} + +/* main function */ +int main (int argc, char *argv[]) +{ + + /* get basename */ + char *pt = progname = argv[0]; + while (*pt) { + if ((*pt == '/') || (*pt == '\\')) { + progname = pt + 1; + } + pt++; + } + + /* process argument */ + while (argc-- > 1) { + char *arg = *(++argv); + if (arg[0] != '-') { + VERBOSE (ERROR, fprintf (stderr, "%s: invalid option -- %s\n", progname, arg)); + return usage (1); + } + char c = arg[1]; + switch (c) { + case 'b': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg == NULL) { + VERBOSE (ERROR, fprintf (stderr, "%s: no board specified\n", progname)); + return usage (1); + } + boardname = arg; + break; + case 'f': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg == NULL) { + VERBOSE (ERROR, fprintf (stderr, "%s: no file specified\n", progname)); + return usage (1); + } + filename = arg; + break; + case 's': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg == NULL) { + VERBOSE (ERROR, fprintf (stderr, "%s: no scale specified\n", progname)); + return usage (1); + } + scale = atoi (arg); + break; + case 'v': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg == NULL) { + VERBOSE (ERROR, fprintf (stderr, "%s: missing verbose level\n", progname)); + return usage (1); + } + verbose = atoi (arg); + break; + case 'h': + default: + return usage (c != 'h'); + } + } + + /* check */ + if ((scale < 0) || (scale > 3)) { + VERBOSE (ERROR, fprintf (stderr, "incorrect scale (%d)\n", scale)); + return 1; + } + + /* load playground */ + board_t *board = NULL; + if (filename) { + char *buffer = readdata (filename); + if (buffer == NULL) { + VERBOSE (ERROR, fprintf (stderr, "can't read file (%s)\n", filename)); + return 1; + } + board = loadboard (buffer); + free (buffer); + if (board == NULL) { + VERBOSE (ERROR, fprintf (stderr, "incorrect file (%s)\n", filename)); + return 1; + } + } else if (boardname) { + board = getboard (boardname); + if (board == (board_t *)(-1)) { + return 0; + } + if (board == NULL) { + VERBOSE (ERROR, fprintf (stderr, "unknown board (%s)\n", boardname)); + return 1; + } + } + setscale (board, scale); + + /* init curses window */ + initscr (); + noecho (); + cbreak (); + nonl (); + keypad (stdscr, TRUE); + curs_set (0); + start_color (); + + /* window positions */ + int xboard = board->xoffset = xoffset + 1; + int yboard = board->yoffset = xoffset + 1; + int xhelp = xboard + xoffset + 1 + board->xsize; + int xcursor = 0; + int ycursor = 0; + int yhelp = yboard - 1; + int xsave = max (xboard + (board->xsize - savelen) / 2, 1); + int ysave = yboard + (board->ysize - 1) / 2; + char *savename = NULL; + + /* help window */ + int lhelp = helpwindow (help, xhelp, yhelp); + + /* window positions */ + int xmsg = xboard; + int ymsg = max (yboard + xoffset + 1 + board->ysize, yhelp + lhelp + yoffset + 1); + int lmsg = xhelp - xmsg + strmaxlen (help, '\n'); + + + + + + + endwin (); + + freeboard (board); + + return 0; +} + +/* test: reversi.exe -b 2>&1 | grep 'no board' */ +/* test: reversi.exe -b unknown 2>&1 | grep 'unknown board' */ +/* test: reversi.exe -b list | grep '^board:' */ +/* test: reversi.exe -f 2>&1 | grep 'no file' */ +/* test: reversi.exe -f nofile.pen 2>&1 | grep "can't read file" */ +/* test: reversi.exe -f bogus.pen 2>&1 | grep 'incorrect file' */ +/* test: reversi.exe -h | grep usage */ +/* test: reversi.exe -s 2>&1 | grep 'no scale' */ +/* test: reversi.exe -s 4 2>&1 | grep incorrect */ +/* test: reversi.exe -v 2>&1 | grep missing */ +/* test: reversi.exe _ 2>&1 | grep invalid */ +/* test: { sleep 1; echo -n s; sleep 1; echo -n ouuljki; sleep 1; echo q; } | reversi.exe -s 0 */ + +/* vim: set ts=4 sw=4 et: */ diff --git a/type.h b/type.h new file mode 100644 index 0000000..199c75f --- /dev/null +++ b/type.h @@ -0,0 +1,28 @@ +#ifndef __TYPE_H__ +#define __TYPE_H__ + +typedef struct { + int width; + int height; + char *tab; + int scale; + int xsize; + int ysize; + int xoffset; + int yoffset; + int current; + int lines; + int next; + int score; +} board_t; + +typedef struct { + int width; + int height; + int color; + char *tab; +} block_t; + +#endif /* __TYPE_H__ */ + +/* vim: set ts=4 sw=4 et: */ -- 2.30.2