Review of new features

In this lesson, we learned about a few new features. Let's recap some of the features.

The most important additional feature of D in this lesson was the introduction of arrays. An array is like a list of things. Those things can be integers, strings, and actually any type that the D language supports.

One declares an array using square brackets:

int[] arr = [1, 2, 3]; // an array containing the integers 1, 2, 3

In order to add to the end of the array, one uses the append operator, ~=:

arr ~= 4; // add 4 to the end of the array

If you want to use just one item from the array, you use indexing. Indexing means give me the item that has this index. In D (and many other langauges) the index starts at 0:

writeln(arr[1]); // write the second element in the array, 2

You can get the length of an array (number of items) by using the length property:

writeln(arr.length); // writes the number of items, 4

The next thing we learned is foreach. foreach allows us to loop exactly over an entire array, with a variable set to each value in the array. A foreach statement looks like this:

foreach(item; arr) {
   // inside here, `item` is set to the next array element
   writeln("item is ", item);
}

So inside the loop, we can use item to do some checking. The loop automatically ends after the last item in the array has been processed. Of course, we can end it early by using the break; statement.

You can also get the index of each item, by providing a second variable name for the index. This is useful if you need the index for accessing a second array (as we needed to do in our hangman game):

foreach(index, item; arr) {
   // inside here, `item` is set to the next array element,
   // and `index` is the index of the item (0, 1, 2, ...)
   writeln("item at index ", index, " is ", item);
}

One final thing we learned is that string is actually an array of char. A char represents a character in a string, and you can access characters by index just like a normal array. We used this to be able to tell which letters were now correct when looping over the secret string.

Homework assignment - Improve hangman

Here is the code that we had at the end of the class:

import std.stdio;

void main()
{
    // game state
    // 1. secret word
    string secret = "hello";
    // 2. how many letters guessed wrong
    int wrongGuesses = 0;
    // 3. current correct word (with underscores for missing letters)
    char[] currentWord;

    int maxGuesses = 6; // this configures how many "hangman" segments means you lose.

    // setup game state
    foreach (char c; secret) // for each charcter in the secret
    {
        currentWord ~= '_'; // add an underscore to the current word.
    }

    while(wrongGuesses < maxGuesses) // while we haven't exceeded the incorrect guesses
    {
        // update output
        writeln("Current word: ", currentWord); // tell the user what has been guessed so far
        writeln("Wrong guesses: ", wrongGuesses); // tell the user how many wrong guesses
        writeln("Guess a letter"); // prompt for a guess
        // consume inputs
        char guess;
        readf("%s\n", guess); // read the guess

        // update game state
        bool guessCorrect = false; // this will be set to true if any letters matched the guess

        // loop over all characters in the secret word. In the loop, `c` is set to the character
        // in the secret string, and `index` is set to the index of the character (starting at 0)
        foreach (index, c; secret)
        {
            if(c == guess) // does the guess match this letter
            {
                // If the guess was correct, we need to change the matching character in the current word
                // to the correct character (it could be an underscore).
                currentWord[index] = c;
                guessCorrect = true; // the guess was correct!
            }
        }

        if(guessCorrect == false) // if no correct guesses were found
        {
            ++wrongGuesses; // add one to the wrong guesses. ++var means increment the variable by 1
        }
        if(currentWord == secret) // if the word is complete (no underscores are left)
        {
            break; // break out of the loop
        }
    }

    // check win or lose
    if(currentWord == secret)
    {
        writeln("You win!");
    }
    writeln("The word was: ", secret); // tell the user what the full word is (in case he didn't guess it)
}

First, the game isn't very hard to play, it always picks the same word. So playing more than once is not enjoyable! We should have a list of words that we pick a random word from, and use that as the secret. A full-blown hangman game probably uses a very extensive English dictionary to pick the words. But we will just pick a few words. Here is the list of words that I got from you in the discord chat:

  1. pineapple
  2. orange
  3. grapefruit
  4. apple
  5. banana
  6. pomegranate
  7. clementine
  8. grape
  9. gravy
  10. cherry
  11. turkey

You all must have been hungry 😂

We need to establish a list of items to pick from. What do we use for a list? An array of course! Here is the start, you finish it (and feel free to add even more words):

string[] words = [
   "pineapple", // comma between each word
   "orange",
   "grapefruit",
   ... // continue the list
];

This can go anywhere inside your main function, or even outside. However, it must appear before you use it.

Remember, a string is an array, but is specified with double quotes instead of square brackets. This means the words array is actually an array of arrays!. For instance, if I wanted to access the 3rd character in the 4th string "apple", I would use words[3][2]. Remember, indexes start at 0. So words[3] means the 4th string, and then to get the third character, we index with [2].

Now that we have a words list, we need to pick a random word. If you remember from last class, we need to use the module std.random. We import that at the top of the file like this:

import std.random;

Now, to get a random number, you need to select an index from a minimum and maximum number. We could use the call uniform(0, words.length), and use the resulting number to index the words array, but std.random provides an easier way. We can use the function choice(words), which returns a random element from the array.:

    //string secret = "hello";
    // do this instead:
    string secret = choice(words);

At this point, your hangman game is much more enjoyable!

If you tried my hangman game that I posted, you can see I made the output a lot better (including a little picture of a hangman). There are a few things I did, and I will go over them quickly in the next class, with more advanced features of D. But I will give you some more information about functions and what they do so you might be able to try making your own game look better:

See if you can use this to make the output nicer!

Here are some things to think about: What if you guess the same letter more than once? Is there any way we can detect this? What if the user types in a character that's not a letter? In my game, I handle all these situations, and I will show you how I do it next time.

©2019-2020 Steven Schveighoffer