From f27f7111a48a930eec69df26bebf6dbe63f068c1 Mon Sep 17 00:00:00 2001 From: Laurent MAZET Date: Thu, 23 May 2024 16:12:57 +0200 Subject: [PATCH] initial commit --- .gitignore | 5 ++ board.c | 145 +++++++++++++++++++++++++++++++++++++++++ board.h | 9 +++ debug.c | 5 ++ debug.h | 21 ++++++ getcomments.pl | 85 ++++++++++++++++++++++++ makefile | 173 +++++++++++++++++++++++++++++++++++++++++++++++++ scrabble.c | 117 +++++++++++++++++++++++++++++++++ 8 files changed, 560 insertions(+) create mode 100644 .gitignore create mode 100644 board.c create mode 100644 board.h create mode 100644 debug.c create mode 100644 debug.h create mode 100644 getcomments.pl create mode 100644 makefile create mode 100644 scrabble.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..214731f --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.d +*.ld +*.exe +*.log +*.o diff --git a/board.c b/board.c new file mode 100644 index 0000000..b58c0c4 --- /dev/null +++ b/board.c @@ -0,0 +1,145 @@ +#include +#include +#include + +#include "board.h" +#include "debug.h" + +typedef struct { + int xsize; + int ysize; + float factor; + int length; + int premium; + char *TW; + char *DW; + char *TL; + char *DL; + char *CS; +} board_t; + +board_t _board = +{ + 15, /* xsize */ + 15, /* ysize */ + 1, /* factor */ + 7, /* length */ + 50, /* premium */ + "A1\0A8\0A15\0H1\0H15\0O1\0O8\0O15\0", /* TW */ + "B2\0B14\0C3\0C13\0D4\0D12\0E5\0E11\0K5\0K11\0L4\0L12\0M3\0M13\0N2\0N14\0", /* DW */ + "B6\0B10\0F2\0F6\0F10\0F14\0J2\0J6\0J10\0J14\0N6\0N10\0", /* TL */ + "A4\0A12\0C7\0C9\0D1\0D8\0D15\0G3\0G7\0G9\0G13\0H4\0H12\0I3\0I7\0I9\0I13\0L1\0L8\0L15\0M7\0M9\0O4\0O12\0", /* DL */ + "H8\0" /* CS */ +}; +board_t *board = &_board; + +int contains (char *list, char *str) +{ + while (*list) { + if (strcmp (list, str) == 0) { + return 1; + } + list += strlen (list) + 1; + } + return 0; +} + + +typedef enum { + white = 1, + red, + green, + blue, + cyan, + magenta, + yellow, + black, +} color_t; + +void set_color (color_t color) +{ + int init = 1; + + if (init) { + init_pair (white, COLOR_WHITE, COLOR_BLACK); + init_pair (red, COLOR_BLACK, COLOR_RED); + init_pair (green, COLOR_BLACK, COLOR_GREEN); + init_pair (blue, COLOR_BLACK, COLOR_BLUE); + init_pair (magenta, COLOR_BLACK, COLOR_MAGENTA); + init_pair (yellow, COLOR_BLACK, COLOR_YELLOW); + init_pair (cyan, COLOR_BLACK, COLOR_CYAN); + init_pair (black, COLOR_BLACK, COLOR_WHITE); + init = 0; + } + + attrset (COLOR_PAIR(color)); +} + +char *initboard (void) +{ + char *tab = (char *) malloc (board->xsize * board->ysize); + memset (tab, ' ', board->xsize * board->ysize); + return tab; +} + +void showboard (char *tab, int xoffset, int yoffset, int full) +{ + int x, y; + for (x = -1; x <= board->xsize; x++) { + for (y = -1; y <= board->ysize; y++) { + int c = ' '; + char pos[4] = {0}; + sprintf (pos, "%c%d", 'A' + x, 1 + y); + if ((x == -1) && (y == -1)) { + c = ACS_ULCORNER; + set_color (black); + } else if ((x == board->xsize) && (y== -1)) { + c = ACS_URCORNER; + set_color (black); + } else if ((x == -1) && (y == board->ysize)) { + c = ACS_LLCORNER; + set_color (black); + } else if ((x == board->xsize) && (y == board->ysize)) { + c = ACS_LRCORNER; + set_color (black); + } else if ((x == -1) || (x == board->xsize)) { + c = ACS_VLINE; + set_color (black); + } else if ((y == -1) || (y == board->xsize)) { + c = ACS_HLINE; + set_color (black); + } else { + c = tab[x + y * board->xsize]; + if (c == ' ') { + if (contains (board->TW, pos)) { + c = 'T'; + set_color (red); + } else if (contains (board->DW, pos)) { + c = 'D'; + set_color (magenta); + } else if (contains (board->TL, pos)) { + c = 't'; + set_color (blue); + } else if (contains (board->DL, pos)) { + c = 'd'; + set_color (cyan); + } else if (contains (board->CS, pos)) { + c = 'S'; + set_color (magenta); + } + if (!full) { + c = ' '; + } + } + } + VERBOSE (DEBUG, if ((c < 32) || (c > 255)) printf ("character: %c\n", c)); + if (c) { + mvaddch(yoffset + y, xoffset + x, c); + } + set_color (white); + + } + } +} + +/* vim: set ts=4 sw=4 et: */ diff --git a/board.h b/board.h new file mode 100644 index 0000000..935b411 --- /dev/null +++ b/board.h @@ -0,0 +1,9 @@ +#ifndef __BOARD_H__ +#define __BOARD_H__ + +char *initboard (void); +void showboard (char *tab, int xoffset, int yoffset, int full); + +#endif /* __BOARD_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/getcomments.pl b/getcomments.pl new file mode 100644 index 0000000..47edf67 --- /dev/null +++ b/getcomments.pl @@ -0,0 +1,85 @@ +#!/usr/bin/perl + +use strict; + +# default value +my $format = "%"; +my $pattern = ""; + +# help message +sub usage() { + + print <) { + my $cmt; + + # process c++ comments + ($cmt, $_) = m{//\s*(.*?)\s*$()} if (m{//} && !m{/\*.*//}); + + # process standard c comments + ($cmt, $_) = m{^.*?/\*\s*(.*?)\s*\*/(.*)}s if (m{/\*.*\*/}s); + + push(@comments, $cmt) if ($cmt); + + # empty buffer if no comment is present + undef($_) if (!m{/[/*]}); + } + + # close file + close (IN); + + # display comment blocks + foreach my $block (@comments) { + if (($block) = ($block =~ /$pattern(.*)/s)) { + ($_ = $format) =~ s/%/$block/gs; + print "$_\n"; + } + } +} diff --git a/makefile b/makefile new file mode 100644 index 0000000..bcdc9c6 --- /dev/null +++ b/makefile @@ -0,0 +1,173 @@ +# 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 $(OPTIONS) + +LDOPT = linker +ifeq ($(OS),Windows_NT) +#LDLIBS += -lws2_32 +LDOPT = winlnk +endif + + +# Targets + +ALLEXE = +ALLEXE += scrabble + +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; } + +## 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: all + $(MAKE) $(addprefix valgrind_,$(ALLEXE)) + +wipe: purge + $(call TITLE, "Wiping") + touch wipe + rm -f wipe $(wildcard *.gcda *.gcno *.gcov *.glog) + $(call PASS, SUCCESS) + +tests: all + $(MAKE) $(addprefix test_,$(ALLEXE)) + +## Main rules + +include $(wildcard *.d) +include $(wildcard *.ld) + +gcov_%: + $(MAKE) purge + OPTIONS="-coverage -O0" $(MAKE) + $(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 $@") +# awk '/\/\* *test:.*\*\// { sub(/^.*\/\* *test: */, ""); sub(/ *\*\/.*$$/, ""); print }' $< > $@ + perl -- getcomments.pl -p='test:\s' -f='%' $< > $@ + $(call PASS, SUCCESS) + +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 perl -- getcomments.pl -p='depend:\s' -f='%' $<) >> $@~ + mv $@~ $@ + $(call PASS, SUCCESS) + +%.ld: %.c + $(call TITLE, "Building $@") + echo ${<:.c=.exe}: $(shell perl -- getcomments.pl -p='$(LDOPT):\s' -f='%' $< | 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 perl -- getcomments.pl -p='cflags:\s' -f='%' $<) -c $< -o $@ + $(call PASS, SUCCESS) + + +%.exe: %.o %.d + $(call TITLE, "Building $@") + $(CC) $(LDFLAGS) $< $(shell perl -- getcomments.pl -p='$(LDOPT):\s' -f='%' ${<:.o=.c}) $(LDLIBS) -o $@ + $(call PASS, SUCCESS) + +## Phony + +.PHONY: all clean count depends gcovs purge tests + +## Precious + +.PRECIOUS: %.d %.o diff --git a/scrabble.c b/scrabble.c new file mode 100644 index 0000000..26b6d19 --- /dev/null +++ b/scrabble.c @@ -0,0 +1,117 @@ +/* depend: */ +/* cflags: */ +/* linker: board.o debug.o -lcurses */ +/* winlnk: board.o debug.o -lpdcurses */ + +#include +#include +#include + +#include "board.h" +#include "debug.h" + +/* static variables */ +char *progname = NULL; +char *version = "0.1"; + +char *language = "FR"; + +int usage (int ret) +{ + FILE *fd = ret ? stderr : stdout; + fprintf (fd, "usage: %s [-h] [-l lang] [-v level]\n", progname); + fprintf (fd, " -h: help message\n"); + fprintf (fd, " -l: language (%s)\n", language); + 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 'l': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg) { + language = arg; + } else { + VERBOSE (ERROR, fprintf (stderr, "%s: no language specified\n", progname)); + return usage (1); + } + 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'); + } + } + + initscr(); + //seed = time((time_t *)0); + //srand(seed); + + noecho(); + cbreak(); + nonl(); + + start_color (); + //endwin (); + + char *tab = initboard (); + + int c = 0; + int stop = 0, mode = 0; + while (!stop) { + showboard (tab, 4, 4, mode); + + c = getch (); + switch (c) { + case 'q': + stop = 1; + break; + case ERR: + break; + default: + mode = mode^1; + } + } + + endwin (); + + return 0; +} + +/* test: scrabble.exe -l 2>&1 | grep error */ +/* test: scrabble.exe -h | grep usage */ +/* test: scrabble.exe -v 2>&1 | grep missing */ +/* test: scrabble.exe -s 2>&1 | grep missing */ +/* test: scrabble.exe _ 2>&1 | grep invalid */ + +/* vim: set ts=4 sw=4 et: */ -- 2.30.2