#include #include "hangman.h" #include //atexit #include #include //tolower #include #include #include "prng.h" int main(int argc, char **argv) { const char *short_options = "w:hf:c"; struct option long_options[] = { {"word", required_argument, NULL, 'w'}, {"help", no_argument, NULL, 'h'}, {"file", required_argument, NULL, 'f'}, {"credits", no_argument, NULL, 'c'} }; int c, startscr = 1; /* Show startscreen by default */ char *filename; //while ( (c = getopt_long(argc, argv, short_options, long_options, NULL)) != -1 ) /* Initialization */ initscr(); atexit(quitProgram); game_state *gs; gs = malloc(sizeof(game_state)); initCoordinates(gs); gs->allowedMoves = DEFAULTTRIES; gs->moves = 0; gs->guesses = 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); startscr = 0; break; case 'h': showHelp(gs); exit(0); break; case 'f': /* Set filename */ filename = optarg; startscr = 0; break; case 'c': break; default: break; } } InitializePRNG(time(NULL)); /* Initialize random number generator */ if (startscr) { showStartScreen(gs); } /* start game */ initGuessWord(gs, filename); startGame(gs); getch(); free(gs); return 0; } void startGame(game_state *gs) { noecho(); /* Don't show the player input */ while (checkWin(gs)) { updateScreen(gs); playerInput(gs); } } void quitProgram(void) { endwin(); } void showStartScreen(game_state *gs) { mvprintw(gs->centery - 1, gs->centerx - 15, "Welcome to hangman in ncurses."); mvprintw(gs->centery, gs->centerx - 5, "Have fun!"); mvprintw(gs->centery + 1, gs->centerx - 17, "https://gitlab.com/STRUCTiX/hangman"); refresh(); getch(); clear(); } void updateScreen(game_state *gs) { mvprintw(1, 1, "Remaining wrong guesses: %i", (gs->allowedMoves - gs->moves)); mvprintw(gs->maxy - 1, 1, "Press ctrl + c to exit."); drawGuessWord(gs); mvprintw(2, 1, "Wrong characters: %s", gs->wrongCharacters); refresh(); } void initCoordinates(game_state *gs) { getmaxyx(stdscr, gs->maxy, gs->maxx); gs->centery = gs->maxy / 2; gs->centerx = gs->maxx / 2; } 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 */ 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] = ' '; } else { gs->currentWord[i] = '_'; } } clear(); //clear the screen } void toLowerCase(char *str) { int length = strlen(str); int i; for (i = 0; i < length; i++) { str[i] = tolower(str[i]); } } void drawGuessWord(game_state *gs) { int startpos = gs->centerx - gs->wordLength; int i, wordpos = 0; int switchspace = 0; for (i = startpos; i < startpos + (gs->wordLength * 2); i++) { if (switchspace) { /* this will place a space */ mvprintw(gs->centery, i, " "); switchspace = 0; } else { mvprintw(gs->centery, i, "%c", gs->currentWord[wordpos++]); switchspace = 1; } } refresh(); } int playerInput(game_state *gs) { char inp; int i, found = 0; inp = getch(); for (i = 0; i < gs->wordLength; i++) { if (inp == gs->guessWord[i]) { found = 1; break; } } if (found) { /* found a valid character */ if (fillCurrentWord(gs, inp)) { //gs->moves++; gs->guesses++; } } else { /* no valid character found */ if (stackWrongCharacter(gs, inp)) { gs->moves++; gs->guesses++; } } return 0; } int fillCurrentWord(game_state *gs, char validchar) { int i, alreadyUsed = 0; for (i = 0; i < gs->wordLength; i++) { if (gs->currentWord[i] == validchar) { alreadyUsed = 1; break; } } if (!alreadyUsed) { for (i = 0; i < gs->wordLength; i++) { if (gs->guessWord[i] == validchar) { gs->currentWord[i] = validchar; } } return 1; } else { return 0; } } int stackWrongCharacter(game_state *gs, char wrongchar) { int i, alreadyUsed = 0; for (i = 0; i < gs->wordLength; i++) { if (gs->wrongCharacters[i] == wrongchar) { alreadyUsed = 1; } } if (!alreadyUsed) { gs->wrongCharacters[strlen(gs->wrongCharacters)] = wrongchar; return 1; } else { return 0; } } int checkWin(game_state *gs) { if (strcmp(gs->guessWord, gs->currentWord) != 0 && gs->moves < gs->allowedMoves) { /* next move */ return 1; } else { /* game end: decide if game is won or lost */ printGameStats(gs); return 0; } } void printGameStats(game_state *gs) { clear(); if (gs->moves >= gs->allowedMoves) { 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); mvprintw(gs->centery, gs->centerx - (strlen(message) / 2), message); } 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"; mvprintw(gs->centery, centerDiff(gs->centerx, wordstring), wordstring); mvprintw(gs->centery + 1, centerDiff(gs->centerx, helpstring), helpstring); getch(); } 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); }