ms_learn_csharp/027_create_methods/027_csharp.md
2024-08-10 21:03:39 -04:00

35 KiB
Raw Blame History

Create methods in C# console applications

Learn how to create methods for C# console applications. Use parameters and return values to manipulate data across applications. Learn to use named and optional arguments to simplify code.

Introduction

The C# programming language allows you to create all sorts of robust applications. Suppose you want to write code to perform operations on unpredictable user input. You might want to add logic to handle incorrect input, convert input into a workable format, and perform the correct operation. As your applications grow larger in size, keeping track of your code can quickly become a challenge.

Methods, also called functions, are a key part of keeping code structured, efficient, and readable. A method is a modular unit of code, and a fundamental programming concept. A method is often designed to perform a specific task and contains code to execute that task. The name of a method should clearly reflect its task, which improves code readability. Learning how to use methods will help you build feature-rich applications more quickly.

In this module, you'll learn to create your own methods to perform specific tasks. You'll learn how methods can simplify and shorten code, as well as keep things organized and easy to find.

Learning Objectives

In this module, you will:

  • Create your first c sharp method
  • Identify parts of code that can be modularized
  • Use methods to organize code into specific tasks

Understand the syntax of methods

You might already be familiar with some methods, such as Console.WriteLine() or random.Next(). You might have appreciated how these methods simplify tasks and allow you to build your code more easily. In this unit, you'll learn how to create your own methods.

How methods work

The process of developing a method begins with creating a method signature. The method signature declares the method's return type, name, and input parameters. For example, consider the following method signature:

void SayHello();

The method name is SayHello. Its return type is void, meaning the method returns no data. However, methods can return a value of any data type, such as bool, int, double, and arrays as well. Method parameters, if any, should be included in the parenthesis (). Methods can accept multiple parameters of any data type. In this example, the method has no parameters.

Before you can run a method, you need to add a definition. The method definition uses brackets {} to contain the code that executes when the method is called. For example:

void SayHello() {
    Console.WriteLine("Hello World!");
}

Now the method will print Hello World! whenever it's called.

Calling a method

A method is called by using its name and including any required arguments. Consider the following:

Console.Write("Input!");

The string "Input!" is the argument provided to the Write method.

A method can be called before or after its definition. For example, the SayHello method can be defined and called using the following syntax:

SayHello();

void SayHello() {
    Console.WriteLine("Hello World!");
}

Notice that it isn't necessary to have the method defined before you call it. This flexibility allows you to organize your code as you see fit. It's common to define all methods at the end of a program. For example:

int[] a = {1,2,3,4,5};

Console.WriteLine("Contents of Array:");
PrintArray();

void PrintArray() {
    foreach (int x in a) {
        Console.Write($"{x} ");
    }
    Console.WriteLine();
}

Method execution

When you call a method, the code in the method body will be executed. This means execution control is passed from the method caller to the method. Control is returned to the caller after the method completes its execution. For example, consider the following code:

Console.WriteLine("Before calling a method");
SayHello();
Console.WriteLine("After calling a method");

void SayHello() {
    Console.WriteLine("Hello World!");
}

This code displays the following output:

Before calling a method
Hello World!
After calling a method

Once a method is defined, it can be called anytime, as many times as you need to use it. You can use methods inside of if-else statements, for-loops, switch statements, even to initialize variables, and so much more!

Best practices

When choosing a method name, it's important to keep the name concise and make it clear what task the method performs. Method names should be Pascal case and generally shouldn't start with digits. Names for parameters should describe what kind of information the parameter represents. Consider the following method signatures:

void ShowData(string a, int b, int c);
void DisplayDate(string month, int day, int year);

The second method describes what kind of data is displayed and provides descriptive names for parameters.

Now that you have the basics down, you're ready to begin writing your own methods!


Exercise

Create your first method

Typically, a method is created to perform a specific task. In this exercise, you'll create a method that generates and displays five random numbers. Let's get started!

Create a method to display random numbers

To create a method, first create a method signature and then add the method body. To create the method signature, you declare the return type, method name, and parameters. Create the method body by using brackets {} that contain the code.

Enter the following code into the Visual Studio Code editor:

void DisplayRandomNumbers();

In this case, the method just needs to generate and display information, so the return type is void. For now, you don't need to include any parameters.

To create the method body, remove the semicolon ; and update your code to the following:

void DisplayRandomNumbers() {
    Random random = new Random();
}

Here, you create a Random object that is used to generate the numbers.

To display five random integers, add a for loop to your method:

void DisplayRandomNumbers() {
    Random random = new Random();

    for (int i = 0; i < 5; i++) {
        Console.Write($"{random.Next(1, 100)} ");
    }
}

In this code, you generate a number between 1 and 99 (inclusive). You also add a space after the number is printed. Next, you'll display a new line before the method terminates.

Update your method with the following code:

void DisplayRandomNumbers() {
    Random random = new Random();
    for (int i = 0; i < 5; i++) {
        Console.Write($"{random.Next(1, 100)} ");
    }
    Console.WriteLine();
}

Now your method will add a new line after displaying the numbers.

Call your method

Enter a new blank code line above the DisplayRandomNumbers method.

Enter the following code on the new blank code line:

Console.WriteLine("Generating random numbers:");
DisplayRandomNumbers();

Compare your code with the following to ensure it's correct:

Console.WriteLine("Generating random numbers:");
DisplayRandomNumbers();

void DisplayRandomNumbers() {
    Random random = new Random();

    for (int i = 0; i < 5; i++) {
        Console.Write($"{random.Next(1, 100)} ");
    }

    Console.WriteLine();
}

Notice how using a method makes the code easy to understand. Rather than spending time trying to decipher the for loop on its own, you can quickly read the method name to learn that this code displays random numbers.

Check Your Work

In this task, you'll run your application from the Integrated Terminal and verify your code is working correctly. Let's get started.

At the Terminal command prompt, enter dotnet run

To verify that your code is working as expected, check that the output of your application is similar to the following output (taking into account the randomly generated numbers):

17 29 46 36 3 

If your code displays different results, you'll need to review your code to find your error and make updates. Run the code again to see if you've fixed the problem. Continue updating and running your code until your code produces the expected results.

Recap

Here's what you've learned about methods so far:

  • Create a method by declaring the return type, name, input parameters, and method body.
  • Method names should clearly reflect the task the method performs.
  • Use a method by calling its name and including parentheses ().

Exercise

Create reusable methods

As you develop applications, you might find yourself writing code to do the same thing over and over again. Instead of writing duplicate code, using a method to perform the same task shortens your code and helps you develop applications faster. In this exercise, you'll identify repeated code and replace it with a reusable method. Let's get started!

Identify duplicated code

In this task, you'll take a look at an application that tracks medication times across different time zones. The user enters their current time zone and their destination time zone. Their medication schedule is displayed and then adjusted for the new time zone.

In the code editor, delete any existing code from the previous exercises.

Copy and paste the following code:

using System;

int[] times = {800, 1200, 1600, 2000};
int diff = 0;

Console.WriteLine("Enter current GMT");
int currentGMT = Convert.ToInt32(Console.ReadLine());

Console.WriteLine("Current Medicine Schedule:");

/* Format and display medicine times */
foreach (int val in times) {
    string time = val.ToString();
    int len = time.Length;
    if (len >= 3) {
        time = time.Insert(len - 2, ":");
    }
    else if (len == 2) {
        time = time.Insert(0, "0:");
    } else {
        time = time.Insert(0, "0:0");
    }
    Console.Write($"{time} ");
}

Console.WriteLine();

Console.WriteLine("Enter new GMT");
int newGMT = Convert.ToInt32(Console.ReadLine());

if (Math.Abs(newGMT) > 12 || Math.Abs(currentGMT) > 12) {
    Console.WriteLine("Invalid GMT");
} else if (newGMT <= 0 && currentGMT <= 0 || newGMT >= 0 && currentGMT >= 0)  {
    diff = 100 * (Math.Abs(newGMT) - Math.Abs(currentGMT));
    /* Adjust the times by adding the difference, keeping the value within 24 hours */
    for (int i = 0; i < times.Length; i++) {
        times[i] = ((times[i] + diff)) % 2400;
    }
} else {
    diff = 100 * (Math.Abs(newGMT) + Math.Abs(currentGMT));
    /* Adjust the times by adding the difference, keeping the value within 24 hours */
    for (int i = 0; i < times.Length; i++) {
        times[i] = ((times[i] + diff)) % 2400;
    }
}

Console.WriteLine("New Medicine Schedule:");

/* Format and display medicine times */
foreach (int val in times) {
    string time = val.ToString();
    int len = time.Length;
    if (len >= 3) {
        time = time.Insert(len - 2, ":");
    } else if (len == 2) {
        time = time.Insert(0, "0:");
    } else {
        time = time.Insert(0, "0:0");
    }
    Console.Write($"{time} ");
}

Console.WriteLine();

Notice that there's several for-loops that are repeated with identical code.

There are two foreach loops that format and display the medicine times. There are another two for loops that adjust the times according to the time zone difference.

As you write code, you might find yourself repeating blocks of code to do the same task. That's a perfect opportunity to consolidate your code by using a method to perform the task instead. Let's practice!

Create methods to perform the repeated tasks

Now that you've identified repeated code, you can create a method to contain the code and remove the duplicates. Using methods has the added bonus of shortening your code and improving readability! The foreach loops format and display the time values, so you can give the method a name that clearly reflects that task. You can do the same with the for loop that adjusts the times. Let's get started!

Enter a new blank code line at the end of the previous code.

On the new blank code line, create a method signature by entering the following code:

void DisplayTimes() {

}

To define the method body, update the DisplayTimes method by copy and pasting the foreach block as follows:

void DisplayTimes() {
    /* Format and display medicine times */
    foreach (int val in times) {
        string time = val.ToString();
        int len = time.Length;
        if (len >= 3) {
            time = time.Insert(len - 2, ":");
        } else if (len == 2) {
            time = time.Insert(0, "0:");
        } else {
            time = time.Insert(0, "0:0");
        }
        Console.Write($"{time} ");
    }

    Console.WriteLine();
}

In this method, you include the call to Console.WriteLine at the end to append a new line after the times are displayed. Next, you'll create another method to adjust the times according to the time zone difference.

Enter a new blank code line at the end of the previous code.

On the new blank code line, create a method signature by entering the following code:

void AdjustTimes() {

}

Update the AdjustTimes method by copy and pasting the for loop as follows:

void AdjustTimes() {
    /* Adjust the times by adding the difference, keeping the value within 24 hours */
    for (int i = 0; i < times.Length; i++) {
        times[i] = ((times[i] + diff)) % 2400;
    }
}

Step 3: Call the methods

In this task, you'll delete the repeated blocks of code and replace them with calls to the methods you created.

Locate the first instance of the repeated foreach loop under the comment "Format and display medicine times":

Console.WriteLine("Current Medicine Schedule:");

/* Format and display medicine times */
foreach (int val in times) {
    ...
}

Console.WriteLine();

Console.WriteLine("Enter new GMT");

Replace the code you identified with a call to the DisplayTimes method. The replacement should result in the following code:

Console.WriteLine("Current Medicine Schedule:");
DisplayTimes();

Console.WriteLine("Enter new GMT");

Next, you'll replace the second instance of the repeated code.

Locate the second instance of the foreach loop under the comment "Format and display medicine times":

Console.WriteLine("New Medicine Schedule:");

/* Format and display medicine times */
foreach (int val in times) {
    ...
}

Console.WriteLine();

Replace the code you identified with a call to the DisplayTimes method. The replacement should result in the following code:

Console.WriteLine("New Medicine Schedule:");
DisplayTimes();

Notice how using a method in place of a large block of code provides more clarity and makes the code easier to understand. Let's do the same with the AdjustTimes method you created.

Locate the following code with the duplicated for-loops:

else if (newGMT <= 0 && currentGMT <= 0 || newGMT >= 0 && currentGMT >= 0) {
    diff = 100 * (Math.Abs(newGMT) - Math.Abs(currentGMT));
    /* Adjust the times by adding the difference, keeping the value within 24 hours */
    for (int i = 0; i < times.Length; i++) {
        times[i] = ((times[i] + diff)) % 2400;
    }
} else {
    diff = 100 * (Math.Abs(newGMT) + Math.Abs(currentGMT));

    /* Adjust the times by adding the difference, keeping the value within 24 hours */
    for (int i = 0; i < times.Length; i++) {
        times[i] = ((times[i] + diff)) % 2400;
    }
}

Replace the instances of repeated code under the comment "Adjust the times by adding the difference" with calls to your AdjustTimes method. The replacement should result in the following code:

else if (newGMT <= 0 && currentGMT <= 0 || newGMT >= 0 && currentGMT >= 0) {
    diff = 100 * (Math.Abs(newGMT) - Math.Abs(currentGMT));
    AdjustTimes();
} else {
    diff = 100 * (Math.Abs(newGMT) + Math.Abs(currentGMT));
    AdjustTimes();
}

Now all of the duplicated code has been replaced by your new method. Notice how much more readable and concise your code looks!

Check Your Work

In this task, you'll run your application from the Integrated Terminal and verify your code is working correctly. Let's get started.

Compare your code with the following to ensure it's correct:

int[] times = {800, 1200, 1600, 2000};
int diff = 0;

Console.WriteLine("Enter current GMT");
int currentGMT = Convert.ToInt32(Console.ReadLine());

Console.WriteLine("Current Medicine Schedule:");
DisplayTimes();

Console.WriteLine("Enter new GMT");
int newGMT = Convert.ToInt32(Console.ReadLine());

if (Math.Abs(newGMT) > 12 || Math.Abs(currentGMT) > 12) {
    Console.WriteLine("Invalid GMT");
} else if (newGMT <= 0 && currentGMT <= 0 || newGMT >= 0 && currentGMT >= 0) {
    diff = 100 * (Math.Abs(newGMT) - Math.Abs(currentGMT));
    AdjustTimes();
} else {
    diff = 100 * (Math.Abs(newGMT) + Math.Abs(currentGMT));
    AdjustTimes();
}

Console.WriteLine("New Medicine Schedule:");
DisplayTimes();

void DisplayTimes() {
    /* Format and display medicine times */
    foreach (int val in times) {
        string time = val.ToString();
        int len = time.Length;
        if (len >= 3) {
            time = time.Insert(len - 2, ":");
        } else if (len == 2) {
            time = time.Insert(0, "0:");
        } else {
            time = time.Insert(0, "0:0");
        }
        Console.Write($"{time} ");
    }
    Console.WriteLine();
}

void AdjustTimes() {
    /* Adjust the times by adding the difference, keeping the value within 24 hours */
    for (int i = 0; i < times.Length; i++) {
        times[i] = ((times[i] + diff)) % 2400;
    }
}

At the Terminal command prompt, enter dotnet run

Enter -6 and +6 for the GMT prompts.

Verify that your code produces the following output:

Enter current GMT
-6
Current Medicine Schedule:
8:00 12:00 16:00 20:00 
Enter new GMT
+6
New Medicine Schedule:
20:00 0:00 4:00 8:00

If your code displays different results, you'll need to review your code to find your error and make updates. Run the code again to see if you've fixed the problem. Continue updating and running your code until your code produces the expected results.


Exercise

Build code with methods

Methods are useful for organizing code, reusing code, and for tackling problems efficiently. You can think of a method like a black box that takes input, performs the named task, and returns output. With this assumption, you can quickly structure programs just by naming your tasks as methods, and then filling in the logic after you've identified all of the necessary tasks.

When you use plain language to describe steps in code, without strictly adhering to syntax rules, you're using "pseudo-code". Combining methods and pseudo-code is a great way to quickly power through any challenging programming task.

Use methods to structure code

Suppose you're a candidate in a coding interview. The interviewer wants you to write a program that checks whether an IPv4 address is valid or invalid. You're given the following rules:

  • A valid IPv4 address consists of four numbers separated by dots
  • Each number must not contain leading zeroes
  • Each number must range from 0 to 255

1.1.1.1 and 255.255.255.255 are examples of valid IP addresses.

The IPv4 address is provided as a string. You can assume that it only consists of digits and dots (there are no letters in the string provided).

How would you approach this task?

Note
Even if you aren't familiar with IP addresses, don't worry! You can still complete the code in this exercise by following the steps.

Break down the problem

In this task, you'll identify the steps needed to solve the problem. If you look closely at the rules, you might realize that it only takes three steps to determine whether or not an IPv4 address is valid.

Enter the following pseudo-code into the Editor:

/*
if ipAddress consists of 4 numbers
and
if each ipAddress number has no leading zeroes
and
if each ipAddress number is in range 0 - 255

then ipAddress is valid

else ipAddress is invalid
*/

Pseudo-code is a great way to begin tackling any problem. Using this comment block, you bridge the gap between the prompt rules and the program code, clarifying the major tasks your code will perform. Pseudo-code doesn't need to be functional or adhere to syntax rules, however, it should be a clear explanation of what the code will do. Now let's turn this into real code!

Enter a new blank code line, then type the following code in the Editor:

if (ValidateLength() && ValidateZeroes() && ValidateRange()) {
    Console.WriteLine($"ip is a valid IPv4 address");
} else {
    Console.WriteLine($"ip is an invalid IPv4 address");
}

In this step, you transform the if statements from your pseudo-code into callable methods and output the results. Don't worry about defining the methods yet; you can assume that each method performs the task its name describes. You'll fix the compilation errors and create the method logic soon, but focus on the big picture for now. When you begin working on a new program, focusing on the overall design helps you stay organized and develop your application faster.

Enter a new blank code line below the existing code, then type the following code in the Editor:

void ValidateLength() {}
void ValidateZeroes() {}
void ValidateRange() {}

Notice how using placeholder methods allowed you to quickly approach the problem and structure your code to develop the solution. Now that you have a structured plan in place, you can continue to solve the problem by filling in the code piece by piece.

Develop your solution

Now that you have all the placeholder methods needed to solve the problem, you can begin to focus on the details of your solution. Keep in mind that the input format of the IPv4 address will be a string consisting of digits separated by dots. Let's get stared!

At the beginning of your program, create variables to store the input and validation statuses:

string ipv4Input = "107.31.1.5";
bool validLength = false;
bool validZeroes = false;
bool validRange = false;

Update your solution code to use the validation variables as follows:

ValidateLength(); 
ValidateZeroes(); 
ValidateRange();

if (validLength && validZeroes && validRange) {
    Console.WriteLine($"ip is a valid IPv4 address");
} else {
    Console.WriteLine($"ip is an invalid IPv4 address");
}

Update the ValidateLength method as follows:

void ValidateLength() {
    string[] address = ipv4Input.Split(".");
    validLength = address.Length == 4;
};

The first rule states that the IPv4 address needs to have four numbers. So in this code, you use string.Split to separate the digits and check that there are four of them.

Update the ValidateZeroes method as follows:

void ValidateZeroes() {
    string[] address = ipv4Input.Split(".");
    foreach (string number in address) {
        if (number.Length > 1 && number.StartsWith("0")) {
            validZeroes = false;
        }
    }
    validZeroes = true;
}

Take a moment to consider how the rule translates to code.

The second rule states that the numbers in the IPv4 address must not contain leading zeroes. So the method needs to check numbers for leading zeroes while accepting 0 as a valid number. If all the numbers have valid zeroes, validZeroes should be equal to true, and false otherwise. So in this code, you check that each number with more than one digit does not begin with a zero.

If you look closely, you'll notice that validZeroes is set to true after the foreach loop completes. However, you only want to set validZeroes to true if no leading zeroes are found. You could correct this bug by setting validZeroes = true before the foreach loop runs. However, you can also correct this bug using a return statement.

Update your code to the following:

foreach (string number in address) {
    if (number.Length > 1 && number.StartsWith("0")) {
        validZeroes = false;
        return;
    }
}

The return statement terminates execution of the method and returns control to the method caller. Adding a return statement after validZeroes = false terminates the method after the first invalid zero is found. If no invalid zero is found, the method will terminate after setting validZeroes to true. Let's move on to the next method.

Update the ValidateRange method as follows:

void ValidateRange() {
    string[] address = ipv4Input.Split(".");

    foreach (string number in address) {
        int value = int.Parse(number);
        if (value < 0 || value > 255) {
            validRange = false;
            return;
        }
    }
    validRange = true;
}

The third rule states that each number in the IPv4 address must range from 0 to 255. So in this code, you check that each number is less than 255, and if not, terminate execution after setting validRange to false. Since the input string only contains digits and dots, you don't need to check for negative numbers.

However, there might be a case where no digits are present between dots. For example, "255...255". In this case, string.Split(".") would return empty entries, causing int.Parse to fail. You can prevent this by specifying StringSplitOptions.

Update your code as follows:

string[] address = ipv4Input.Split(".", StringSplitOptions.RemoveEmptyEntries);

Using StringSplitOptions.RemoveEmptyEntries omits empty entries from the address array and prevent attempts to parse empty strings.

Complete your solution

Now that you have all the methods completed to validate an IP address, it's time to revisit your initial solution. In this task, you'll add more input values and prepare to test your code.

Locate the following code you wrote earlier in the program:

string ipv4Input = "107.31.1.5";

Update the code as follows:

string[] ipv4Input = {"107.31.1.5", "255.0.0.255", "555..0.555", "255...255"};

When developing a solution, it is important to test your code with different input cases. In this code, you provide a decent range of test values. Now that you've updated your test input, you'll need to update your code to use the new values. Since the values are in an array, you'll need to update your code to test each one using a loop.

Update your code as follows:

foreach (string ip in ipv4Input) {
    ValidateLength(); 
    ValidateZeroes(); 
    ValidateRange();

    if (validLength && validZeroes && validRange) {
        Console.WriteLine($"{ip} is a valid IPv4 address");
    } else {
        Console.WriteLine($"{ip} is an invalid IPv4 address");
    }
}

Lastly, you need to fix the input data each method uses since you updated ipv4Input from a string to an array. Since each method uses string.Split, you can declare a variable to store the result of string.Split and use it in each method instead.

Add a variable to store the current IPv4 address that each method will reference:

string[] ipv4Input = {"107.31.1.5", "255.0.0.255", "555..0.555", "255...255"};
string[] address;
bool validLength = false;
bool validZeroes = false;
bool validRange = false;

Initialize address using string.Split as follows:

foreach (string ip in ipv4Input) {
    address = ip.Split(".", StringSplitOptions.RemoveEmptyEntries);

Remove references to string.Split from each of the validation methods so that they use the global address variable instead. For example:

void ValidateLength() {
    validLength = address.Length == 4;
};

Check Your Work

In this task, you'll run your application from the Integrated Terminal and verify your code is working correctly. Let's get started.

Compare your code with the following to ensure it is correct:

string[] ipv4Input = {"107.31.1.5", "255.0.0.255", "555..0.555", "255...255"};
string[] address;
bool validLength = false;
bool validZeroes = false;
bool validRange = false;

foreach (string ip in ipv4Input) {
    address = ip.Split(".", StringSplitOptions.RemoveEmptyEntries);
    ValidateLength(); 
    ValidateZeroes(); 
    ValidateRange();
    if (validLength && validZeroes && validRange) {
        Console.WriteLine($"{ip} is a valid IPv4 address");
    } else {
        Console.WriteLine($"{ip} is an invalid IPv4 address");
    }
}

void ValidateLength() {
    validLength = address.Length == 4;
};

void ValidateZeroes() {
    foreach (string number in address) {
        if (number.Length > 1 && number.StartsWith("0")) {
            validZeroes = false;
            return;
        }
    }
    validZeroes = true;
}

void ValidateRange() {
    foreach (string number in address) {
        int value = int.Parse(number);
        if (value < 0 || value > 255) {
            validRange = false;
            return;
        }
    }
    validRange = true;
}

At the Terminal command prompt, enter dotnet run

Verify that your code produces the following output:

107.31.1.5 is a valid IPv4 address
255.0.0.255 is a valid IPv4 address
555..0.555 is an invalid IPv4 address
255...255 is an invalid IPv4 address

If your code displays different results, you'll need to review your code to find your error and make updates. Run the code again to see if you've fixed the problem. Continue updating and running your code until your code produces the expected results.

Recap

Here's what you've learned about using methods so far:

  • Methods can be used to quickly structure applications
  • The return keyword can be used to terminate method execution
  • Each step of a problem can often be translated into its own method
  • Use methods to solve small problems to build up your solution

Exercise - Complete the challenge to create a reusable method

Code challenges reinforce what you've learned, and help you gain some confidence before continuing on.

The focus of this challenge is to modify code so that it is reusable and can be executed at any time.

Tell a fortune

You're helping to develop a massive multiplayer role-playing game. Each player has a luck stat that can affect their odds of finding rare treasure. Each day, a player can speak to an in-game fortune teller that reveals whether their luck stat is high, low, or neutral.

The game currently has code to generate a player's fortune, but it isn't reusable. Your task is to create a tellFortune method that can be called at any time, and replace the existing logic with a call to your method.

In this challenge, you're given some starting code. You must decide how to create and call the tellFortune method.

Code challenge: create a reusable method

In the code that you start with, there's a generic text array, followed by goo d, bad, and neutral text arrays. Depending on the value of luck, one of the arrays is selected and displayed alongside the generic text.

Your challenge is to create a reusable method that prints a player's fortune at any time. The method should contain the logic that is already present in the code provided.

Copy and paste the following code into the Editor:

Random random = new Random();
int luck = random.Next(100);

string[] text = {
    "You have much to",
    "Today is a day to",
    "Whatever work you do",
    "This is an ideal time to"
};
string[] good = {
    "look forward to.",
    "try new things!",
    "is likely to succeed.",
    "accomplish your dreams!"
};
string[] bad = {
    "fear.",
    "avoid major decisions.",
    "may have unexpected outcomes.",
    "re-evaluate your life."
};
string[] neutral = {
    "appreciate.",
    "enjoy time with friends.",
    "should align with your values.",
    "get in tune with nature."
};

Console.WriteLine("A fortune teller whispers the following words:");
string[] fortune = (luck > 75 ? good : (luck < 25 ? bad : neutral));
for (int i = 0; i < 4; i++) {
    Console.Write($"{text[i]} {fortune[i]} ");
}

Update the code to use a method to display the fortune.

Use what you've learned about creating and calling methods to complete the update.

Test your code by changing the value of luck and calling the method again.

Verify that your code produces one of the following messages:

A fortune teller whispers the following words:
You have much to look forward to. Today is a day to try new things! Whatever work you do is likely to succeed. This is an ideal time to accomplish your dreams!
A fortune teller whispers the following words:
You have much to appreciate. Today is a day to enjoy time with friends. Whatever work you do should align with your values. This is an ideal time to get in tune with nature.
A fortune teller whispers the following words:
You have much to fear. Today is a day to avoid major decisions. Whatever work you do may have unexpected outcomes. This is an ideal time to re-evaluate your life.

Whether you get stuck and need to peek at the solution or you finish successfully, continue on to view a solution to this challenge.


Review the solution to create a reusable method

The following code is one possible solution for the challenge from the previous unit.

Random random = new Random();
int luck = random.Next(100);

string[] text = {
    "You have much to",
    "Today is a day to",
    "Whatever work you do",
    "This is an ideal time to"
};
string[] good = {
    "look forward to.",
    "try new things!",
    "is likely to succeed.",
    "accomplish your dreams!"
};
string[] bad = {
    "fear.",
    "avoid major decisions.",
    "may have unexpected outcomes.",
    "re-evaluate your life."
};
string[] neutral = {
    "appreciate.",
    "enjoy time with friends.",
    "should align with your values.",
    "get in tune with nature."
};

tell_fortune();

void tell_fortune() {
    Console.WriteLine("A fortune teller whispers the following words:");
    string[] fortune = (luck > 75 ? good : (luck < 25 ? bad : neutral));
    for (int i = 0; i < 4; i++) {
        Console.Write($"{text[i]} {fortune[i]} ");
    }
}

This code is just "one possible solution" because you might have added line feeds in different spots or you might have formatted the code differently.

Regardless of minor code differences, when you run the code, you should see one of the following output messages:

A fortune teller whispers the following words:
You have much to look forward to. Today is a day to try new things! Whatever work you do is likely to succeed. This is an ideal time to accomplish your dreams! 
A fortune teller whispers the following words:
You have much to appreciate. Today is a day to enjoy time with friends. Whatever work you do should align with your values. This is an ideal time to get in tune with nature. 
A fortune teller whispers the following words:
You have much to fear. Today is a day to avoid major decisions. Whatever work you do may have unexpected outcomes. This is an ideal time to re-evaluate your life.

The output should be dependent on the value of the luck variable.

If you completed the challenge, congratulations! Continue on to the knowledge check in the next unit.

Important
If you had trouble completing this challenge, consider reviewing the previous units before you continue on. All new ideas we discuss in other modules will depend on your understanding of the ideas that were presented in this module.


Summary

Your goal was to learn how to create your own methods to perform specific task s. You learned to move reusable code into methods to minimize repeating code. You also learned to use pseudo-code and placeholder methods to tackle a complex problem. By creating small methods with specific responsibilities, you learned to quickly build solutions for problems using efficient, readable code.