From: Laurent Mazet Date: Mon, 26 Aug 2024 22:15:55 +0000 (+0200) Subject: initial commit X-Git-Tag: v1.0~15 X-Git-Url: https://secure.softndesign.org/git/?a=commitdiff_plain;h=00f8b889420ad3c75fe1e86f011c4d92a966de3a;p=reversi.git initial commit --- 00f8b889420ad3c75fe1e86f011c4d92a966de3a 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: */