#include #include "hangman.h" #include //atexit #include #include //tolower #include #include //time(null) #include "prng.h" #include //usleep int main(int argc, char **argv) { const char *short_options = "w:hf:ct"; struct option long_options[] = { {"word", required_argument, NULL, 'w'}, {"help", no_argument, NULL, 'h'}, {"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]; filename[0] = '\0'; //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; gs->trollEnabled = 0; keypad(stdscr, FALSE); 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 */ sprintf(filename, "%s", optarg); startscr = 0; break; case 'c': break; case 't': /* troll option */ gs->trollEnabled = 1; 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->maxy -= 1; gs->maxx -= 1; 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) { int inp; int i, found = 0; inp = getch(); if (inp != KEY_UP && inp != KEY_DOWN && inp != KEY_LEFT && inp != KEY_RIGHT) { for (i = 0; i < gs->wordLength; i++) { if (inp == gs->guessWord[i]) { found++; //break; } } if (found) { /* found a valid character */ if (fillCurrentWord(gs, inp)) { //gs->moves++; gs->guesses++; trollHitScreen(gs, found); } } 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]; float result = 0; sprintf(message, "Game won! Total guesses: %i", gs->guesses); mvprintw(gs->centery, gs->centerx - (strlen(message) / 2), message); if (gs->moves != 0) { result = (float)((gs->guesses - gs->moves) / gs->moves); } else { result = (float)((gs->guesses - gs->moves) / 1); } sprintf(message, "Wrong guesses: %i, right/wrong ratio: %.2f", gs->moves, result); mvprintw(gs->centery + 1, 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; int wordlength = 0; while ((c = fgetc(fp)) != EOF) { if (c == '\n') ++totalLength; } rand = getrandom(0, totalLength); fseek(fp, -rand, SEEK_END); fgets(result, MAXWORDLENGTH, fp); /* remove \n at the end of the line */ wordlength = strlen(result); result[wordlength - 1] = '\0'; fclose(fp); } void trollHitScreen(game_state *gs, int hits) { if (gs->trollEnabled) { 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++) { if (selection[i] == hits) { found = 1; break; } } if (hits > 10) { found = 1; i = 8; } if (found) { flash(); /* flash the screen */ mvprintw(5, centerDiff(gs->centerx, strings[i]), strings[i]); refresh(); /* sleep and vanish */ int j = 0, k = gs->maxx - 1; for (j = 0; j <= gs->centerx; j++, k--) { mvprintw(5, j, "!"); mvprintw(5, k, "!"); refresh(); usleep(8000); mvprintw(5, j, " "); mvprintw(5, k, " "); } } } }