From 9aa8bc1e4aab7ddb8c6b41eefad0742d7ff8f121 Mon Sep 17 00:00:00 2001 From: ipvg Date: Thu, 8 Aug 2024 00:20:43 -0400 Subject: [PATCH] avnc 027 --- .../026_csharp.md | 0 .../Final/Final.csproj | 0 .../Challenge-Variable_data/Final/Program.cs | 0 .../Challenge-Variable_data/LICENSE | 0 .../Challenge-Variable_data/Own/Own.csproj | 0 .../Challenge-Variable_data/Own/Program.cs | 0 .../Starter/Program.cs | 0 .../Starter/Starter.csproj | 0 027_create_methods/027_csharp.md | 1187 +++++++++++++++++ README.md | 3 +- 10 files changed, 1189 insertions(+), 1 deletion(-) rename {026_Challenge_variabe_data => 026_Challenge_variable_data}/026_csharp.md (100%) rename {026_Challenge_variabe_data => 026_Challenge_variable_data}/Challenge-Variable_data/Final/Final.csproj (100%) rename {026_Challenge_variabe_data => 026_Challenge_variable_data}/Challenge-Variable_data/Final/Program.cs (100%) rename {026_Challenge_variabe_data => 026_Challenge_variable_data}/Challenge-Variable_data/LICENSE (100%) rename {026_Challenge_variabe_data => 026_Challenge_variable_data}/Challenge-Variable_data/Own/Own.csproj (100%) rename {026_Challenge_variabe_data => 026_Challenge_variable_data}/Challenge-Variable_data/Own/Program.cs (100%) rename {026_Challenge_variabe_data => 026_Challenge_variable_data}/Challenge-Variable_data/Starter/Program.cs (100%) rename {026_Challenge_variabe_data => 026_Challenge_variable_data}/Challenge-Variable_data/Starter/Starter.csproj (100%) create mode 100644 027_create_methods/027_csharp.md diff --git a/026_Challenge_variabe_data/026_csharp.md b/026_Challenge_variable_data/026_csharp.md similarity index 100% rename from 026_Challenge_variabe_data/026_csharp.md rename to 026_Challenge_variable_data/026_csharp.md diff --git a/026_Challenge_variabe_data/Challenge-Variable_data/Final/Final.csproj b/026_Challenge_variable_data/Challenge-Variable_data/Final/Final.csproj similarity index 100% rename from 026_Challenge_variabe_data/Challenge-Variable_data/Final/Final.csproj rename to 026_Challenge_variable_data/Challenge-Variable_data/Final/Final.csproj diff --git a/026_Challenge_variabe_data/Challenge-Variable_data/Final/Program.cs b/026_Challenge_variable_data/Challenge-Variable_data/Final/Program.cs similarity index 100% rename from 026_Challenge_variabe_data/Challenge-Variable_data/Final/Program.cs rename to 026_Challenge_variable_data/Challenge-Variable_data/Final/Program.cs diff --git a/026_Challenge_variabe_data/Challenge-Variable_data/LICENSE b/026_Challenge_variable_data/Challenge-Variable_data/LICENSE similarity index 100% rename from 026_Challenge_variabe_data/Challenge-Variable_data/LICENSE rename to 026_Challenge_variable_data/Challenge-Variable_data/LICENSE diff --git a/026_Challenge_variabe_data/Challenge-Variable_data/Own/Own.csproj b/026_Challenge_variable_data/Challenge-Variable_data/Own/Own.csproj similarity index 100% rename from 026_Challenge_variabe_data/Challenge-Variable_data/Own/Own.csproj rename to 026_Challenge_variable_data/Challenge-Variable_data/Own/Own.csproj diff --git a/026_Challenge_variabe_data/Challenge-Variable_data/Own/Program.cs b/026_Challenge_variable_data/Challenge-Variable_data/Own/Program.cs similarity index 100% rename from 026_Challenge_variabe_data/Challenge-Variable_data/Own/Program.cs rename to 026_Challenge_variable_data/Challenge-Variable_data/Own/Program.cs diff --git a/026_Challenge_variabe_data/Challenge-Variable_data/Starter/Program.cs b/026_Challenge_variable_data/Challenge-Variable_data/Starter/Program.cs similarity index 100% rename from 026_Challenge_variabe_data/Challenge-Variable_data/Starter/Program.cs rename to 026_Challenge_variable_data/Challenge-Variable_data/Starter/Program.cs diff --git a/026_Challenge_variabe_data/Challenge-Variable_data/Starter/Starter.csproj b/026_Challenge_variable_data/Challenge-Variable_data/Starter/Starter.csproj similarity index 100% rename from 026_Challenge_variabe_data/Challenge-Variable_data/Starter/Starter.csproj rename to 026_Challenge_variable_data/Challenge-Variable_data/Starter/Starter.csproj diff --git a/027_create_methods/027_csharp.md b/027_create_methods/027_csharp.md new file mode 100644 index 0000000..c08bffc --- /dev/null +++ b/027_create_methods/027_csharp.md @@ -0,0 +1,1187 @@ +# 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: + +```cs +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: + +```cs +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: + +```cs +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: + +```cs +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: + +```cs +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: + +```cs +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: + +```txt +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: + +```cs +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: + +```cs +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: + +```cs +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: + +```cs +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: + +```cs +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: + +```cs +Console.WriteLine("Generating random numbers:"); +DisplayRandomNumbers(); +``` + +Compare your code with the following to ensure it's correct: + +```cs +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): + +```cs +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: + +```cs +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: + +```cs +void DisplayTimes() { + +} +``` + +To define the method body, update the DisplayTimes method by copy and pasting +the foreach block as follows: + +```cs +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: + +```cs +void AdjustTimes() { + +} +``` + +Update the `AdjustTimes` method by copy and pasting the `for` loop as follows: + +```cs +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": + +```cs +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: + +```cs +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": + +```cs +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: + +```cs +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: + +```cs +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: + +```cs +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: + +```cs +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: + +```txt +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: + +```cs +/* +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: + +```cs +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: + +```cs +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: + +```cs +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: + +```cs +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: + +```cs +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: + +```cs +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: + +```cs +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: + +```cs +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: + +```cs +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: + +```cs +string ipv4Input = "107.31.1.5"; +``` + +Update the code as follows: + +```cs +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: + +```cs +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: + +```cs +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: + +```cs +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: + +```cs +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: + +```cs +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: + +```txt +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: + +```cs +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: + +```txt +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! +``` + +```txt +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. +``` + +```txt +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. + +```cs +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." +}; + +TellFortune(); + +void TellFortune() { + 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: + +```txt +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! +``` + +```txt +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. +``` + +```txt +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. diff --git a/README.md b/README.md index 8dbb433..6761ca7 100644 --- a/README.md +++ b/README.md @@ -30,4 +30,5 @@ Following 23. [Format alphanumeric data](./023_alphanumeric_data_format/023_csharp.md) 24. [String data type methods](./024_String_data_type_methods/024_csharp.md) 25. [Work with variable data](./025_Work_with_variable_data/025_csharp.md) -26. [Challenge - variable data](./026_Challenge_variabe_data/026_csharp.md) +26. [Challenge - variable data](./026_Challenge_variable_data/026_csharp.md) +27. [Create methods](./027_create_methods/027_csharp.md)