mirror of
https://github.com/TheAlgorithms/C
synced 2024-11-25 06:49:36 +03:00
71a7cf3bc4
* Add files via upload feat: added hangman game #967 * Update hangman.c * Update hangman.c * Update hangman.c * Update hangman.c * Update hangman.c * Update hangman.c Updated so that game instance was held as struct - can include current guess in game_instance too if preferred. * Update hangman.c * Update hangman.c * Add files via upload Adding test file * Update hangman.c * Update hangman.c Co-authored-by: David Leal <halfpacho@gmail.com> Co-authored-by: Sharon "Cass" Cassidy <monadicdiffusive@proton.me>
292 lines
7.9 KiB
C
292 lines
7.9 KiB
C
/**
|
|
* @file
|
|
* @brief C implementation of [Hangman Game](https://en.wikipedia.org/wiki/Hangman_(game))
|
|
* @details
|
|
* Simple, readable version of hangman.
|
|
* Changed graphic to duck instead of traditional stick figure (same number of guesses).
|
|
* @author [AtlantaEmrys2002](https://github.com/AtlantaEmrys2002)
|
|
*/
|
|
|
|
#include <ctype.h> /// for main() - tolower()
|
|
#include <stdio.h> /// for main(), new_word(), new_guess(), won() - I/O operations
|
|
#include <stdlib.h> /// for all functions - exit(), rand() and file functions
|
|
#include <string.h> /// for main() - for string operations strlen, strchr, strcpy
|
|
#include <time.h> /// for new_game() - used with srand() for declaring new game instance
|
|
|
|
/*
|
|
* @brief game_instance structure that holds current state of game
|
|
*/
|
|
struct game_instance{
|
|
|
|
char current_word[30]; ///< word to be guessed by player
|
|
char hidden[30]; ///< hidden version of word that is displayed to player
|
|
int size; ///< size of word
|
|
int incorrect; ///< number of incorrect guesses
|
|
char guesses[25]; ///< previous guesses
|
|
int guesses_size; ///< size of guesses array
|
|
|
|
};
|
|
|
|
// function prototypes
|
|
struct game_instance new_game(void); // creates a new game
|
|
int new_guess(char, const char guesses[], int size); // checks if player has already played letter
|
|
int in_word(char, const char word[], unsigned int size); // checks if letter is in word
|
|
void picture(int score); // outputs image of duck (instead of hang man)
|
|
void won(const char word[], int score); // checks if player has won or lost
|
|
|
|
/**
|
|
* @brief Main Function
|
|
* @returns 0 on exit
|
|
*/
|
|
int main() {
|
|
|
|
struct game_instance game = new_game(); // new game created
|
|
char guess; // current letter guessed by player
|
|
|
|
// main loop - asks player for guesses
|
|
while ((strchr(game.hidden, '_') != NULL) && game.incorrect <= 12) {
|
|
do {
|
|
printf("\n****************************\n");
|
|
printf("Your word: ");
|
|
|
|
for (int i = 0; i < game.size; i++) {
|
|
printf("%c ", game.hidden[i]);
|
|
}
|
|
|
|
if (game.guesses_size > 0) {
|
|
printf("\nSo far, you have guessed: ");
|
|
for (int i = 0; i < game.guesses_size; i++) {
|
|
printf("%c ", game.guesses[i]);
|
|
}
|
|
}
|
|
|
|
printf("\nYou have %d guesses left.", (12 - game.incorrect));
|
|
printf("\nPlease enter a letter: ");
|
|
scanf(" %c", &guess);
|
|
guess = tolower(guess);
|
|
|
|
} while (new_guess(guess, game.guesses, game.guesses_size) != -1);
|
|
|
|
game.guesses[game.guesses_size] = guess; // adds new letter to guesses array
|
|
game.guesses_size++; // updates size of guesses array
|
|
|
|
if (in_word(guess, game.current_word, game.size) == 1) {
|
|
printf("That letter is in the word!");
|
|
for (int i = 0; i < game.size; i++) {
|
|
if ((game.current_word[i]) == guess) {
|
|
game.hidden[i] = guess;
|
|
}
|
|
}
|
|
} else {
|
|
printf("That letter is not in the word.\n");
|
|
(game.incorrect)++;
|
|
}
|
|
picture(game.incorrect);
|
|
}
|
|
|
|
won(game.current_word, game.incorrect);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief checks if letter has been guessed before
|
|
* @param new_guess letter that has been guessed by player
|
|
* @param guesses array of player's previous guesses
|
|
* @param size size of guesses[] array
|
|
* @returns 1 if letter has been guessed before
|
|
* @returns -1 if letter has not been guessed before
|
|
*/
|
|
int new_guess(char new_guess, const char guesses[], int size) {
|
|
|
|
for (int j = 0; j < size; j++) {
|
|
if (guesses[j] == new_guess) {
|
|
printf("\nYou have already guessed that letter.");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* @brief checks if letter is in current word
|
|
* @param letter letter guessed by player
|
|
* @param word current word
|
|
* @param size length of word
|
|
* @returns 1 if letter is in word
|
|
* @returns -1 if letter is not in word
|
|
*/
|
|
int in_word(char letter, const char word[], unsigned int size) {
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
if ((word[i]) == letter) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* @brief creates a new game - generates a random word and stores in global variable current_word
|
|
* @returns current_game - a new game instance containing randomly selected word, its length and hidden version of word
|
|
*/
|
|
struct game_instance new_game() {
|
|
|
|
char word[30]; // used throughout function
|
|
|
|
FILE *fptr;
|
|
fptr = fopen("games/words.txt", "r");
|
|
|
|
if (fptr == NULL){
|
|
fprintf(stderr, "File not found.\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
// counts number of words in file - assumes each word on new line
|
|
int line_number = 0;
|
|
while (fgets(word, 30, fptr) != NULL) {
|
|
line_number++;
|
|
}
|
|
|
|
rewind(fptr);
|
|
|
|
// generates random number
|
|
int random_num;
|
|
srand(time(NULL));
|
|
random_num = rand() % line_number;
|
|
|
|
// selects randomly generated word
|
|
int s = 0;
|
|
while (s <= random_num){
|
|
fgets(word, 30, fptr);
|
|
s++;
|
|
}
|
|
|
|
// formats string correctly
|
|
if (strchr(word, '\n') != NULL){
|
|
word[strlen(word) - 1] = '\0';
|
|
}
|
|
|
|
fclose(fptr);
|
|
|
|
// creates new game instance
|
|
struct game_instance current_game;
|
|
strcpy(current_game.current_word, word);
|
|
current_game.size = strlen(word);
|
|
for (int i = 0; i < (strlen(word)); i++) {
|
|
current_game.hidden[i] = '_';
|
|
}
|
|
current_game.incorrect = 0;
|
|
current_game.guesses_size = 0;
|
|
|
|
return current_game;
|
|
}
|
|
|
|
/**
|
|
* @brief checks if player has won or lost
|
|
* @param word the word player has attempted to guess
|
|
* @param score how many incorrect guesses player has made
|
|
* @returns void
|
|
*/
|
|
void won(const char word[], int score) {
|
|
if (score > 12) {
|
|
printf("\nYou lost! The word was: %s.\n", word);
|
|
}
|
|
else {
|
|
printf("\nYou won! You had %d guesses left.\n", (12 - score));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* @brief gradually draws duck as player gets letters incorrect
|
|
* @param score how many incorrect guesses player has made
|
|
* @returns void
|
|
*/
|
|
void picture(int score) {
|
|
|
|
switch(score) {
|
|
|
|
case 12:
|
|
printf("\n _\n"
|
|
" __( ' )> \n"
|
|
" \\_ < _ ) ");
|
|
break;
|
|
|
|
case 11:
|
|
printf("\n _\n"
|
|
" __( ' )\n"
|
|
" \\_ < _ ) ");
|
|
break;
|
|
|
|
case 10:
|
|
printf("\n _\n"
|
|
" __( )\n"
|
|
" \\_ < _ ) ");
|
|
break;
|
|
|
|
case 9:
|
|
printf("\n \n"
|
|
" __( )\n"
|
|
" \\_ < _ ) ");
|
|
break;
|
|
|
|
case 8:
|
|
printf("\n \n"
|
|
" __( \n"
|
|
" \\_ < _ ) ");
|
|
break;
|
|
|
|
case 7:
|
|
printf("\n \n"
|
|
" __ \n"
|
|
" \\_ < _ ) ");
|
|
break;
|
|
|
|
case 6:
|
|
printf("\n \n"
|
|
" _ \n"
|
|
" \\_ < _ ) ");
|
|
break;
|
|
|
|
case 5:
|
|
printf("\n \n"
|
|
" _ \n"
|
|
" _ < _ ) ");
|
|
break;
|
|
|
|
case 4:
|
|
printf("\n \n"
|
|
" \n"
|
|
" _ < _ ) ");
|
|
break;
|
|
|
|
case 3:
|
|
printf("\n \n"
|
|
" \n"
|
|
" < _ ) ");
|
|
break;
|
|
|
|
case 2:
|
|
printf("\n \n"
|
|
" \n"
|
|
" _ ) ");
|
|
break;
|
|
|
|
case 1:
|
|
printf("\n \n"
|
|
" \n"
|
|
" ) ");
|
|
break;
|
|
|
|
case 0:
|
|
break;
|
|
|
|
default:
|
|
printf("\n _\n"
|
|
" __( ' )> QUACK!\n"
|
|
" \\_ < _ ) ");
|
|
break;
|
|
}
|
|
}
|