From 3e042aefddb3805de9ef1f87147259273d72b8e2 Mon Sep 17 00:00:00 2001 From: Laurent Mazet Date: Sat, 20 Jul 2024 10:45:07 +0200 Subject: [PATCH 1/1] initial skeleton --- constant.c | 8 + constant.h | 8 + debug.c | 5 + debug.h | 21 +++ display.c | 446 +++++++++++++++++++++++++++++++++++++++++++++++++++++ display.h | 19 +++ function.c | 238 ++++++++++++++++++++++++++++ function.h | 46 ++++++ makefile | 182 ++++++++++++++++++++++ tetris.c | 247 +++++++++++++++++++++++++++++ type.h | 19 +++ 11 files changed, 1239 insertions(+) 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 tetris.c create mode 100644 type.h diff --git a/constant.c b/constant.c new file mode 100644 index 0000000..eb0f8ee --- /dev/null +++ b/constant.c @@ -0,0 +1,8 @@ +#include +#include + +#include "type.h" + +#include "constant.h" + +/* vim: set ts=4 sw=4 et: */ diff --git a/constant.h b/constant.h new file mode 100644 index 0000000..e270e12 --- /dev/null +++ b/constant.h @@ -0,0 +1,8 @@ +#ifndef __CONSTANT_H__ +#define __CONSTANT_H__ + +#include "type.h" + +#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..467787c --- /dev/null +++ b/display.c @@ -0,0 +1,446 @@ +#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 (char symb) +{ + switch (symb) { + case ' ': + set_color (black); + break; + case '.': + set_color (white); + break; + case '/': + set_color (byellow); + break; + case '0': + case '6': + set_color (wgreen); + break; + case '1': + case '7': + set_color (wred); + break; + case '2': + case '8': + set_color (green); + break; + case '3': + case '9': + set_color (red); + break; + case '4': + case ':': + set_color (bgreen); + break; + case '5': + case ';': + set_color (bred); + break; + case 'S': + set_color (byellow); + break; + case 'Z': + set_color (bblue); + break; + } +} + +void _element0 (board_t *board, int x, int y, int symb) +{ + int element = ' '; + switch (symb) { + case '/': + element = 'X'; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + element = '0'; + break; + case '6': + case '7': + case '8': + case '9': + case ':': + case ';': + element = ACS_DIAMOND; + 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 '/': + element0 = '>'; + element1 = '<'; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + element0 = '['; + element1 = ']'; + break; + case '6': + case '7': + case '8': + case '9': + case ':': + case ';': + element0 = '<'; + element1 = '>'; + break; + } + _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 '/': + element00 = '\\'; + element01 = '/'; + element10 = '/'; + element11 = '\\'; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + element00 = ACS_ULCORNER; + element01 = ACS_URCORNER; + element10 = ACS_LLCORNER; + element11 = ACS_LRCORNER; + break; + case '6': + case '7': + case '8': + case '9': + case ':': + case ';': + element00 = '/'; + element01 = '\\'; + element10 = '\\'; + element11 = '/'; + break; + } + _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 '/': + element00 = '\\'; + element01 = '|'; + element02 = '/'; + element10 = '/'; + element11 = '|'; + element12 = '\\'; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + element00 = ACS_ULCORNER; + element01 = ACS_HLINE; + element02 = ACS_URCORNER; + element10 = ACS_LLCORNER; + element11 = ACS_HLINE; + element12 = ACS_LRCORNER; + break; + case '6': + case '7': + case '8': + case '9': + case ':': + case ';': + element00 = '/'; + element01 = 'T'; + element02 = '\\'; + element10 = '\\'; + element11 = '_'; + element12 = '/'; + 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); + 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); + 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..d12ca6f --- /dev/null +++ b/function.c @@ -0,0 +1,238 @@ +#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->current = (char *) calloc (1, width * height + 1); + CHECKALLOC (board->current); + memset (board->current, ' ', width * height); + board->scale = 0; + board->xsize = board->width = width; + board->ysize = board->height = height; + board->xoffset = 0; + board->yoffset = 0; + board->next = -1; + return board; +} + +board_t *copyboard (board_t *board) +{ + board_t *newboard = initboard (board->width, board->height); + char *tab = newboard->tab; + char *current = newboard->current; + memcpy (newboard, board, sizeof (board_t)); + newboard->tab = tab; + newboard->current = current; + memcpy (newboard->tab, board->tab, board->width * board->height + 1); + memcpy (newboard->current, board->current, 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->current); + } + 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 = 3 * (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: \"%s\"\n", board->current); + l += sprintf (buffer + l, "next: %d\n", board->next); + + 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 *current = NULL; + int next = -1; + + 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 = atos (value); + } else if (strcmp (keyword, "next") == 0) { + next = 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)) && + (current) && (strlen (current) == (size_t)(width * height))) { + board = initboard (width, height); + memcpy (board->tab, tab, width * height); + memcpy (board->current, current, width * height); + board->next = next; + } + + 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..b0d4842 --- /dev/null +++ b/function.h @@ -0,0 +1,46 @@ +#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; }) + +int strmaxlen (char *str, char ch); + +board_t *initboard (int xsize, int ysize); + +board_t *initplay (board_t *board); + +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/makefile b/makefile new file mode 100644 index 0000000..d36ede3 --- /dev/null +++ b/makefile @@ -0,0 +1,182 @@ +# 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 +ifeq ($(OS),Windows_NT) +#LDLIBS += -lws2_32 +LDOPT = winlnk +endif +ifeq ($(OS),Dos) +LDOPT = doslnk +endif + +# Targets + +ALLEXE = +ALLEXE += tetris + +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/tetris.c b/tetris.c new file mode 100644 index 0000000..22c6b24 --- /dev/null +++ b/tetris.c @@ -0,0 +1,247 @@ +/* depend: */ +/* cflags: */ +/* linker: constant.o debug.o display.o function.o -lcurses */ +/* doslnk: constant.o debug.o display.o function.o -lpdc~1 */ +/* winlnk: constant.o debug.o display.o function.o -lpdcurses */ + +#include +#include +#include +#include +#include + +#include "constant.h" +#include "debug.h" +#include "display.h" +#include "function.h" +#include "type.h" + +/* static variables */ +char *progname = NULL; +char *version = "0.1"; + +char *filename = NULL; +int scale = 1; + +int height = 20; +int width = 9; + +int savelen = 12; +int xoffset = 1; +int yoffset = 1; + +char *help = + " Put down tile\n" + " Move left tile\n" + " Move down tile\n" + " Move right tile\n" + " Rotate left tile\n" + "

Pause\n" + " Quit\n" + " Rotate right tile\n" + " Save file\n" + ; + +int usage (int ret) +{ + FILE *fd = ret ? stderr : stdout; + fprintf (fd, "usage: %s [-f file] [-h] [-s int] [-v level]\n", progname); + fprintf (fd, " -f: file name (%s)\n", (filename) ? filename : "none"); + 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 '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; + } + + 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 { + board = initboard (width, height); + } + 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 = 1; + 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'); + + /* event loop */ + int mode = 0; + int stop = 0; + while (!stop) { + + boardwindow (board); + if (1) { /* not end of game */ + char msg[128] = {0}; + switch (mode) { + case 0: + sprintf (msg, "Get ready player One"); + break; + case 1: + break; + } + msgwindow (msg, xmsg, ymsg, lmsg); + } else { + msgwindow ("End of game", xmsg, ymsg, lmsg); + } + + int ch = getch (); + switch (ch) { + case KEY_ENTER: + case '\n': + case '\r': + case 'c': + break; + case KEY_LEFT: + case 'j': + break; + case KEY_DOWN: + case 'k': + break; + case KEY_RIGHT: + case 'l': + break; + case KEY_UP: + case ' ': + case 'i': + case 'o': + break; + case 'p': + mode = (mode == 0) ? 1 : 0; + break; + case KEY_ESC: + case 'q': + stop = 1; + break; + case 's': + savename = savewindow (savelen, xsave, ysave); + if (savename != NULL) { + char *ptr = saveboard (board); + if (writedata (savename, ptr)) { + VERBOSE (WARNING, printf ("issue writing Board\n")); + } + free (ptr); + free (savename); + } + break; + case KEY_BACKSPACE: + case KEY_DELETE: + case 127: + case '\b': + case 'u': + break; + //case ERR: + //default: + } + } + + endwin (); + + freeboard (board); + + return 0; +} + +/* test: tetris.exe -f 2>&1 | grep 'no file' */ +/* test: tetris.exe -f tests/nofile.ttr 2>&1 | grep "can't read file" */ +/* test: tetris.exe -f tests/bogus.ttr 2>&1 | grep 'incorrect file' */ +/* test: tetris.exe -h | grep usage */ +/* test: tetris.exe -s 2>&1 | grep 'no scale' */ +/* test: tetris.exe -s 4 2>&1 | grep incorrect */ +/* test: tetris.exe -v 2>&1 | grep missing */ +/* test: tetris.exe _ 2>&1 | grep invalid */ + +/* vim: set ts=4 sw=4 et: */ diff --git a/type.h b/type.h new file mode 100644 index 0000000..3c66510 --- /dev/null +++ b/type.h @@ -0,0 +1,19 @@ +#ifndef __TYPE_H__ +#define __TYPE_H__ + +typedef struct { + int width; + int height; + char *tab; + char *current; + int scale; + int xsize; + int ysize; + int xoffset; + int yoffset; + int next; +} board_t; + +#endif /* __TYPE_H__ */ + +/* vim: set ts=4 sw=4 et: */ -- 2.30.2