diff --git a/026_Challenge_variabe_data/026_csharp.md b/026_Challenge_variabe_data/026_csharp.md new file mode 100644 index 0000000..ee3f82d --- /dev/null +++ b/026_Challenge_variabe_data/026_csharp.md @@ -0,0 +1,481 @@ +# Challenge project + +## Work with variable data in C# + +Demonstrate your ability to develop a console app that implements data +formatting and using arrays to deliver a multiple term search feature. + +### Learning objectives + +Apply iteration statements using data input. + +- Process data. + +- Format data output. + +- Choose the correct data types and safely converting data types. + +- Create and manipulate string arrays, and sort array data. + +- Modify and build complex strings from multiple data sources, and format data +for display. + +## Introduction + +Suppose you're one of the developers working on the Contoso Pets adoption +application to help find new homes for pets. Your starting version of the +application gathers a single search term used to search the descriptions of +dogs. A single term search is helpful, but the feedback given from the team is +the application needs more search functionality. The team wants you to extend +the search functionality to allow for multiple term searches. Additionally, the +team wants to pilot an update to the "search status" animation that shows +search progress. + +In this challenge coding project, your C# data knowledge and skills are applied +for: + +- Creating string arrays by splitting strings +- Manipulating array data, iterating through elements in an array, and sorting array data +- Modifying and building strings from multiple data sources + +In short, you'll: + +- Develop multi-term search functionality for the "dogs" search +- Update the "search status" animation, information and countdown + +By the end of this module, you complete an updated version of the Contoso Pets +application that searches all dogs available for adoption using multiple search +terms and an improved search status simulation. + +--- + +### Project specification overview + +Update the existing Contoso Pets starter application to include multiple term +search and improved "search status" animation features: + +#### Add dog attribute multi-term search + +Gather user input for the pet characteristic multiple term search + +- Users need to provide search terms separated by commas +- Store the search terms in an array and sort the terms alphabetically + +Within the animals array loop that identifies "dogs": + +- Iterate through the search terms to search each dog's description +- Search the combined description for a term match +- Output each dog's description where there's one or more terms matched + +After exiting the "search Animals" array loop that identifies dogs: + +If no dogs were a match for any of the users provided search terms, output a no +dogs matched message. + +#### Add "search status" improvements + +Update the animation + +- Adjust the searchingIcons array to resemble a spinning dial +- Adjust the animation loop so the animation shows a numeric countdown from two to zero (2.., 1.., 0..) + +#### Starter code + +The starter code project for this challenge project module includes a Program +.cs file that provides the following code features: + +The code declares variables used to collect and process pet data and menu item +selections + +The code declares the ourAnimals array + +The code uses a for loop around an if-elseif-else construct to populate the +ourAnimals array with a sample dataset + +The code displays the following main menu options for user selection: + + ```txt + 1. List all of our current pet information + 2. Display all dogs with a specified characteristic + + Enter menu item selection or type "Exit" to exit the program + ``` + +The application menu code reads the user's menu item selection and displays a +message echoing their selection + +Case 1: "List all of our current pet information" displays the sample data for +all animals (two dogs and two cats) + +Case 2: "2. Display all dogs with a specified characteristic" is the primary +area where new functionality code is added + + - Under Case 2, the starter code identifies dogs and searches for a single + user input term + - Before you search each dog, the console shows a simple "animation" that + simulates a status for searching occurring + +Your goal is to update the existing code to develop key features requested by +your team: + +- Add dog multiple attribute search +- Update search animation + +Use your development environment, and test your application at each stage of +your development process. + +#### Setup + +Download a +[zip](https://github.com/MicrosoftLearning/Challenge-project-Work-with-variable-data-in-CSharp/archive/refs/heads/main.zip) +file containing the code folders for the challenge project. + +Build and run the file entering `dotnet run` in the terminal window. + +The menu should display with two options. Enter `1` as shown in the following +terminal example: + + ```txt + Welcome to the Contoso PetFriends app. Your main menu options are: + 1. List all of our current pet information + 2. Display all dogs with a specified characteristic + + Enter your selection number (or type Exit to exit the program) + 1 + ``` + +The sample data on the current pets should display followed by the message +`Press the Enter key to continue` + +After pressing Enter, the menu should display again. Choose Option `2`, shown +in the following example: + + ```txt + Welcome to the Contoso PetFriends app. Your main menu options are: + 1. List all of our current pet information + 2. Display all dogs with a specified characteristic + + Enter your selection number (or type Exit to exit the program) + 2 + + Enter one desired dog characteristic to search for + ``` + +Enter "large" for the search term and press "Enter." + +Notice the "searching" message as shown: + +```txt +searching our dog Nickname: gus for large ... +``` + +Notice, the message runs before each search of a pet, and the periods +(`., .., ...`) at the end change in an animation. Run the search again if you +missed it. + +Once the search ends, press enter to return to the menu. Then type "exit" and +press "Enter" to close the application. + +Take a few minutes to become familiar with the Project.cs started code. + +Focus on the areas that require updates, search and the animation. + +Notice that there are some comments left in the code that indicate where to +place an update. + +You're now ready to begin the Guided project exercises. Good luck! + +--- + +### Add multiple term search support + +The Contoso Pets app helps find new homes for abandoned pets. The team wants +the search feature improved to let users enter multiple terms when searching +for dogs to adopt. + +### Search specification + +In this first challenge exercise, you need to update the single term search +feature to allow users to enter multiple search terms separated by commas. + +#### Gather multiple search terms from the user + +- Allow the user to enter multiple search terms when searching for dogs +- The user needs instructions to "enter the search terms separated by commas" +- Separate out individual search terms from the user entry string and store as +values in an array +- Sort the terms in the array in alphanumeric sort order + +#### Identify dogs with descriptions with matches for one, or more, user search term + +- As you identify a dog in the `animalsArray`, search for matches for each term +the user has entered +- For a term match, output a message with the dogs name and the term that is +matched + - example: `Our dog Jake is a match for your search for sheppard!` +- When all term searches complete for the current dog description: + - For one or more matches, output the nickname and description for the + current dog + - For one or more matches, track that there has been a match so you know not + to display an "no matches found for any available dogs" message (refer to the + next item) +- After **all** dog searches complete with no matches, display a message "No +matches found for any available dogs" + +#### Enforce the following validation rules + +- values can't be null +- values can't have zero characters +- any further restriction is up to the developer + +#### Code comments + +- Numbered code comments in the starter code offer suggestions +- The comments are in a sequential order and only the comments starting with #1, #2, and #3 apply to this exercise of the challenge + +#### Sample output + +Review the following animated image + +Notice the temporary display of "`searching...`" followed by the current term +(example: "`searching...retriever`") + +Notice the order the terms appear in search is now in alphanumeric + +Notice the messages for matches persist (example: +"`Our dog lola is a chase match!`") + +Review the sample output in the following section, "How to check your work", to further clarify how to implement features + +### How to check your work + +To validate that your code satisfies the specified requirements. + +Build and run your app. + +> Note +> You can exit the verification test before completing all of the verification +steps if see a result that does not satisfy the specification requirements. To +force an exit from the running program, in the Terminal panel, press Ctrl-C. +After exiting the running app, complete the edits that you believe will address +the issue you are working on, save your updates to the Program.cs file, and +then re-build and run your code. + +The terminal command prompt should display as the starting point for the +program + +At the command prompt, enter 2 menu: + + ```txt + Welcome to the Contoso PetFriends app. Your main menu options are: + 1. List all of our current pet information + 2. Display all dogs with a specified characteristic + + Enter your selection number (or type Exit to exit the program) + 2 + + Enter dog characteristics to search for separated by commas + ``` + +At the command prompt, enter large, cream, golden to test when more than one +search term matches the dog descriptions. Verify that the Terminal panel +updates with a message similar to the code output sample: + + ```txt + Enter dog characteristics to search for separated by commas + large, cream, golden + + Our dog Nickname: lola matches your search for cream + Our dog Nickname: lola matches your search for golden + Nickname: lola (ID #: d1) + Physical description: medium sized cream colored female golden retriever weighing about 45 pounds. housebroken. + Personality: loves to have her belly rubbed and likes to chase her tail. gives lots of kisses. + + Our dog Nickname: gus matches your search for golden + Our dog Nickname: gus matches your search for large + Nickname: gus (ID #: d2) + Physical description: large reddish-brown male golden retriever weighing about 85 pounds. housebroken. + Personality: loves to have his ears rubbed when he greets you at the door, or at any time! loves to lean-in and give doggy hugs. + + Press the Enter key to continue + ``` + +At the command prompt, press the enter key to continue to the main menu + +At the command prompt, enter 2 menu: + + ```txt + Welcome to the Contoso PetFriends app. Your main menu options are: + 1. List all of our current pet information + 2. Display all dogs with a specified characteristic + + Enter your selection number (or type Exit to exit the program) + 2 + + Enter dog characteristics to search for separated by commas + ``` + +At the command prompt, enter big, grey, stripes to test when none of the search +terms match dog descriptions. Verify that the Terminal panel updates with a +message similar to the code output samples: + + ```txt + Enter dog characteristics to search for separated by commas + big, grey, stripes + + None of our dogs are a match for: big, grey, stripes + + + Press the Enter key to continue + ``` + +If you specified further restrictions for valid entries, run the appropriate +test cases to verify your work. + +> Note +> If your code meets the requirements you should be able to complete each step +in order and see the expected results in a single test pass. If you added +additional restrictions, you may need to exit the application and then run a +separate test pass to complete your verification. + +Congratulations if you succeeded in this challenge exercise! + +--- + +## Exercise + +### Add improved search animation + +The Contoso Pets app helps find new homes for abandoned pets. Part of the +request for search feature improvement is to update the animated simulation +indicating search progress. + +#### Search animation specification + +In this second challenge exercise, you need to update the search animation to +resemble spinning and add a count down (2, 1, 0). + +#### Change the current "searching" animation icons + +Update the current animation "icons" +`string[] searchingIcons = {". ", ".. ", "..."};` + +Use new icons that simulate spinning + +You can design the "searching" animation to display "spinning" to work +differently than displayed in the animated image + +The "searching..." animation, should continue to be overwritten, after each +animation completes so it stays on the same line, and so that it doesn't +display after the animation stops. + +#### Add a countdown to the "searching" animation + +Review the previous animated image - note the countdown in the output +"`searching...retriever / 2`" +The previous number "`2`" displays as "`1`", and finally as "`0`", counting down +Update the loop that contains the "searching" animation so that the loop can +display a countdown + +##### Code comments + +- Numbered code comments in the starter code offer suggestions +- The comments are in a sequential order and only the comments starting with #4, and #5 apply to this exercise of the challenge + +#### How to check your work + +To validate that your code satisfies the specified requirements, complete the +instruction steps: + +Build and run your app. + +> Note +> You can exit the verification test before completing all of the verification +steps if see a result that does not satisfy the specification requirements. To +force an exit from the running program, in the Terminal panel, press Ctrl-C. +After exiting the running app, complete the edits that you believe will address +the issue you are working on, save your updates to the Program.cs file, and +then re-build and run your code. + +The terminal command prompt should display as the starting point for the +program + +At the command prompt, enter 2 menu: + + ```txt + Welcome to the Contoso PetFriends app. Your main menu options are: + 1. List all of our current pet information + 2. Display all dogs with a specified characteristic + + Enter your selection number (or type Exit to exit the program) + 2 + + Enter dog characteristics to search for separated by commas + ``` + +At the command prompt, enter **golden, big** and press enter to test the search +status messages with animation and countdown + +Verify that the console panel updates with temporary "searching" status +messages similar to the code output samples: + + ```txt + Enter dog characteristics to search for separated by commas + golden, big + + searching our dog Nickname: lola for big / 2 + ``` + + ```txt + searching our dog Nickname: lola for big -- 1 + ``` + + ```txt + searching our dog Nickname: lola for golden \ 1 + ``` + + ```txt + searching our dog Nickname: lola for golden * 0 + ``` + +All the user entered search terms should display with the "`searching`" spin +animation and countdown for each dog where the "searching our dog..." line in +the output overwrites the previous line to create an animation + +Refer to the previous animated image of the running program for more examples +of the "searching" status animation with countdown + +Validate after the searching has stopped, the "`searching`" animation and +countdown no longer displays + +> Note +> If your code meets the requirements you should be able to complete each step +in order and see the expected results in a single test pass. + +Congratulations if you succeeded in this exercise challenge! + +- [Challenge](./Challenge-Variable_data/Own/Program.cs) + +--- + +### Summary + +Your challenge was to update an application to support multiple term search and +to improve the "search status" information animation. + +In this module, you developed code that combines: + +- Iterate using data input. +- Process data. +- Format data output. +- Choose the correct data types and safely convert data types. +- Create and manipulate string arrays, and sort array data. +- Modify and build complex strings from multiple data sources, and format data +for display. + +You delivered functionality to your Contoso pet app team, including: + +- Gather the pet characteristics for multiple search term inputs. +- Store search input terms in a sorted array. +- Display the dogs that have a term match. +- Provide an improved search status animation with a countdown. diff --git a/026_Challenge_variabe_data/Challenge-Variable_data/Final/Final.csproj b/026_Challenge_variabe_data/Challenge-Variable_data/Final/Final.csproj new file mode 100644 index 0000000..f02677b --- /dev/null +++ b/026_Challenge_variabe_data/Challenge-Variable_data/Final/Final.csproj @@ -0,0 +1,10 @@ + + + + Exe + net7.0 + enable + enable + + + diff --git a/026_Challenge_variabe_data/Challenge-Variable_data/Final/Program.cs b/026_Challenge_variabe_data/Challenge-Variable_data/Final/Program.cs new file mode 100644 index 0000000..7964071 --- /dev/null +++ b/026_Challenge_variabe_data/Challenge-Variable_data/Final/Program.cs @@ -0,0 +1,207 @@ +// Final + +// ourAnimals array will store the following: +string animalSpecies = ""; +string animalID = ""; +string animalAge = ""; +string animalPhysicalDescription = ""; +string animalPersonalityDescription = ""; +string animalNickname = ""; +string suggestedDonation = ""; + +// variables that support data entry +int maxPets = 8; +string? readResult; +string menuSelection = ""; +decimal decimalDonation = 0.00m; + +// array used to store runtime data +string[,] ourAnimals = new string[maxPets, 7]; + +// sample data ourAnimals array entries +for (int i = 0; i < maxPets; i++) { + switch (i) { + case 0: + animalSpecies = "dog"; + animalID = "d1"; + animalAge = "2"; + animalPhysicalDescription = "medium sized cream colored female golden retriever weighing about 45 pounds. housebroken."; + animalPersonalityDescription = "loves to have her belly rubbed and likes to chase her tail. gives lots of kisses."; + animalNickname = "lola"; + suggestedDonation = "85.00"; + break; + + case 1: + animalSpecies = "dog"; + animalID = "d2"; + animalAge = "9"; + animalPhysicalDescription = "large reddish-brown male golden retriever weighing about 85 pounds. housebroken."; + animalPersonalityDescription = "loves to have his ears rubbed when he greets you at the door, or at any time! loves to lean-in and give doggy hugs."; + animalNickname = "gus"; + suggestedDonation = "49.99"; + break; + + case 2: + animalSpecies = "cat"; + animalID = "c3"; + animalAge = "1"; + animalPhysicalDescription = "small white female weighing about 8 pounds. litter box trained."; + animalPersonalityDescription = "friendly"; + animalNickname = "snow"; + suggestedDonation = "40.00"; + break; + + case 3: + animalSpecies = "cat"; + animalID = "c4"; + animalAge = ""; + animalPhysicalDescription = ""; + animalPersonalityDescription = ""; + animalNickname = "lion"; + suggestedDonation = ""; + + break; + + default: + animalSpecies = ""; + animalID = ""; + animalAge = ""; + animalPhysicalDescription = ""; + animalPersonalityDescription = ""; + animalNickname = ""; + suggestedDonation = ""; + break; + } + + ourAnimals[i, 0] = "ID #: " + animalID; + ourAnimals[i, 1] = "Species: " + animalSpecies; + ourAnimals[i, 2] = "Age: " + animalAge; + ourAnimals[i, 3] = "Nickname: " + animalNickname; + ourAnimals[i, 4] = "Physical description: " + animalPhysicalDescription; + ourAnimals[i, 5] = "Personality: " + animalPersonalityDescription; + + if (!decimal.TryParse(suggestedDonation, out decimalDonation)) { + decimalDonation = 45.00m; // if suggestedDonation NOT a number, default to 45.00 + } + ourAnimals[i, 6] = $"Suggested Donation: {decimalDonation:C2}"; +} + +// top-level menu options +do { + // NOTE: the Console.Clear method is throwing an exception in debug sessions + Console.Clear(); + + Console.WriteLine("Welcome to the Contoso PetFriends app. Your main menu options are:"); + Console.WriteLine(" 1. List all of our current pet information"); + Console.WriteLine(" 2. Display all dogs with a specified characteristic"); + Console.WriteLine(); + Console.WriteLine("Enter your selection number (or type Exit to exit the program)"); + + readResult = Console.ReadLine(); + + if (readResult != null) { + menuSelection = readResult.ToLower(); + } + + // switch-case to process the selected menu option + switch (menuSelection) { + case "1": + // list all pet info + for (int i = 0; i < maxPets; i++) { + if (ourAnimals[i, 0] != "ID #: ") { + Console.WriteLine(); + + for (int j = 0; j < 7; j++) { + Console.WriteLine(ourAnimals[i, j].ToString()); + } + } + } + + Console.WriteLine("\r\nPress the Enter key to continue"); + readResult = Console.ReadLine(); + + break; + + case "2": + // #1 Display all dogs with a multiple search characteristics + + string dogCharacteristics = ""; + + while (dogCharacteristics == "") { + // #2 have user enter multiple comma separated characteristics to search for + Console.WriteLine($"\nEnter dog characteristics to search for separated by commas"); + readResult = Console.ReadLine(); + + if (readResult != null) { + dogCharacteristics = readResult.ToLower(); + Console.WriteLine(); + } + } + + string[] dogSearches = dogCharacteristics.Split(","); + // trim leading and trailing spaces from each search term + for (int i = 0; i < dogSearches.Length; i++) { + dogSearches[i] = dogSearches[i].Trim(); + } + + Array.Sort(dogSearches); + // #4 update to "rotating" animation with countdown + string[] searchingIcons = { " |", " /", "--", " \\", " *" }; + + bool matchesAnyDog = false; + string dogDescription = ""; + + // loops through the ourAnimals array to search for matching animals + for (int i = 0; i < maxPets; i++) { + if (ourAnimals[i, 1].Contains("dog")) { + + // Search combined descriptions and report results + dogDescription = ourAnimals[i, 4] + "\n" + ourAnimals[i, 5]; + bool matchesCurrentDog = false; + + foreach (string term in dogSearches) { + // only search if there is a term to search for + if (term != null && term.Trim() != "") { + for (int j = 2; j > -1; j--) { + // #5 update "searching" message to show countdown + foreach (string icon in searchingIcons) { + Console.Write($"\rsearching our dog {ourAnimals[i, 3]} for {term.Trim()} {icon} {j.ToString()}"); + Thread.Sleep(100); + } + + Console.Write($"\r{new String(' ', Console.BufferWidth)}"); + } + + // #3a iterate submitted characteristic terms and search description for each term + if (dogDescription.Contains(" " + term.Trim() + " ")) { + // #3b update message to reflect current search term match + + Console.WriteLine($"\rOur dog {ourAnimals[i, 3]} matches your search for {term.Trim()}"); + + matchesCurrentDog = true; + matchesAnyDog = true; + } + } + } + + // #3d if the current dog is match, display the dog's info + if (matchesCurrentDog) { + Console.WriteLine($"\r{ourAnimals[i, 3]} ({ourAnimals[i, 0]})\n{dogDescription}\n"); + } + } + } + + if (!matchesAnyDog) { + Console.WriteLine("None of our dogs are a match found for: " + dogCharacteristics); + } + + Console.WriteLine("\n\rPress the Enter key to continue"); + readResult = Console.ReadLine(); + + break; + + default: + break; + } +} +while (menuSelection != "exit"); diff --git a/026_Challenge_variabe_data/Challenge-Variable_data/LICENSE b/026_Challenge_variabe_data/Challenge-Variable_data/LICENSE new file mode 100644 index 0000000..2080d95 --- /dev/null +++ b/026_Challenge_variabe_data/Challenge-Variable_data/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Microsoft Learning + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/026_Challenge_variabe_data/Challenge-Variable_data/Own/Own.csproj b/026_Challenge_variabe_data/Challenge-Variable_data/Own/Own.csproj new file mode 100644 index 0000000..2150e37 --- /dev/null +++ b/026_Challenge_variabe_data/Challenge-Variable_data/Own/Own.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/026_Challenge_variabe_data/Challenge-Variable_data/Own/Program.cs b/026_Challenge_variabe_data/Challenge-Variable_data/Own/Program.cs new file mode 100644 index 0000000..c78e856 --- /dev/null +++ b/026_Challenge_variabe_data/Challenge-Variable_data/Own/Program.cs @@ -0,0 +1,434 @@ +const int max_pets = 8; +bool exit = false; +string? selection; +const string WIP = "Under Construction - please check " + + "back next month to see progress."; +const string separator = "+-------------------------------------" + + "----------------------------------------+"; +const string main_menu = $@"{separator} +Welcome to the Contoso PetFriends app. Your main menu options are: +{separator} + + 1. List all of our current pet information. + 2. Assign values to the ourAnimals array fields. + 3. Ensure animal ages and physical descriptions are complete. + 4. Ensure animal nicknames and personality descriptions are complete. + 5. Edit an animal's age. + 6. Edit an animal's personality description. + 7. Display all cats with a specified characteristics. + 8. Display all dogs with a specified characteristics. + + Enter menu item selection or type 'Exit' to exit the program +{separator}"; +string[] description = { + "big sized female golden colored weighing 20 pounds. housebroken.", + "large dark-brown male siver back weighing 15 pounds. housebroken.", + "small white female weighing about 8 pounds. translucid.", + "medium size male. fluorescent at night.", + "medium size weighing 4 punds, orange with black lines.", +}; +string[] personality = { + "friendly", + "loves to have his ears rubbed at any time! loves to lean-in.", + "loves to have her belly rubbed. gives lots of kisses.", + "sauvage and lovelly.", + "mad but cute", + "loves to play with a rope", +}; +string[] options = { "1", "2", "3", "4", "5", "6", "7", "8", "exit" }; +string[] nickname = { "lola", "loki", "fuzz", "boby", "gogo", "besti" }; +string[] species = { "cat", "dog", "bee", "pig", "fly", "cat", "cat" }; +string[] abcd = { "a", "b", "c", "d" }; +string[] icons = { "󰔟", "󱦟", "󱦠" }; +decimal[] donations = { 85.00M, 49.99M, 40.00M, 45.00M }; +int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8 }; +string[,] our_animals = new string[max_pets, 7]; +Random rand = new Random(); + +var clear = Console.Clear; + +void print(string text, bool new_line = true) { + if (new_line) { + Console.WriteLine(text); + } else { + Console.Write(text); + } +} + +string rand_str(string[] choices) { + int indx = rand.Next(choices.Length); + return choices[indx]; +} + +int rand_int(int[] choices) { + int indx = rand.Next(choices.Length); + return choices[indx]; +} + +decimal rand_dec(decimal[] choices) { + int indx = rand.Next(choices.Length); + return choices[indx]; +} + +string get_uniq_id(string[,] animals) { + for (int i = 0; i < max_pets - 4; i++) { + bool uniq_id = false; + while (!uniq_id) { + bool check = true; + string id = $"{rand_str(abcd)}{rand_int(nums)}"; + for (int j = 0; j < max_pets - 4; j++) { + if (!string.IsNullOrEmpty(animals[j, 1]) && animals[j, 1] == id) { + uniq_id = false; + check = false; + break; + } + } + if (check) { + uniq_id = true; + return id; + } + } + } + return "?"; +} + +void populate_animals_array() { + for (int i = 0; i < max_pets - 4; i++) { + our_animals[i, 0] = rand_str(species); + our_animals[i, 1] = get_uniq_id(our_animals); + our_animals[i, 2] = rand_str(description); + our_animals[i, 3] = $"{rand_int(nums)}"; + our_animals[i, 4] = rand_str(personality); + our_animals[i, 5] = rand_str(nickname); + our_animals[i, 6] = $"{rand_dec(donations):C2}"; + } +} + +void press_enter(string msg = "\n\tPress 'Enter' to continue") { + print(msg, false); + Console.ReadLine(); +} + +void print_pets(string[,] animals) { + clear(); + int outher_length = animals.GetLength(0); + int inner_length = animals.GetLength(1); + print(separator); + for (int j = 0; j < outher_length; j++) { + string[] animal = new string[inner_length]; + for (int k = 0; k < animals.GetLength(1); k++) { + animal[k] = animals[j, k]; + } + print_pet(animal); + } + press_enter(); +} + +void print_pet(string[] pet) { + if (!string.IsNullOrEmpty(pet[1])) { + string id = pet[1]; + string name = pet[5]; + string specie = pet[0]; + int age = Int32.Parse(pet[3].ToString()); + string year_word = age > 1 ? "years" : "year"; + string desc = pet[2]; + string perso = pet[4]; + string donation = pet[6]; + print($@" ID: {id} SPECIE: {specie} + NAME: {name} AGE: {age} {year_word} + DESCRIPTION: {desc} + PERSONALITY: {perso} + SUGGESTED DONATION: {donation} +{separator}"); + } +} + +int availability(string[,] animals) { + int pet_count = 0; + for (int j = 0; j < animals.GetLength(0); j++) { + if (!string.IsNullOrEmpty(animals[j, 1])) { + pet_count++; + } + } + int slots = max_pets - pet_count; + return slots; +} + +string get_input(string text = "Please enter your text: ", + bool is_integer = false, + bool is_money = false, + string[]? opts = null) { + bool invalid = true; + while (invalid) { + print(text, false); + string? usr_in = Console.ReadLine(); + if (!string.IsNullOrEmpty(usr_in) && usr_in.Trim() != "") { + string resp = usr_in.Trim(); + if (is_integer) { + int temp_int; + if (int.TryParse(resp, out temp_int)) { + return resp; + } + } else if (is_money) { + decimal temp_dec; + if (decimal.TryParse(resp, out temp_dec)) { + resp = $"{temp_dec:C2}"; + return resp; + } + } else if (opts != null) { + resp = resp.ToLower(); + if (opts.Contains(resp)) { + return resp; + } else { + print($"Please enter a valid option (", false); + foreach (string opt in opts) { + print($" {opt} ", false); + } + print(")"); + } + } else { + return resp; + } + } + } + return "?"; +} + +void add_new_pet(string[,] animals, int slots) { + int at_indx = max_pets - slots; + string id = $"{rand_str(abcd)}{rand_int(nums)}"; + string specie = get_input("Enter pet specie: ", false, false, species); + string name = get_input("Enter the pet name (? if unknown): "); + int age = Int32.Parse(get_input("Enter pet age (-1 if unknown): ", true)); + string donation = get_input("Enter suggested donation: ", false, true); + string desc = get_input("Enter the physical description (? if unknown): "); + string perso = get_input("Enter pet personality (? if unknown): "); + animals[at_indx, 0] = specie; + animals[at_indx, 1] = id; + animals[at_indx, 2] = desc; + animals[at_indx, 3] = age.ToString(); + animals[at_indx, 4] = perso; + animals[at_indx, 5] = name; + animals[at_indx, 6] = donation; +} + +void ask_new_pet() { + clear(); + print("Assign values to the ourAnimals array fields"); + print(separator); + int slots = availability(our_animals); + print($"\nWe currently have {max_pets - slots} pets that need homes."); + print($"We can manage {slots} more."); + if (slots > 0) { + bool another = false; + do { + string resp = get_input( + "Do you want to enter info for another pet?: " + ); + bool invalid = true; + if (resp != "") { + while (invalid) { + switch (resp) { + case "y" or "yes": + add_new_pet(our_animals, slots); + resp = ""; + invalid = false; + another = true; + break; + case "n" or "no": + invalid = false; + another = false; + break; + default: + resp = get_input("Please enter [Y]es or [N]o: "); + break; + } + } + } + slots = availability(our_animals); + } while (another && slots > 0); + if (slots == 0) { + print("We have reached our limit on the number of pets that we can manage."); + } + } + press_enter(); +} + +void check_age_and_desc(string[,] animals) { + clear(); + print("\nEnsure animal ages and physical descriptions are complete"); + int pet_count = max_pets - (availability(animals)); + for (int j = 0; j < pet_count; j++) { + if (animals[j, 3] == "-1") { + print("\n" + separator); + string[] animal = { + animals[j,0], animals[j,1], animals[j,2], + animals[j,3], animals[j,4], animals[j,5] + }; + print_pet(animal); + int age = Int32.Parse( + get_input( + $"Enter an age for ID: {animals[j, 1]}" + + " (-1 if unknown): ", true + ) + ); + animals[j, 3] = age.ToString(); + } + if (animals[j, 2] == "?") { + print("\n" + separator); + string[] animal = { + animals[j,0], animals[j,1], animals[j,2], + animals[j,3], animals[j,4], animals[j,5] + }; + print_pet(animal); + string desc = get_input( + $"Enter a physical description for ID: {animals[j, 1]}" + + " (? if unknown): " + ); + animals[j, 2] = desc; + } + } + press_enter(); +} + +void check_nick_and_perso(string[,] animals) { + clear(); + print("Ensure animal nicknames and personality descriptions are complete"); + print(separator); + int pet_count = max_pets - (availability(animals)); + for (int j = 0; j < pet_count; j++) { + if (animals[j, 5] == "?") { + print("\n" + separator); + string[] animal = { + animals[j,0], animals[j,1], animals[j,2], + animals[j,3], animals[j,4], animals[j,5] + }; + print_pet(animal); + string nick = get_input( + $"Enter a nickname for ID: {animals[j, 1]}" + + "(? if unknown): " + ); + animals[j, 5] = nick; + } + if (animals[j, 4] == "?") { + print("\n" + separator); + string[] animal = { + animals[j,0], animals[j,1], animals[j,2], + animals[j,3], animals[j,4], animals[j,5] + }; + print_pet(animal); + string perso = get_input( + $"Enter a personality description for ID: {animals[j, 1]}" + + "(? if unknown): " + ); + animals[j, 4] = perso; + } + } + press_enter(); +} + +bool search(string specie, string detail, string[,] animals) { + bool found = false; + for (int j = 0; j < animals.GetLength(0); j++) { + if (!string.IsNullOrEmpty(animals[j, 1])) { + if (animals[j, 0] == specie) { + for (int i=2; i>-1; i--) { + foreach (string icon in icons){ + print( + $"\rsearching our {specie} {animals[j, 5]}" + + $" for {detail.Trim()} {icon} {i.ToString()}", + false + ); + Thread.Sleep(200); + } + print($"\r{new String(' ', Console.BufferWidth)}", false); + } + string description = " " + animals[j, 2] + + "\n " + animals[j, 4]; + if (description.Contains(detail)) { + found = true; + print($"\r{separator}"); + print($"Our {specie} {animals[j, 5]} is a match!"); + print($"{description}"); + } + } + } + } + return found; +} + +void search_specie_by_desc(string specie, string[,] animals) { + clear(); + bool found = false; + string detail = get_input( + $"Enter {specie} characteristics to search for separated by commas: " + ); + if (detail.IndexOf(',') >= 0) { + string[] details = detail.Split(','); + foreach (string characteristic in details) { + found = search(specie, characteristic.Trim(), animals); + } + } else { + found = search(specie, detail, animals); + } + if (!found) { + print($"None of our {specie}s are a match found for: {detail}"); + } + print(separator); + press_enter(); +} + +populate_animals_array(); + +while (!exit) { + clear(); + print(main_menu); + print(" >_", false); + selection = Console.ReadLine(); + if (selection != null && options.Contains(selection.ToLower())) { + selection = selection.ToLower(); + switch (selection) { + case "1": + print_pets(our_animals); + break; + case "2": + ask_new_pet(); + break; + case "3": + check_age_and_desc(our_animals); + break; + case "4": + check_nick_and_perso(our_animals); + break; + case "5": + clear(); + print(WIP); + press_enter(); + break; + case "6": + clear(); + print(WIP); + press_enter(); + break; + case "7": + search_specie_by_desc("cat", our_animals); + break; + case "8": + search_specie_by_desc("dog", our_animals); + break; + case "exit": + print("\n\tClosing application\n"); + exit = !exit; + break; + default: + print("\n\tPlease read the instructions"); + press_enter(); + break; + } + } else { + print("\n\tPlease read the instructions"); + press_enter(); + } +} + +Environment.Exit(0); diff --git a/026_Challenge_variabe_data/Challenge-Variable_data/Starter/Program.cs b/026_Challenge_variabe_data/Challenge-Variable_data/Starter/Program.cs new file mode 100644 index 0000000..237b5f4 --- /dev/null +++ b/026_Challenge_variabe_data/Challenge-Variable_data/Starter/Program.cs @@ -0,0 +1,188 @@ +// ourAnimals array will store the following: +string animalSpecies = ""; +string animalID = ""; +string animalAge = ""; +string animalPhysicalDescription = ""; +string animalPersonalityDescription = ""; +string animalNickname = ""; +string suggestedDonation = ""; + +// variables that support data entry +int maxPets = 8; +string? readResult; +string menuSelection = ""; +decimal decimalDonation = 0.00m; + +// array used to store runtime data +string[,] ourAnimals = new string[maxPets, 7]; + +// sample data ourAnimals array entries +for (int i = 0; i < maxPets; i++) { + switch (i) { + case 0: + animalSpecies = "dog"; + animalID = "d1"; + animalAge = "2"; + animalPhysicalDescription = "medium sized cream colored female golden retriever weighing about 45 pounds. housebroken."; + animalPersonalityDescription = "loves to have her belly rubbed and likes to chase her tail. gives lots of kisses."; + animalNickname = "lola"; + suggestedDonation = "85.00"; + break; + + case 1: + animalSpecies = "dog"; + animalID = "d2"; + animalAge = "9"; + animalPhysicalDescription = "large reddish-brown male golden retriever weighing about 85 pounds. housebroken."; + animalPersonalityDescription = "loves to have his ears rubbed when he greets you at the door, or at any time! loves to lean-in and give doggy hugs."; + animalNickname = "gus"; + suggestedDonation = "49.99"; + break; + + case 2: + animalSpecies = "cat"; + animalID = "c3"; + animalAge = "1"; + animalPhysicalDescription = "small white female weighing about 8 pounds. litter box trained."; + animalPersonalityDescription = "friendly"; + animalNickname = "snow"; + suggestedDonation = "40.00"; + break; + + case 3: + animalSpecies = "cat"; + animalID = "c4"; + animalAge = ""; + animalPhysicalDescription = ""; + animalPersonalityDescription = ""; + animalNickname = "lion"; + suggestedDonation = ""; + + break; + + default: + animalSpecies = ""; + animalID = ""; + animalAge = ""; + animalPhysicalDescription = ""; + animalPersonalityDescription = ""; + animalNickname = ""; + suggestedDonation = ""; + break; + + } + + ourAnimals[i, 0] = "ID #: " + animalID; + ourAnimals[i, 1] = "Species: " + animalSpecies; + ourAnimals[i, 2] = "Age: " + animalAge; + ourAnimals[i, 3] = "Nickname: " + animalNickname; + ourAnimals[i, 4] = "Physical description: " + animalPhysicalDescription; + ourAnimals[i, 5] = "Personality: " + animalPersonalityDescription; + + if (!decimal.TryParse(suggestedDonation, out decimalDonation)) { + decimalDonation = 45.00m; // if suggestedDonation NOT a number, default to 45.00 + } + ourAnimals[i, 6] = $"Suggested Donation: {decimalDonation:C2}"; +} + +// top-level menu options +do { + // NOTE: the Console.Clear method is throwing an exception in debug sessions + Console.Clear(); + + Console.WriteLine("Welcome to the Contoso PetFriends app. Your main menu options are:"); + Console.WriteLine(" 1. List all of our current pet information"); + Console.WriteLine(" 2. Display all dogs with a specified characteristic"); + Console.WriteLine(); + Console.WriteLine("Enter your selection number (or type Exit to exit the program)"); + + readResult = Console.ReadLine(); + if (readResult != null) { + menuSelection = readResult.ToLower(); + } + + // switch-case to process the selected menu option + switch (menuSelection) { + case "1": + // list all pet info + for (int i = 0; i < maxPets; i++) { + if (ourAnimals[i, 0] != "ID #: ") { + Console.WriteLine(); + for (int j = 0; j < 7; j++) { + Console.WriteLine(ourAnimals[i, j].ToString()); + } + } + } + + Console.WriteLine("\r\nPress the Enter key to continue"); + readResult = Console.ReadLine(); + + break; + + case "2": + // #1 Display all dogs with a multiple search characteristics + + string dogCharacteristic = ""; + + while (dogCharacteristic == "") { + // #2 have user enter multiple comma separated characteristics to search for + Console.WriteLine($"\r\nEnter one desired dog characteristic to search for"); + readResult = Console.ReadLine(); + if (readResult != null) { + dogCharacteristic = readResult.ToLower().Trim(); + Console.WriteLine(); + } + } + + bool noMatchesDog = true; + string dogDescription = ""; + + // #4 update to "rotating" animation with countdown + string[] searchingIcons = { ". ", ".. ", "..." }; + + // loop ourAnimals array to search for matching animals + for (int i = 0; i < maxPets; i++) { + + if (ourAnimals[i, 1].Contains("dog")) { + + // Search combined descriptions and report results + dogDescription = ourAnimals[i, 4] + "\r\n" + ourAnimals[i, 5]; + + for (int j = 5; j > -1; j--) { + // #5 update "searching" message to show countdown + foreach (string icon in searchingIcons) { + Console.Write($"\rsearching our dog {ourAnimals[i, 3]} for {dogCharacteristic} {icon}"); + Thread.Sleep(250); + } + + Console.Write($"\r{new String(' ', Console.BufferWidth)}"); + } + + // #3a iterate submitted characteristic terms and search description for each term + + if (dogDescription.Contains(dogCharacteristic)) { + // #3b update message to reflect term + // #3c set a flag "this dog" is a match + Console.WriteLine($"\nOur dog {ourAnimals[i, 3]} is a match!"); + + noMatchesDog = false; + } + + // #3d if "this dog" is match write match message + dog description + } + } + + if (noMatchesDog) { + Console.WriteLine("None of our dogs are a match found for: " + dogCharacteristic); + } + + Console.WriteLine("\n\rPress the Enter key to continue"); + readResult = Console.ReadLine(); + + break; + + default: + break; + } + +} while (menuSelection != "exit"); diff --git a/026_Challenge_variabe_data/Challenge-Variable_data/Starter/Starter.csproj b/026_Challenge_variabe_data/Challenge-Variable_data/Starter/Starter.csproj new file mode 100644 index 0000000..f02677b --- /dev/null +++ b/026_Challenge_variabe_data/Challenge-Variable_data/Starter/Starter.csproj @@ -0,0 +1,10 @@ + + + + Exe + net7.0 + enable + enable + + + diff --git a/README.md b/README.md index a265548..8dbb433 100644 --- a/README.md +++ b/README.md @@ -30,3 +30,4 @@ 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)