The author is Xie Enming, an official account of Programmer Union (wechat id: CoderHub). Please indicate the source of reprint. Original: www.jianshu.com/p/6cbf45266…

The whole series of C language Exploration

Content abstract


  1. preface
  2. Subject stipulated
  3. Optimization Suggestions
  4. Part 2 Lesson 10 Notice

1. Introduction


The theoretical knowledge of the second part is basically finished. We experienced last lesson interesting exploration trip | C the second part of the eighth class: dynamic allocation.

This lesson we come to the actual combat, to achieve the game called “hanging SIMS”.

This “villain” is not the villain of “gentleman and villain”. Little man is a little man.

Reader: “Do you really have to put so much emphasis on it? It’s boring…”

All right, keep your mouth shut…

As an old saying goes, “Practice is essential!”

This is especially important for you, as we’ve just finished an advanced technical onslaught of C and need to review and digest.

No matter how good you are, in programming, you can never do without practice. Although you may have read all the previous lessons, you will not be able to understand them thoroughly without some practice.

I used to read C language books before I started programming in college, and I thought I understood them, but when I got started, I had to write programs, just like squeezing toothpaste.

This actual combat practice, we come together to achieve a small game: “hanging SIMS”, or called “hanging game”. HangMan is a popular casual puzzle game.

It’s a game, but unfortunately it doesn’t have a graphical interface (although later in the course we’ll talk about how to draw a small figure on the console, but it can also be “graphical”) : Because C itself does not have the ability to draw guIs (short for Graphical User Interface), a third-party library was needed.

Hanging SIMS game is a classic alphabet game, in a set number of steps, one letter at a time to guess the word, until you guess the whole word.

So for now, the game will be in console form (black box), but if you know how to program graphics, you can also expand the game into a graphical interface.

I believe many readers should have seen the graphical interface version of this game, is every guess a wrong letter to draw a stroke, until the specified number of times, the villain is “hanged”.

The purpose of this exercise is to review all the C language knowledge we have learned before: Pointers, strings, file reading and writing, structures, arrays, etc., are good guys!

2. According to the title


Since it is the actual combat, then we need to grievance in accordance with my title requirements to write this game.

Ok, let’s announce our title requirements:

  • Each round of the game has 7 guesses (the number of guesses can be set, not necessarily 7), and the round fails when all guesses are used up.

  • In each round, a random word is chosen from the dictionary for the player to guess, initially represented by asterisks (*). Which means all the letters are still hidden.

  • All the words of a dictionary are stored in a text file (usually TXT under Windows, or any suffix under Unix/Linux/macOS).

  • One chance is deducted for each wrong guess, and no chance is deducted for a correct guess. The correctly guessed letter is displayed among the words on the screen, replacing the asterisk.

The mechanics of a turn


Suppose the word to guess is OSCAR.

Suppose we give the program a letter B (the first letter guessed), and the program verifies that the letter is in the word.

There are two cases:

  • The guessed letter is in the word, and the program displays the word, not all of it, but the guessed letters, and the remaining unguessed letters are represented by *.

  • The guessing letter is not in the word (currently, because the letter B is not in the word OSCAR), and the program tells the player “you guessed wrong,” and one of the remaining chances is deducted. If the number of remaining opportunities becomes 0, the game ends.

In the graphical game of Hangman, one figure is drawn for every guess. Our game, while not really graphical yet, can be tuned to look something like this on the console:

Assuming the player types a C, because C is in OSCAR, the program does not deduct the player’s remaining chances, but instead displays the guessed letter, as follows:

Words: * * * * CCopy the code

If the player continues typing, this time with O, the program will display:

Words: O * * * CCopy the code

Multiple letters of the same letter


In some words, the same letter appears more than once. In APPLE, for example, the letter P appears twice; In ELEGANCE, the letter E appears three times.

Hangman’s rules for this are simple: you guess one letter, and the other repeated letters are displayed.

If the word is ELEGANCE and the user types an E, it looks like this:

Words: E * E * * * * ECopy the code

An example of a round


Welcome to hanging SIMS! You have seven chances left. What is the secret word? ***** Enter a letter: E You have 6 chances left What is the mystery word? ***** Enter a letter: S You have 6 chances left What is the mystery word? *S*** Enter a letter: R You have 6 chances left What is the mystery word? *S**R Enter a letter:Copy the code

The game continues until the player guesses the word before running out of seven chances, or the game is over.

Such as:


You have two more chances. What is the secret word? OS*AR enter a letter: C victory! The mystery word: OSCARCopy the code

Enter a letter in the console


Getting a program to read a letter in the console may seem simple, but it can be tricky. Let’s try it.

To enter a letter, you usually think of it this way:

scanf("%c", &myLetter);
Copy the code

This is good because %c indicates that a character is waiting for the user to enter. The input character is stored in the variable myLetter (type char).

If we just write a scanf, that’s fine. But what if there are several scanfs? Let’s test it out:

int main(int argc, char* argv[])
{
    char myLetter = 0;

    scanf("%c", &myLetter);
    printf("%c", myLetter);

    scanf("%c", &myLetter);
    printf("%c", myLetter);

    return 0;
}
Copy the code

As we imagine, the program would ask the user to type a character and print it out: twice.

So let’s test that out. What does it look like? You enter a character, yes, and then…

The program prints out for you the character you typed, and if you typed a, the program prints out

a
Copy the code

And then the program exits, nothing more. Why not prompt me for the second character? As if it ignores the second scanf. So what happened?

In fact, when you type on the Console, everything you type is recorded somewhere in memory, including when you press Enter:

\n
Copy the code

So, you type a character (for example, a), and then you hit the Enter key:

The character a is taken by the first scanf, and your enter key (\n) is taken by the second scanf.

To avoid this problem, we write a function readCharacter() to handle it:

char readCharacter() { char character = 0; character = getchar(); // Read the first character of the input character = toupper(character); // Read other characters up to \n (to ignore them)while(getchar() ! ='\n');returncharacter; // Return the first letter read}Copy the code

As you can see, we used the getchar function in the stdio.h library to read a character typed by the user

scanf("%c", &letter);
Copy the code

Then, we use a function that we haven’t studied in this course: toupper.

To + upper converts a letter to uppercase letters.

As you can see, if a function is well named, there is almost no need for comments, and the name tells you roughly what it does.

With the toupper function, the player can type in lowercase or uppercase letters, because in “Hang The Little Man” we display words in uppercase letters.

The toupper function is defined in the ctype.h library header file, so it is required

#include <ctype.h>
Copy the code

Moving on to our function, we can see that the most important thing is:

while(getchar() ! ='\n');Copy the code

This little piece of code allows us to clear all characters other than the first typed letter until we encounter \n (carriage return).

The function returns the first character typed, ensuring that carriage returns are not affected by carriage returns.

We used a while loop with only a semicolon (;) in the body. Pretty neat.

You might be asking yourself, in the previous video, didn’t the body of the while loop have curly braces around it, why is there only a semicolon?

In fact, this semicolon is the equivalent of

{}Copy the code

The empty loop body does nothing, so the above code is equivalent to:

while(getchar() ! ='\n') {}Copy the code

But isn’t a semicolon easier to write than braces? Programmers are lazy people!

This while loop continues until the user enters a carriage return and all other characters are cleared from memory, which we call “clearing the buffer.”

Therefore:

In order to read user input one letter at a time in our program, we do not use

scanf("%c", &myLetter);
Copy the code

Instead, we need to use the function we wrote:

myLetter = readCharacter();
Copy the code

So, our test program looks like this:

#include <stdio.h>
#include <ctype.h>

char readCharacter() { char character = 0; character = getchar(); // Read a letter character = toupper(character); // Read other characters until \n (to ignore it)while(getchar() ! ='\n');returncharacter; } int main(int argc, char* argv[]) {char myLetter = 0; myLetter =readCharacter();

    printf("%c\n", myLetter);

    myLetter = readCharacter();

    printf("%c\n", myLetter);

    return 0;
}
Copy the code

Run, the output looks like this (if the user types O, press Enter; Enter k, press Enter) :

o
O
k
K
Copy the code

Dictionary/thesaurus


Because our game is written step by step, it’s important to start with something simple and then improve it.

So we start with just one guessing word. So, we’ll start with this:

char secretWord[] = "BOTTLE";
Copy the code

You say, “Isn’t that boring? It’s always the same guessing word.”

Yes, but then we will definitely expand. The idea was to do one thing at a time and not complicate things.

Then, if the code is ready to guess a word, we can store all possible words in a file called ‘dictionary’.

What is a dictionary or thesaurus?

In our case, it’s a file, and each line of the file holds a word, and then our program randomly picks one word from the file as the guessing word for each round.

The thesaurus looks something like this:

YOU
MOTHER
LOVE
PANDA
BOTTLE
FUNNY
HONEY
LIKE
JAZZ
MUSIC
BREAD
APPLE
WATER
PEOPLE
Copy the code

As for how many words are in the file, since our thesaurus is extensible (we can definitely add new words later), it’s really just a matter of counting carriage returns (\n), since it’s one word per line.

Ok, so that’s the basics of the game, but with the basics of all the previous lessons, you have the ability to do what seems like a complicated game, but it’s not easy to organize it well, and you can use multiple functions to do different things.

Come on, perseverance is victory, look forward to your results!

3. Optimization suggestions


If you are compiling under Windows using an IDE such as CodeBlocks, change the dictionary file to dictionary.txt. Because Windows stores files differently from Linux/Unix/macOS.

To improve the game


  1. For now, we only let players play one round, but it would be “really nice” to add a loop so that each time the game asks the player if they want to play again.

  2. It’s still single-player mode, but you can create a two-player mode, where one player types in a word and the second player guesses.

  3. Why not use the printf function to print (draw) a hanging figure? Every time we guess wrong, we draw it. For each mistake, we draw one more stroke. This can increase the fun.

if(guess wrong 1 letter) {printf(" _____\n");
    printf(" | |\n");
    printf(" | O\n");
    printf(" |\n");
    printf(" |\n");
    printf(" |\n");
    printf(" |\n");
    printf("_|__\n");
}
else if(guess wrong 2 letters) {printf(" _____\n");
    printf(" | |\n");
    printf(" | O\n");
    printf(" | |\n");
    printf(" |\n");
    printf(" |\n");
    printf(" |\n");
    printf("_|__\n");
}
else if(guess wrong 3 letters) {printf(" _____\n");
    printf(" | |\n");
    printf(" | O\n");
    printf(" | \\|\n");
    printf(" |\n");
    printf(" |\n");
    printf(" |\n");
    printf("_|__\n");
}
else if(guess wrong 4 letters) {printf(" _____\n");
    printf(" | |\n");
    printf(" | O\n");
    printf(" | \\|/\n");
    printf(" |\n");
    printf(" |\n");
    printf(" |\n");
    printf("_|__\n");
}
else if(guess wrong 5 letters) {printf(" _____\n");
    printf(" | |\n");
    printf(" | O\n");
    printf(" | \\|/\n");
    printf(" | |\n");
    printf(" |\n");
    printf(" |\n");
    printf("_|__\n");
}
else if(guess wrong 6 letters) {printf(" _____\n");
    printf(" | |\n");
    printf(" | O\n");
    printf(" | \\|/\n");
    printf(" | |\n");
    printf(" | /\n");
    printf(" |\n");
    printf("_|__\n");
}
else if(guess wrong 7 letters) {printf(" _____\n");
    printf(" | |\n");
    printf(" | O\n");
    printf(" | \\|/\n");
    printf(" | |\n");
    printf(" | / \\\n");
    printf(" |\n");
    printf("_|__\n");
}
Copy the code

The Spaces in the code above may appear differently on different platforms and may need to be adjusted.

If all 7 opportunities are used up, the villain dies and the game ends.

Please take the time to understand the game and improve it as much as possible. If you can finish the game and improve it without looking at our answers, you’ll get a lot!

4. Part 2 Lesson 10 Notice


That’s all for today’s lesson, come on!

In the next lesson, we will reveal the solution and the answer to hanging SIMS.

Next lesson: C exploration trip | the second part of the first lesson 10: practical answer “hanging man” game


My name is Xie Enming, the operator of the public account “Programmer Union” (wechat id: CoderHub), the moOCs elite lecturer Oscar, and a lifelong learner. Love life, like swimming, a little cooking. Life motto: “Run straight for the pole”