diff --git a/.gitignore b/.gitignore index 29cf209..c7f9f76 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ *.o /hangman *.md~ +*.core diff --git a/figures.h b/figures.h index 73abbcd..20f6255 100644 --- a/figures.h +++ b/figures.h @@ -1,18 +1,18 @@ const char base_figure[6][8] = {{"======="}, \ - {"I "}, \ - {"I "}, \ - {"I "}, \ - {"I "}, \ - {"I\\ "}}; - + {"I "}, \ + {"I "}, \ + {"I "}, \ + {"I "}, \ + {"I\\ "}}; + const char figure[6][5] = {{" O "}, \ - {" I "}, \ - {"\\I "}, \ - {"\\I/"}, \ - {"/ "}, \ - {"/ \\"}}; - + {" I "}, \ + {"\\I "}, \ + {"\\I/"}, \ + {"/ "}, \ + {"/ \\"}}; + /* This array represents the layers where the strings - of the current stage(array index) should be printed*/ + of the current stage(array index) should be printed */ const int stages[] = {0, 1, 1, 1, 2, 2}; diff --git a/hangman.c b/hangman.c index 0488675..6ed6dea 100644 --- a/hangman.c +++ b/hangman.c @@ -1,9 +1,9 @@ #ifdef _WIN32 //For 32 and 64 bits - /* pdcurses include */ - #include + /* pdcurses include */ + #include #else - /* Linux ncurses include */ - #include + /* Linux ncurses include */ + #include #endif #include "hangman.h" //includes time.h #include //atexit @@ -15,9 +15,8 @@ #include "figures.h" - int main(int argc, char **argv) { - + const char *short_options = "w:hf:ct"; struct option long_options[] = { {"word", required_argument, NULL, 'w'}, @@ -25,39 +24,34 @@ int main(int argc, char **argv) { {"file", required_argument, NULL, 'f'}, {"credits", no_argument, NULL, 'c'}, {"troll", no_argument, NULL, 't'} - }; + }; int c, startscr = 1; /* Show startscreen by default */ char filename[255]; + game_state gs = {0}; + hitfeed hf = {{{0}}}; // 3 braces are needed to not get a warning + filename[0] = '\0'; - + /* Initialization */ initscr(); atexit(quitProgram); - game_state *gs; - hitfeed *hf; - - gs = malloc(sizeof(game_state)); - hf = malloc(sizeof(hitfeed)); //zeroes the whole struct - initCoordinates(gs); - gs->allowedMoves = DEFAULTTRIES; - gs->moves = 0; - gs->guesses = 0; - gs->trollEnabled = 0; - hf->besthit = 0; - hf->impstreakcounter = 0; + + initCoordinates(&gs); + gs.allowedMoves = DEFAULTTRIES; + keypad(stdscr, FALSE); nonl(); //No new line. Prevents the new line when hitting enter - - curs_set(0); + + curs_set(0); while ( (c = getopt_long(argc, argv, short_options, long_options, NULL)) != -1 ) { switch (c) { case 'w': - sprintf(gs->guessWord, "%s", optarg); + sprintf(gs.guessWord, "%s", optarg); startscr = 0; break; case 'h': - showHelp(gs); - exit(0); + showHelp(&gs); + return 0; break; case 'f': /* Set filename */ @@ -69,34 +63,32 @@ int main(int argc, char **argv) { break; case 't': /* troll option */ - gs->trollEnabled = 1; + gs.trollEnabled = 1; break; default: - mvprintw(gs->centery, gs->centerx - 9, "Invalid arguments."); + mvprintw(gs.centery, gs.centerx - 9, "Invalid arguments."); getch(); - showHelp(gs); - exit(0); + showHelp(&gs); + return 0; break; } } InitializePRNG(time(NULL)); /* Initialize random number generator */ - + if (startscr) { - showStartScreen(gs); + showStartScreen(&gs); } /* start game */ - initGuessWord(gs, filename); - initAlphabet(gs); - drawAlphabet(gs, 0); - drawFigure(gs, 0); - startGame(gs, hf); + initGuessWord(&gs, filename); + initAlphabet(&gs); + drawAlphabet(&gs, 0); + drawFigure(&gs, 0); + startGame(&gs, &hf); nl(); //enable newline again while (getch() != 10); clear(); - free(gs); - free(hf); return 0; } @@ -143,14 +135,13 @@ void initGuessWord(game_state *gs, char *filename) { int i; mvprintw(0, 1, "Please enter your word: "); if (strlen(gs->guessWord) == 0) { /* Word can be set by arguments */ - if (strlen(filename) == 0) { + /* If a file argument was specified then try to read a random line from the file, + if this is not successful or if there is no file argument use the manual input. */ + if (strlen(filename) == 0 || readRandomLine(filename, gs->guessWord) != 0) { // readRandomLine is only excecuted when strlen(filename) != 0 /* Manual input */ curs_set(1); getnstr(gs->guessWord, MAXWORDLENGTH - 1); /* Reads the guessWord with a limit */ curs_set(0); - } else { - /* Random line from file */ - readRandomLine(filename, gs->guessWord); } } @@ -169,34 +160,28 @@ void initGuessWord(game_state *gs, char *filename) { } void initAlphabet(game_state *gs) { - int hasNumber = 0; - int i; - for (i = 0; i < MAXWORDLENGTH; i++) { + strcpy(gs->alphabet, "abcdefghijklmnopqrstuvwxyz"); + + for (unsigned int i = 0; i < strlen(gs->guessWord); i++) { if (isdigit(gs->guessWord[i]) > 0) { - hasNumber = 1; + strcat(gs->alphabet, "1234567890"); break; } } - gs->alphabet = malloc(sizeof(char) * hasNumber ? ALPHABET : ALPHABET_NUM); - strcpy(gs->alphabet, "abcdefghijklmnopqrstuvwxyz"); - - if (hasNumber) { - strcat(gs->alphabet, "1234567890"); - } } void drawAlphabet(game_state *gs, char usedchar) { int start = centerDiff(gs->centerx, gs->alphabet); - int i; - if (usedchar != 0) { /* 0 is used for initialization */ - for (i = 0; i < (int)strlen(gs->alphabet); i++) { - if (gs->alphabet[i] == usedchar) { - gs->alphabet[i] = '_'; - break; - } - } - } - mvprintw(1, start, "%s", gs->alphabet); + int i; + if (usedchar != 0) { /* 0 is used for initialization */ + for (i = 0; i < (int)strlen(gs->alphabet); i++) { + if (gs->alphabet[i] == usedchar) { + gs->alphabet[i] = '_'; + break; + } + } + } + mvprintw(1, start, "%s", gs->alphabet); } void toLowerCase(char *str) { @@ -215,7 +200,7 @@ void drawGuessWord(game_state *gs) { int ycounter = 0; /* counter of the y position on sceen (row) */ int tempstartpos = startpos; /* the calculated start position to draw the characters */ int rows = 1; /* number of rows */ - + if (gs->wordLength * 2 > gs->maxx - LINEBREAK) { /* The word will be longer then the max. linesize with offset. */ rows = 2; @@ -227,7 +212,7 @@ void drawGuessWord(game_state *gs) { } rows++; } - gs->wordRows = rows; //set the number of rows for clearing the screen later + gs->wordRows = rows; //set the number of rows for clearing the screen later tempstartpos = xcounter = gs->centerx - (gs->wordLength / rows); } for (i = startpos; i < startpos + (gs->wordLength * 2); i++) { @@ -287,13 +272,13 @@ int fillCurrentWord(game_state *gs, char validchar) { break; } } - if (!alreadyUsed) { + if (!alreadyUsed) { for (i = 0; i < gs->wordLength; i++) { if (gs->guessWord[i] == validchar) { gs->currentWord[i] = validchar; } } - drawAlphabet(gs, validchar); + drawAlphabet(gs, validchar); return 1; } else { return 0; @@ -301,21 +286,18 @@ int fillCurrentWord(game_state *gs, char validchar) { } int stackWrongCharacter(game_state *gs, char wrongchar) { - int i, alreadyUsed = 0; - for (i = 0; i < gs->wordLength; i++) { + for (unsigned i = 0; i < strlen(gs->wrongCharacters); i++) { if (gs->wrongCharacters[i] == wrongchar) { - alreadyUsed = 1; + return 0; // already used } } - - if (!alreadyUsed) { - gs->wrongCharacters[strlen(gs->wrongCharacters)] = wrongchar; - drawAlphabet(gs, wrongchar); - drawFigure(gs, 1); - return 1; - } else { - return 0; - } + + // not yet used + gs->wrongCharacters[strlen(gs->wrongCharacters)] = wrongchar; + drawAlphabet(gs, wrongchar); + drawFigure(gs, 1); + + return 1; } int checkWin(game_state *gs) { @@ -333,8 +315,7 @@ int checkWin(game_state *gs) { void printGameStats(game_state *gs) { //clear(); int i, z; - double diff; - diff = difftime(gs->endTime, gs->startTime); + if (!gs->trollEnabled) { for (z = 0; z <= gs->wordRows; z++) { //<= takes the last row too for (i = 0; i < gs->maxx; i++) { @@ -353,23 +334,25 @@ void printGameStats(game_state *gs) { mvprintw(gs->centery + 1, gs->centerx - (gs->wordLength / 2), gs->guessWord); } else { char message[100]; - float result = 0; + sprintf(message, "Game won! Total guesses: %i", gs->guesses); mvprintw(gs->centery, gs->centerx - (strlen(message) / 2), message); + + sprintf(message, "Wrong guesses: %i, right/wrong ratio: ", gs->moves); if (gs->moves != 0) { - result = (float)((gs->guesses - gs->moves) / gs->moves); + sprintf(message + strlen(message), "%.2f", ((double)gs->guesses - (double)gs->moves) / (double)gs->moves); } else { - result = (float)((gs->guesses - gs->moves) / 1); - } - - sprintf(message, "Wrong guesses: %i, right/wrong ratio: %.2f, time: %.2fsec", gs->moves, result, diff); + sprintf(message + strlen(message), "max"); + } + + sprintf(message + strlen(message), ", time: %llusec", (unsigned long long)(gs->endTime - gs->startTime)); mvprintw(gs->centery + 1, gs->centerx - (strlen(message) / 2), message); mvprintw(gs->centery + 2, gs->centerx - (gs->wordLength / 2), gs->guessWord); } refresh(); } - + void showHelp(game_state *gs) { char *wordstring = "-w or --word: Enter the word or sentence as an argument"; char *helpstring = "-h or --help: Show this page"; @@ -383,14 +366,20 @@ int centerDiff(int coordinate, char *str) { return coordinate - (len / 2); /* Integer division */ } -void readRandomLine(char *file, char *result) { - FILE *fp = fopen(file, "r"); +int readRandomLine(char *file, char *result) { + FILE *fp; int count = 0, wordlength = 0; char line[MAXWORDLENGTH]; + + fp = fopen(file, "r"); + if (fp == NULL) { + return 1; + } + srand(time(NULL)); while (fgets(line, MAXWORDLENGTH, fp) != NULL) { count++; - if ((rand() / (float)RAND_MAX) <= (1.0 / count)) { + if ((rand() / (float)RAND_MAX) <= (1.0 / count)) { strcpy(result, line); } } @@ -398,13 +387,15 @@ void readRandomLine(char *file, char *result) { wordlength = strlen(result); result[wordlength - 1] = '\0'; fclose(fp); + + return 0; } void trollHitScreen(game_state *gs, hitfeed *hf, int hits) { if (gs->trollEnabled) { - char *strings[] = {"Double Hit", "Triple Hit", "Multi Hit", \ - "Ultra Hit", "Monster Hit", "Rampage", \ - "Unstoppable", "Wicked sick", "Godlike"}; + char *strings[] = {"Double Hit", "Triple Hit", "Multi Hit", + "Ultra Hit", "Monster Hit", "Rampage", + "Unstoppable", "Wicked sick", "Godlike"}; int selection[] = {2, 3, 4, 5, 6, 7, 8, 9, 10}; int i, found = 0; for (i = 0; i < 9; i++) { @@ -441,15 +432,15 @@ void addHitToFeed(hitfeed *hf, char *streak, int hit) { hf->besthit = hit; } } - + void printHitFeed(game_state *gs, hitfeed *hf) { if (gs->trollEnabled) { /* print the stats at the bootom right corner */ int newMaxy = gs->maxy - HITFEEDSLOTS; int newMaxx = gs->maxx - (gs->centerx / 2); int i, z; - for (i = 0; i < HITFEEDSLOTS; i++) { - for (z = 0; z < gs->maxx - newMaxx; z++) { + for (i = -1; i < HITFEEDSLOTS; i++) { + for (z = 0; z <= gs->maxx - newMaxx; z++) { mvprintw(newMaxy + i, newMaxx + z, " "); } } @@ -465,7 +456,7 @@ void printHitFeed(game_state *gs, hitfeed *hf) { } } } - + void trollHandleImpressive(hitfeed *hf, game_state *gs, int hits) { if (hits >= IMPRESSIVEHIT) { hf->impstreakcounter++; //Increase the counter @@ -484,38 +475,35 @@ void trollHandleImpressive(hitfeed *hf, game_state *gs, int hits) { mvprintw(5, gs->centerx - 5, " "); refresh(); usleep(100000); - } + } hf->impstreakcounter = 0; } } - - - void drawFigure(game_state *gs, int drawNext) { - int row = 6; - int length = 8; - int i; - static int state = 0; - if (!state) { - for (i = 0; i < row; i++) { - mvprintw(i, gs->maxx - length - 1, "%s", base_figure[i]); - } - state++; - } else { - /* Draw the stages */ - if (drawNext) { - mvprintw(stages[state - 1] + 1, gs->maxx - 4, "%s", figure[state - 1]); - state++; - } - } + int row = 6; + int length = 8; + int i; + static int state = 0; + if (!state) { + for (i = 0; i < row; i++) { + mvprintw(i, gs->maxx - length - 1, "%s", base_figure[i]); + } + state++; + } else { + /* Draw the stages */ + if (drawNext) { + mvprintw(stages[state - 1] + 1, gs->maxx - 4, "%s", figure[state - 1]); + state++; + } + } } void animateLineClear(game_state *gs, int line, int offsetMultiplier) { /* sleep and vanish */ int j = 0, k = gs->maxx, usec; usec = ((ANIM_DURATION * 1000000) + (100000 * offsetMultiplier)) / gs->maxx; - + for (j = 0; j <= gs->centerx; j++, k--) { mvprintw(line, j, "!"); mvprintw(line, k, "!"); @@ -525,5 +513,3 @@ void animateLineClear(game_state *gs, int line, int offsetMultiplier) { mvprintw(line, k, " "); } } - - diff --git a/hangman.h b/hangman.h index 7b03004..a70c3a1 100644 --- a/hangman.h +++ b/hangman.h @@ -1,18 +1,16 @@ #include - - /* Defined macros */ -#define DEFAULTTRIES 6 +#define DEFAULTTRIES 6 #define MAXWORDLENGTH 200 #define ALPHABET 26 #define ALPHABET_NUM 36 #define ANIM_DURATION 1 #define LINEBREAK 16 //Linebreak offset -#define HITFEEDSLOTS 5 -#define IMPRESSIVESTREAK 3 //reach amount of hit streaks to activate impressive screen -#define IMPRESSIVEHIT 2 +#define HITFEEDSLOTS 5 +#define IMPRESSIVESTREAK 3 //reach amount of hit streaks to activate impressive screen +#define IMPRESSIVEHIT 2 /* Data structures */ typedef struct { @@ -28,7 +26,7 @@ typedef struct { char currentWord[MAXWORDLENGTH]; char wrongCharacters[DEFAULTTRIES]; int trollEnabled; - char *alphabet; + char alphabet[ALPHABET_NUM + 1]; time_t startTime; time_t endTime; int wordRows; @@ -51,20 +49,20 @@ void quitProgram(void); void updateScreen(game_state *gs); void initCoordinates(game_state *gs); void initGuessWord(game_state *gs, char *filename); -void initAlphabet(game_state *gs); +void initAlphabet(game_state *gs); void drawAlphabet(game_state *gs, char usedchar); void drawGuessWord(game_state *gs); int playerInput(game_state *gs, hitfeed *hf); int fillCurrentWord(game_state *gs, char validchar); int stackWrongCharacter(game_state *gs, char wrongchar); int checkWin(game_state *gs); -void printGameStats(game_state *gs); +void printGameStats(game_state *gs); void toLowerCase(char *str); void showStartScreen(game_state *gs); void startGame(game_state *gs, hitfeed *hf); void showHelp(game_state *gs); int centerDiff(int coordinate, char *str); -void readRandomLine(char *file, char *result); +int readRandomLine(char *file, char *result); void trollHitScreen(game_state *gs, hitfeed *hf, int hits); void addHitToFeed(hitfeed *hf, char *streak, int hit); void trollHandleImpressive(hitfeed *hf, game_state *gs, int hits); diff --git a/makefile b/makefile index 1f9bdf0..294a9f4 100644 --- a/makefile +++ b/makefile @@ -2,8 +2,8 @@ VERSION = 1.0 -CC = gcc -CFLAGS = -Wall -g -O3 -D_REENTRANT -DVERSION=\"$(VERSION)\" +CC = cc +CFLAGS = -Wall -O3 -D_REENTRANT -DVERSION=\"$(VERSION)\" #LDFLAGS = -lm -lpthread `gtk-config --cflags` `gtk-config --libs` -lgthread LDFLAGS = -lncurses @@ -11,7 +11,7 @@ OBJ = hangman.o prng.o all: $(OBJ) $(CC) $(CFLAGS) -o hangman $(OBJ) $(LDFLAGS) - + %.o: %.c $(CC) $(CFLAGS) -c $< diff --git a/makefile_mingw b/makefile_mingw index 0437390..dc39422 100644 --- a/makefile_mingw +++ b/makefile_mingw @@ -3,7 +3,7 @@ VERSION = 1.0 CC = gcc -CFLAGS = -Wall -Wextra -O3 -D_REENTRANT -DVERSION=\"$(VERSION)\" +CFLAGS = -Wall -Wextra -O3 -D_REENTRANT -DVERSION=\"$(VERSION)\" #LDFLAGS = -lm -lpthread `gtk-config --cflags` `gtk-config --libs` -lgthread LDFLAGS = -lpdcurses @@ -11,7 +11,7 @@ OBJ = hangman.o prng.o all: $(OBJ) $(CC) $(CFLAGS) -o hangman $(OBJ) $(LDFLAGS) - + %.o: %.c $(CC) $(CFLAGS) -c $< diff --git a/prng.c b/prng.c index 2c9962d..c668a1a 100644 --- a/prng.c +++ b/prng.c @@ -44,7 +44,7 @@ void InitializePRNG(const uint32_t seed) index = N; } -static void Twist() +static void Twist(void) { uint32_t i, x, xA; @@ -64,7 +64,7 @@ static void Twist() } // Obtain a 32-bit random number -uint32_t ExtractU32() +uint32_t ExtractU32(void) { uint32_t y; int i = index; diff --git a/prng.h b/prng.h index 14ba35d..06e6d48 100644 --- a/prng.h +++ b/prng.h @@ -5,5 +5,5 @@ #include void InitializePRNG(const uint32_t seed); -uint32_t ExtractU32(); +uint32_t ExtractU32(void); int getrandom(int low, int high);