From 37b129b81116fb049a728bde0dd9120a86d22c59 Mon Sep 17 00:00:00 2001 From: structix Date: Tue, 2 May 2017 18:22:29 +0200 Subject: [PATCH] Random word from file #5 --- hangman.c | 42 +++++++++++++++++++++---- hangman.h | 6 ++-- makefile | 2 +- prng.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ prng.h | 9 ++++++ 5 files changed, 141 insertions(+), 9 deletions(-) create mode 100644 prng.c create mode 100644 prng.h diff --git a/hangman.c b/hangman.c index 570f9fe..37e7254 100644 --- a/hangman.c +++ b/hangman.c @@ -4,7 +4,8 @@ #include #include //tolower #include - +#include +#include "prng.h" int main(int argc, char **argv) { @@ -55,7 +56,8 @@ int main(int argc, char **argv) { break; } } - + InitializePRNG(time(NULL)); /* Initialize random number generator */ + if (startscr) { showStartScreen(gs); } @@ -112,12 +114,22 @@ void initGuessWord(game_state *gs, char *filename) { int i; mvprintw(1, 1, "Please enter your word: "); if (strlen(gs->guessWord) == 0) { /* Word can be set by arguments */ - curs_set(1); - getstr(gs->guessWord); - curs_set(0); + if (strlen(filename) == 0) { + /* Manual input */ + curs_set(1); + getstr(gs->guessWord); + curs_set(0); + } else { + /* Random line from file */ + readRandomLine(filename, gs->guessWord); + } + } + + /* Make String all lowercase */ toLowerCase(gs->guessWord); gs->wordLength = strlen(gs->guessWord); + for (i = 0; i < gs->wordLength; i++) { if (gs->guessWord[i] == ' ') { //Check for spaces if it's a sentence gs->currentWord[i] = ' '; @@ -230,7 +242,8 @@ int checkWin(game_state *gs) { void printGameStats(game_state *gs) { clear(); if (gs->moves >= gs->allowedMoves) { - mvprintw(gs->centery, gs->centerx - 5, "Game lost."); + mvprintw(gs->centery, gs->centerx - 10, "Game lost. Solution:"); + mvprintw(gs->centery + 1, gs->centerx - (gs->wordLength / 2), gs->guessWord); } else { char message[100]; sprintf(message, "Game won! Total guesses: %i", gs->guesses); @@ -251,3 +264,20 @@ int centerDiff(int coordinate, char *str) { int len = strlen(str); return coordinate - (len / 2); /* Integer division */ } + +void readRandomLine(char *file, char *result) { + long totalLength = 0, rand = 0; + FILE *fp = fopen(file, "r"); + char c; + + while ((c = fgetc(fp)) != EOF) { + if (c == '\n') ++totalLength; + } + + rand = getrandom(0, totalLength); + fseek(fp, rand, SEEK_SET); + + fgets(result, MAXWORDLENGTH, fp); + + fclose(fp); +} diff --git a/hangman.h b/hangman.h index 6dc236d..661e5e3 100644 --- a/hangman.h +++ b/hangman.h @@ -1,5 +1,6 @@ /* Defined macros */ #define DEFAULTTRIES 9 +#define MAXWORDLENGTH 100 /* Data structures */ typedef struct { @@ -10,9 +11,9 @@ typedef struct { int maxx; int centery; int centerx; - char guessWord[100]; + char guessWord[MAXWORDLENGTH]; int wordLength; - char currentWord[100]; + char currentWord[MAXWORDLENGTH]; char wrongCharacters[DEFAULTTRIES]; } game_state; @@ -38,3 +39,4 @@ void showStartScreen(game_state *gs); void startGame(game_state *gs); void showHelp(game_state *gs); int centerDiff(int coordinate, char *str); +void readRandomLine(char *file, char *result); diff --git a/makefile b/makefile index 84216ae..97c4583 100644 --- a/makefile +++ b/makefile @@ -7,7 +7,7 @@ CFLAGS = -Wall -g -D_REENTRANT -DVERSION=\"$(VERSION)\" #LDFLAGS = -lm -lpthread `gtk-config --cflags` `gtk-config --libs` -lgthread LDFLAGS = -lncurses -OBJ = hangman.o +OBJ = hangman.o prng.o all: $(OBJ) $(CC) $(CFLAGS) -o hangman $(OBJ) $(LDFLAGS) diff --git a/prng.c b/prng.c new file mode 100644 index 0000000..2c9962d --- /dev/null +++ b/prng.c @@ -0,0 +1,91 @@ + +#include "prng.h" +// Define MT19937 constants (32-bit RNG) +enum +{ + // Assumes W = 32 (omitting this) + N = 624, + M = 397, + R = 31, + A = 0x9908B0DF, + + F = 1812433253, + + U = 11, + // Assumes D = 0xFFFFFFFF (omitting this) + + S = 7, + B = 0x9D2C5680, + + T = 15, + C = 0xEFC60000, + + L = 18, + + MASK_LOWER = (1ull << R) - 1, + MASK_UPPER = (1ull << R) +}; + +static uint32_t mt[N]; +static uint16_t index; + +// Re-init with a given seed +void InitializePRNG(const uint32_t seed) +{ + uint32_t i; + + mt[0] = seed; + + for ( i = 1; i < N; i++ ) + { + mt[i] = (F * (mt[i - 1] ^ (mt[i - 1] >> 30)) + i); + } + + index = N; +} + +static void Twist() +{ + uint32_t i, x, xA; + + for ( i = 0; i < N; i++ ) + { + x = (mt[i] & MASK_UPPER) + (mt[(i + 1) % N] & MASK_LOWER); + + xA = x >> 1; + + if ( x & 0x1 ) + xA ^= A; + + mt[i] = mt[(i + M) % N] ^ xA; + } + + index = 0; +} + +// Obtain a 32-bit random number +uint32_t ExtractU32() +{ + uint32_t y; + int i = index; + + if ( index >= N ) + { + Twist(); + i = index; + } + + y = mt[i]; + index = i + 1; + + y ^= (mt[i] >> U); + y ^= (y << S) & B; + y ^= (y << T) & C; + y ^= (y >> L); + + return y; +} + +int getrandom(int low, int high) { + return ((ExtractU32() % high) + low); +} diff --git a/prng.h b/prng.h new file mode 100644 index 0000000..14ba35d --- /dev/null +++ b/prng.h @@ -0,0 +1,9 @@ +/** + * Pseudo random number generator using the Mersenne Twister algorithm + * This code was taken from wikipedia: https://en.wikipedia.org/wiki/Mersenne_Twister + */ +#include + +void InitializePRNG(const uint32_t seed); +uint32_t ExtractU32(); +int getrandom(int low, int high);