-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
/
Copy pathhangman.c
291 lines (241 loc) · 7.86 KB
/
hangman.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
/**
* @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;
}
}