Skip to content

Commit 71a7cf3

Browse files
AtlantaEmrys2002Panquesito7CascadingCascade
authored
feat: added hangman game #967 (#1248)
* 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 <[email protected]> Co-authored-by: Sharon "Cass" Cassidy <[email protected]>
1 parent 2b88510 commit 71a7cf3

File tree

2 files changed

+299
-0
lines changed

2 files changed

+299
-0
lines changed

games/hangman.c

+291
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
/**
2+
* @file
3+
* @brief C implementation of [Hangman Game](https://en.wikipedia.org/wiki/Hangman_(game))
4+
* @details
5+
* Simple, readable version of hangman.
6+
* Changed graphic to duck instead of traditional stick figure (same number of guesses).
7+
* @author [AtlantaEmrys2002](https://github.com/AtlantaEmrys2002)
8+
*/
9+
10+
#include <ctype.h> /// for main() - tolower()
11+
#include <stdio.h> /// for main(), new_word(), new_guess(), won() - I/O operations
12+
#include <stdlib.h> /// for all functions - exit(), rand() and file functions
13+
#include <string.h> /// for main() - for string operations strlen, strchr, strcpy
14+
#include <time.h> /// for new_game() - used with srand() for declaring new game instance
15+
16+
/*
17+
* @brief game_instance structure that holds current state of game
18+
*/
19+
struct game_instance{
20+
21+
char current_word[30]; ///< word to be guessed by player
22+
char hidden[30]; ///< hidden version of word that is displayed to player
23+
int size; ///< size of word
24+
int incorrect; ///< number of incorrect guesses
25+
char guesses[25]; ///< previous guesses
26+
int guesses_size; ///< size of guesses array
27+
28+
};
29+
30+
// function prototypes
31+
struct game_instance new_game(void); // creates a new game
32+
int new_guess(char, const char guesses[], int size); // checks if player has already played letter
33+
int in_word(char, const char word[], unsigned int size); // checks if letter is in word
34+
void picture(int score); // outputs image of duck (instead of hang man)
35+
void won(const char word[], int score); // checks if player has won or lost
36+
37+
/**
38+
* @brief Main Function
39+
* @returns 0 on exit
40+
*/
41+
int main() {
42+
43+
struct game_instance game = new_game(); // new game created
44+
char guess; // current letter guessed by player
45+
46+
// main loop - asks player for guesses
47+
while ((strchr(game.hidden, '_') != NULL) && game.incorrect <= 12) {
48+
do {
49+
printf("\n****************************\n");
50+
printf("Your word: ");
51+
52+
for (int i = 0; i < game.size; i++) {
53+
printf("%c ", game.hidden[i]);
54+
}
55+
56+
if (game.guesses_size > 0) {
57+
printf("\nSo far, you have guessed: ");
58+
for (int i = 0; i < game.guesses_size; i++) {
59+
printf("%c ", game.guesses[i]);
60+
}
61+
}
62+
63+
printf("\nYou have %d guesses left.", (12 - game.incorrect));
64+
printf("\nPlease enter a letter: ");
65+
scanf(" %c", &guess);
66+
guess = tolower(guess);
67+
68+
} while (new_guess(guess, game.guesses, game.guesses_size) != -1);
69+
70+
game.guesses[game.guesses_size] = guess; // adds new letter to guesses array
71+
game.guesses_size++; // updates size of guesses array
72+
73+
if (in_word(guess, game.current_word, game.size) == 1) {
74+
printf("That letter is in the word!");
75+
for (int i = 0; i < game.size; i++) {
76+
if ((game.current_word[i]) == guess) {
77+
game.hidden[i] = guess;
78+
}
79+
}
80+
} else {
81+
printf("That letter is not in the word.\n");
82+
(game.incorrect)++;
83+
}
84+
picture(game.incorrect);
85+
}
86+
87+
won(game.current_word, game.incorrect);
88+
return 0;
89+
}
90+
91+
/**
92+
* @brief checks if letter has been guessed before
93+
* @param new_guess letter that has been guessed by player
94+
* @param guesses array of player's previous guesses
95+
* @param size size of guesses[] array
96+
* @returns 1 if letter has been guessed before
97+
* @returns -1 if letter has not been guessed before
98+
*/
99+
int new_guess(char new_guess, const char guesses[], int size) {
100+
101+
for (int j = 0; j < size; j++) {
102+
if (guesses[j] == new_guess) {
103+
printf("\nYou have already guessed that letter.");
104+
return 1;
105+
}
106+
}
107+
108+
return -1;
109+
}
110+
111+
/**
112+
* @brief checks if letter is in current word
113+
* @param letter letter guessed by player
114+
* @param word current word
115+
* @param size length of word
116+
* @returns 1 if letter is in word
117+
* @returns -1 if letter is not in word
118+
*/
119+
int in_word(char letter, const char word[], unsigned int size) {
120+
121+
for (int i = 0; i < size; i++) {
122+
if ((word[i]) == letter) {
123+
return 1;
124+
}
125+
}
126+
127+
return -1;
128+
}
129+
130+
/**
131+
* @brief creates a new game - generates a random word and stores in global variable current_word
132+
* @returns current_game - a new game instance containing randomly selected word, its length and hidden version of word
133+
*/
134+
struct game_instance new_game() {
135+
136+
char word[30]; // used throughout function
137+
138+
FILE *fptr;
139+
fptr = fopen("games/words.txt", "r");
140+
141+
if (fptr == NULL){
142+
fprintf(stderr, "File not found.\n");
143+
exit(EXIT_FAILURE);
144+
}
145+
146+
// counts number of words in file - assumes each word on new line
147+
int line_number = 0;
148+
while (fgets(word, 30, fptr) != NULL) {
149+
line_number++;
150+
}
151+
152+
rewind(fptr);
153+
154+
// generates random number
155+
int random_num;
156+
srand(time(NULL));
157+
random_num = rand() % line_number;
158+
159+
// selects randomly generated word
160+
int s = 0;
161+
while (s <= random_num){
162+
fgets(word, 30, fptr);
163+
s++;
164+
}
165+
166+
// formats string correctly
167+
if (strchr(word, '\n') != NULL){
168+
word[strlen(word) - 1] = '\0';
169+
}
170+
171+
fclose(fptr);
172+
173+
// creates new game instance
174+
struct game_instance current_game;
175+
strcpy(current_game.current_word, word);
176+
current_game.size = strlen(word);
177+
for (int i = 0; i < (strlen(word)); i++) {
178+
current_game.hidden[i] = '_';
179+
}
180+
current_game.incorrect = 0;
181+
current_game.guesses_size = 0;
182+
183+
return current_game;
184+
}
185+
186+
/**
187+
* @brief checks if player has won or lost
188+
* @param word the word player has attempted to guess
189+
* @param score how many incorrect guesses player has made
190+
* @returns void
191+
*/
192+
void won(const char word[], int score) {
193+
if (score > 12) {
194+
printf("\nYou lost! The word was: %s.\n", word);
195+
}
196+
else {
197+
printf("\nYou won! You had %d guesses left.\n", (12 - score));
198+
}
199+
}
200+
201+
/*
202+
* @brief gradually draws duck as player gets letters incorrect
203+
* @param score how many incorrect guesses player has made
204+
* @returns void
205+
*/
206+
void picture(int score) {
207+
208+
switch(score) {
209+
210+
case 12:
211+
printf("\n _\n"
212+
" __( ' )> \n"
213+
" \\_ < _ ) ");
214+
break;
215+
216+
case 11:
217+
printf("\n _\n"
218+
" __( ' )\n"
219+
" \\_ < _ ) ");
220+
break;
221+
222+
case 10:
223+
printf("\n _\n"
224+
" __( )\n"
225+
" \\_ < _ ) ");
226+
break;
227+
228+
case 9:
229+
printf("\n \n"
230+
" __( )\n"
231+
" \\_ < _ ) ");
232+
break;
233+
234+
case 8:
235+
printf("\n \n"
236+
" __( \n"
237+
" \\_ < _ ) ");
238+
break;
239+
240+
case 7:
241+
printf("\n \n"
242+
" __ \n"
243+
" \\_ < _ ) ");
244+
break;
245+
246+
case 6:
247+
printf("\n \n"
248+
" _ \n"
249+
" \\_ < _ ) ");
250+
break;
251+
252+
case 5:
253+
printf("\n \n"
254+
" _ \n"
255+
" _ < _ ) ");
256+
break;
257+
258+
case 4:
259+
printf("\n \n"
260+
" \n"
261+
" _ < _ ) ");
262+
break;
263+
264+
case 3:
265+
printf("\n \n"
266+
" \n"
267+
" < _ ) ");
268+
break;
269+
270+
case 2:
271+
printf("\n \n"
272+
" \n"
273+
" _ ) ");
274+
break;
275+
276+
case 1:
277+
printf("\n \n"
278+
" \n"
279+
" ) ");
280+
break;
281+
282+
case 0:
283+
break;
284+
285+
default:
286+
printf("\n _\n"
287+
" __( ' )> QUACK!\n"
288+
" \\_ < _ ) ");
289+
break;
290+
}
291+
}

games/words.txt

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
dog
2+
cat
3+
tree
4+
flower
5+
table
6+
programming
7+
language
8+
testing

0 commit comments

Comments
 (0)