From 9f0352273d91c94f6879a40815ca120026812f18 Mon Sep 17 00:00:00 2001 From: Laurent MAZET Date: Mon, 16 Dec 2024 17:34:57 +0100 Subject: [PATCH] add functions to manage boards --- display.c | 356 +++++++++++++++++++++++++++++++++++++++++++++++++++++ display.h | 19 +++ function.c | 219 ++++++++++++++++++++++++++++++++ function.h | 42 +++++++ sokoban.c | 10 +- type.h | 17 +++ 6 files changed, 658 insertions(+), 5 deletions(-) create mode 100644 display.c create mode 100644 display.h create mode 100644 function.c create mode 100644 function.h create mode 100644 type.h diff --git a/display.c b/display.c new file mode 100644 index 0000000..12ed42b --- /dev/null +++ b/display.c @@ -0,0 +1,356 @@ +#include +#include +#include +#include + +#include "debug.h" +#include "function.h" +#include "type.h" + +#include "display.h" + +typedef enum { + white = 1, + red, + green, + blue, + cyan, + magenta, + yellow, + bred, + bgreen, + bblue, + bcyan, + bmagenta, + byellow, + black, + wred, + wgreen, + wblue, + wcyan, + wmagenta, + wyellow, +} color_t; + +void set_color (color_t color) +{ + static int init = 1; + + if (init) { + init_pair (white, COLOR_WHITE, COLOR_BLACK); + init_pair (red, COLOR_RED, COLOR_BLACK); + init_pair (green, COLOR_GREEN, COLOR_BLACK); + init_pair (blue, COLOR_BLUE, COLOR_BLACK); + init_pair (magenta, COLOR_MAGENTA, COLOR_BLACK); + init_pair (yellow, COLOR_YELLOW, COLOR_BLACK); + init_pair (cyan, COLOR_CYAN, COLOR_BLACK); + init_pair (bred, COLOR_BLACK, COLOR_RED); + init_pair (bgreen, COLOR_BLACK, COLOR_GREEN); + init_pair (bblue, COLOR_BLACK, COLOR_BLUE); + init_pair (bmagenta, COLOR_BLACK, COLOR_MAGENTA); + init_pair (byellow, COLOR_BLACK, COLOR_YELLOW); + init_pair (bcyan, COLOR_BLACK, COLOR_CYAN); + init_pair (black, COLOR_BLACK, COLOR_WHITE); + init_pair (wred, COLOR_WHITE, COLOR_RED); + init_pair (wgreen, COLOR_WHITE, COLOR_GREEN); + init_pair (wblue, COLOR_WHITE, COLOR_BLUE); + init_pair (wcyan, COLOR_WHITE, COLOR_CYAN); + init_pair (wmagenta, COLOR_WHITE, COLOR_MAGENTA); + init_pair (wyellow, COLOR_WHITE, COLOR_YELLOW); + init = 0; + } + + attrset (COLOR_PAIR(color)); +} + +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 _set_symb_color (int symb) +{ + set_color (white); + switch (symb) { + case '$': /* box */ + set_color (red); + break; + case '*': /* box docked */ + case '+': /* sokoban on dock */ + set_color (cyan); + break; + case '@': /* sokoban */ + set_color (green); + break; + case '#': /* wall */ + set_color (black); + break; + } +} + +void _element0 (board_t *board, int x, int y, int symb) +{ + int element = ' '; + switch (symb) { + case '$': /* box */ + case '*': /* box docked */ + element = ACS_DIAMOND; + break; + case '.': /* empty dock */ + element = 'X'; + break; + } + _set_symb_color (symb); + mvaddch (board->yoffset + y, board->xoffset + x, element); + set_color (white); +} + +void _element1 (board_t *board, int x, int y, int symb) +{ + int element0 = ' '; + int element1 = ' '; + switch (symb) { + case '$': + case '*': + element0 = ACS_LARROW; + element1 = ACS_RARROW; + break; + case '.': + element0 = '-'; + element1 = '-'; + } + _set_symb_color (symb); + mvaddch (board->yoffset + y, board->xoffset + 2 * x, element0); + mvaddch (board->yoffset + y, board->xoffset + 2 * x + 1, element1); + set_color (white); +} + +void _element2 (board_t *board, int x, int y, int symb) +{ + int element00 = ' '; + int element10 = ' '; + int element01 = ' '; + int element11 = ' '; + switch (symb) { + case '$': + case '*': + element00 = ACS_ULCORNER; + element01 = ACS_URCORNER; + element10 = ACS_LLCORNER; + element11 = ACS_LRCORNER; + break; + case '.': + element00 = '.'; + element01 = '.'; + element10 = '.'; + element11 = '.'; + } + _set_symb_color (symb); + mvaddch (board->yoffset + 2 * y, board->xoffset + 2 * x, element00); + mvaddch (board->yoffset + 2 * y, board->xoffset + 2 * x + 1, element01); + mvaddch (board->yoffset + 2 * y + 1, board->xoffset + 2 * x, element10); + mvaddch (board->yoffset + 2 * y + 1, board->xoffset + 2 * x + 1, element11); + set_color (white); +} + +void _element3 (board_t *board, int x, int y, int symb) +{ + int element00 = ' '; + int element10 = ' '; + int element01 = ' '; + int element11 = ' '; + int element02 = ' '; + int element12 = ' '; + switch (symb) { + case '$': + case '*': + element00 = ACS_ULCORNER; + element01 = ACS_HLINE; + element02 = ACS_URCORNER; + element10 = ACS_LLCORNER; + element11 = ACS_HLINE; + element12 = ACS_LRCORNER; + break; + case '.': + element00 = ACS_VLINE; + element01 = ' '; + element02 = ACS_VLINE; + element10 = ACS_LLCORNER; + element11 = ACS_HLINE; + element12 = ACS_LRCORNER; + break; + } + _set_symb_color (symb); + mvaddch (board->yoffset + 2 * y, board->xoffset + 3 * x, element00); + mvaddch (board->yoffset + 2 * y, board->xoffset + 3 * x + 1, element01); + mvaddch (board->yoffset + 2 * y, board->xoffset + 3 * x + 2, element02); + mvaddch (board->yoffset + 2 * y + 1, board->xoffset + 3 * x, element10); + mvaddch (board->yoffset + 2 * y + 1, board->xoffset + 3 * x + 1, element11); + mvaddch (board->yoffset + 2 * y + 1, board->xoffset + 3 * x + 2, element12); + set_color (white); +} + +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 i, j; + + set_color (black); + _dobound (board->xsize, board->ysize, board->xoffset, board->yoffset); + set_color (white); + + for (i = 0; i < board->width; i++) { + for (j = 0; j < board->height; j++) { + _element (board, i, j, getvalue (board, i, j)); + } + } +} + +char *savewindow (int length, int xoffset, int yoffset) +{ + char *name = (char *) calloc (1, length + 1); + CHECKALLOC (name); + memset (name, ' ', length); + + set_color (black); + _dobound (length, 1, xoffset, yoffset); + set_color (white); + + int i = 0, j; + int stop = 0; + while (!stop) { + for (j = 0; j < length; j++) { + set_color ((j == i) ? yellow : black); + mvaddch (yoffset, xoffset + j, name[j]); + set_color (white); + } + 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) +{ + set_color (white); + _dobound ((length > 0) ? length : (int)strlen (msg), 1, xoffset, yoffset); + mvaddstr (yoffset, xoffset + ((length > 0) ? (length - (int)strlen (msg)) / 2 : 0), msg); + set_color (black); +} + +/* vim: set ts=4 sw=4 et: */ diff --git a/display.h b/display.h new file mode 100644 index 0000000..df04aa7 --- /dev/null +++ b/display.h @@ -0,0 +1,19 @@ +#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); + +void boardwindow (board_t *board); + +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..446e0c1 --- /dev/null +++ b/function.c @@ -0,0 +1,219 @@ +#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; + return board; +} + +board_t *copyboard (board_t *board) +{ + board_t *newboard = (board_t *) malloc (sizeof (board_t)); + CHECKALLOC (board); + memcpy (newboard, board, sizeof (board_t)); + newboard->tab = (char *) calloc (1, board->width * board->height + 1); + CHECKALLOC (newboard->tab); + memcpy (newboard->tab, board->tab, board->width * board->height + 1); + return newboard; +} + +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", getvalue (board, i, j)); + } + l += sprintf (buffer + l, "\"\n"); + } + return l; +} + +char *saveboard (board_t *board) +{ + int size = 2 * (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); + + 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; + + 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, "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); + } + + return board; +} + +char *getcell (board_t *board, int x, int y) +{ + return board->tab + x + board->width * y; +} + +char getvalue (board_t *board, int x, int y) +{ + return (x >= 0) && (x < board->width) && (y >= 0) && (y < board->height) ? *getcell (board, x, y) : 0; +} + +/* vim: set ts=4 sw=4 et: */ diff --git a/function.h b/function.h new file mode 100644 index 0000000..34f8760 --- /dev/null +++ b/function.h @@ -0,0 +1,42 @@ +#ifndef __FUNCTION_H__ +#define __FUNCTION_H__ + +#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; }) + +int strmaxlen (char *str, char ch); + +board_t *initboard (int xsize, int ysize); + +board_t *copyboard (board_t *board); + +board_t *setscale (board_t *board, int scale); + +void freeboard (board_t *board); + +char *saveboard (board_t *board); + +int writedata (char *filename, char *data); + +char *readdata (char *filename); + +board_t *loadboard (char *str); + +char *getcell (board_t *board, int x, int y); + +char getvalue (board_t *board, int x, int y); + +#endif /* __FUNCTION_H__ */ + +/* vim: set ts=4 sw=4 et: */ diff --git a/sokoban.c b/sokoban.c index 5756498..2198cc0 100644 --- a/sokoban.c +++ b/sokoban.c @@ -1,16 +1,16 @@ /* depend: */ /* cflags: */ -/* linker: block.o color.c constant.o debug.o display.o function.o time.o -lcurses */ -/* doslnk: block.o color.c constant.o debug.o display.o function.o time.o -lpdc~1 */ -/* winlnk: block.o color.c constant.o debug.o display.o function.o time.o -lpdcurses */ +/* linker: debug.o display.o function.o -lcurses */ +/* doslnk: debug.o display.o function.o -lpdc~1 */ +/* winlnk: debug.o display.o function.o -lpdcurses */ #include #include #include -//#include "constant.h" #include "debug.h" -//#include "time.h" +#include "display.h" +#include "function.h" /* static variables */ char *progname = NULL; diff --git a/type.h b/type.h new file mode 100644 index 0000000..34ea365 --- /dev/null +++ b/type.h @@ -0,0 +1,17 @@ +#ifndef __TYPE_H__ +#define __TYPE_H__ + +typedef struct { + int width; + int height; + char *tab; + int scale; + int xsize; + int ysize; + int xoffset; + int yoffset; +} board_t; + +#endif /* __TYPE_H__ */ + +/* vim: set ts=4 sw=4 et: */ -- 2.30.2