Contents

Kata 8

Setup instructions

  • Download the starting folder for this Kata.
  • Open a Command Prompt window and navigate to the starting folder using cd.
  • Open the starting folder for this Kata in VSCode.

Overview

In this Kata we’ll continue to build on the quiz game by using Object Oriented Programming techniques.

Kata instructions

Inspect the program as it stands. You’ll notice that Program.cs is a lot shorter. It just consists of Main, which looks like this:

QuizGame quizGame = new QuizGame();
quizGame.Start();

I’ve moved the code into a new class, which is found in QuizGame.cs. I new up an instance of the QuizGame class, then call Start to start the quiz.

Why the change?

Moving the code from Program to QuizGame has several benefits:

  • Program.cs is the ‘entry point’ for the application. Therefore it should only be responsible for doing the bare minimum in order to get the program running
  • The responsibility for the ‘quiz’ part of the application is now in it’s own class. This splits up the program in a more logical way, and makes it clearer what the program is doing
  • We aren’t using the static keyword all over the place. Why static is bad in this context is beyond the scope of this Kata - but trust me that it’s important not to use static all over the place!

In future, all C# programs you write should contain the majority of their code in classes that are called from Main in Program.cs. The bulk of your code should not be in Program.cs.

Our first real class

Now we can start to create classes for different parts of the application.

Let’s create a class that represents a question. Create a new file called Question.cs inside the App. Inside Question.cs write the following:

using System;

class Question {
    public string Text;
    public string CorrectAnswer;

    public Question(string text, string correctAnswer) {
        CorrectAnswer = correctAnswer;
        Text = text;
    }
}

First, notice the line using System; at the top of the file. This is known as an ‘import’. Imports allow us to access instructions from outside of our program - in this case System.

The System import is something we installed with the .NET Core SDK. System contains fundamental stuff that actually allows the C# code we write to function. How it works exactly is beyond the scope of this Kata - but it’s very important you don’t miss it.

Question contains two fields - Text and CorrectAnswer. It also has a constructor that assigns values to those fields. It has no methods - only data.

Using our class

Let’s alter the string arrays inside DoQuizQuestions to use Question objects instead. Inside QuizGame.cs, inside the DoQuizQuestions method, replace the code that creates the questions and answers arrays with a Question array instead. Write:

Question[] questions = new Question[2];
questions[0] = new Question("In what year did the Titanic sink?", "1912");
questions[1] = new Question("In what year did the Titanic II sink?", "1913");

Next, amend AskQuestion to ask for a Question object instead of two strings as it’s arguments.

The signature of AskQuestion should look like this:

private bool AskQuestion(Question question) 

You now need to access the fields of the question object. Inside AskQuestion, Update usages of question and correctAnswer to question.Text and question.CorrectAnswer as appropriate.

Next, pass the Question object to AskQuestion in the for loop:

bool questionResult = AskQuestion(questions[i]);

Introducing QuestionAsker

Let’s create a new class responsible for asking the questions, and recording if the user’s answer was right or wrong.

Inside App, create a new file, QuestionAsker.cs. In it, write:

using System;

class QuestionAsker {
    private Question[] Questions;

    public QuestionAsker(Question[] questions) {
        Questions = questions;
    }

We want this class to be responsible for asking all the questions in the game.

Create a public method inside QuestionAsker called AskQuestions. This method will use a for loop to ask all the questions inside the Questions field:

public bool AskQuestions() {
    for (int i = 0; i < Questions.Length; i++) {
        // Empty for now...
    }
}

We’re using a for loop to iterate through Questions. However, it doesn’t do anything just yet.

Ask me anything

Next we’re going to copy some of the code responsible for asking a single question from QuizGame.cs into our new class.

Create a private method inside QuestionAsker, called AskQuestion - singular - that looks like this:

private bool AskQuestion(Question question) {
    Console.WriteLine(question.Text);
    string answer = Console.ReadLine();

    if(answer == question.CorrectAnswer) {
        Console.WriteLine("Correct!");
        return true;
    }
    else {
        Console.WriteLine("Incorrect!");
        return false;
    }
}

AskQuestions can then call AskQuestion multiple times inside the for loop:

public bool AskQuestions() {
    for (int i = 0; i < Questions.Length; i++) {
        AskQuestion(Questions[i]);
    }
}

We’re almost there with this method. The next thing to fix is this code doesn’t actually return any information to the caller. We want AskQuestions to return true if the user has won, or false, if the user has lost.

To achieve this, we can do the following:

for (int i = 0; i < Questions.Length; i++) {
    bool result = AskQuestion(Questions[i]);

    if (result == false) {
        return false;
    }
}

return true;

This will return false if the user gets a single question wrong. However if they succeed, then the final return true statement will be executed.

Using QuestionAsker

Now use QuestionAsker inside QuizGame.cs. DoQuizQuestions should look like this:

private void DoQuizQuestions() {
    Question[] questions = new Question[2];
    questions[0] = new Question("In what year did the Titanic sink?", "1912");
    questions[1] = new Question("In what year did the Titanic II sink?", "1913");
    QuestionAsker questionAsker = new QuestionAsker(questions);
    
    bool hasUserWon = questionAsker.AskQuestions();

    if (hasUserWon) {
        Console.WriteLine("You won!");
    }
    else {
        Console.WriteLine("You lost!");
    }
}

In the Command Prompt, use dotnet run to test it out

Try on your own…

Q1

Create a class that is responsible for:

  • Reading the user’s age from the Standard Input
  • Validating the user’s age

This will involve moving some of the code inside QuizGame - the methods GetUsersAgeInYears and GetIsAgeValid.

  • Your class should only need one public method, ValidateUserAge. This should return a bool.
  • Your class doesn’t need any fields.
Copyright Mikiel Agutu 2019