9.4. Lab: Collections
Notes on Assignments:
Notes on GAI: Note that the course policy is that you should not use generative AI (GAI) without authorization. GAI’s are great tools and you should learn how to use it, but they are tools and should be used to facilitate but not replace your learning. If you are suspected to have used GAI tools to generate answers to the assignment questions instead of using it as a learning tool, you may be called up to explain/reproduce your work. If you fail to demonstrate your competence, all your related assignments throughout the semester will be regraded as 0. For example, if you fail to produce good code in
whileloops in midterm exam, your lab06 while loop homework and lab will be re-evaluated.
Create a dotnet console app project (see Create a C# Project if you need to) in your
introcscsdirectory (C:\Users\*USERNAME*\workspace\introcscsfor Windows orCOMPUTER:introcscs USERNAME$for macOS) ; call it Ch09CollectionsLab.Inside the folder, issue the command
dotnet new consoleto create the project in the folder.Still inside the project directory, type
code .to start VS Code with the folder as the default folder.Prepare your code in VS Code using the file
Program.csto code unless otherwise specified.The namespace of this project is IntroCSCS.
The class name of this project is Ch09CollectionsLab.
When executing code, you will start with the Main() method in a designated class/file.
You will prepare methods in the same class or project to be called from the Main() method.
Use a Word document to prepare your assignment.
Number the questions and annotate your answers (using // in code) to show your understanding.
For coding questions, screenshot and paste 1) your code in VS Code and 2) the results of the code’s execution (command prompt and username are part of the execution).
9.4.1. Overview
9.4.1.1. Goals for this lab:
Read a text file.
Work with loops.
Work with a Dictionary and a List.
Retrieve a random entry.
This project has a program called We-Give-Answer! as in fake_help_verbose/fake_help_verbose.cs
that has some fake AI/virtual assistant capacity. The program is working but all the response texts are
hard-coded in the program and that is not ideal for maintenance. Your team want to use external text
files so that you can manage response texts with ease. For that your colleagues have prepared a file
called fake_help.cs. Your job is to complete this new program.
Your team has designed this new program to be structured a little differently from the verbose version.
A helper class file_util.cs (file_util.cs) is added to
contain the functionalities of handling files. You need to work on the file to provide such functionalities.
You will need to complete short versions of methods GetParagraphs and GetDictionary in file_util.cs.
Testing: When you complete this function, the program should behave just like the earlier verbose version with the hard-coded data: Using a dictionary value if it finds the right key, or choosing a random response if there is no key match.
This should also be an extremely short amount of coding! Think of following through the data file, and get the corresponding sequence of instructions to handle the data in the exact same sequence.
9.4.2. Steps
9.4.2.1. Download files
Download the following files by going to the github repositories and use the download raw files to download individual files and move them to the project folder:
fake_help_verbose (fake_help_verbose),
fake_help.cs (dict_lab_stub) along with the following files:
file_util.cs
help_not_defaults.txt
help_not_responses.txt, and
the UI class (
ui.csat ui) so you don’t have to write the user input code.
Note that some of the files are data files (*.txt).
Note
For now, you may keep the namespace IntroCS and change them later for organization purpose.
9.4.2.2. The FakeHelpVerbose Class
Open the working program, the downloaded take_help_verbose.cs (fake_help_verbose/fake_help_verbose.cs) and
look at how the methods Main, Response, GetParagraphs() and GetDictionary() work together
to provide the Fake Help functionality.
Note
To run the program (take_help_verbose.cs), you need to change the Main method in fake_help.cs to something
else such as main as you are allowed to have only one Main in a program and both fake_help.cs and
fake_help_verbose.cs have a Main method. You have to rename or comment out one of them to run the other.
All the strings for the responses are pre-coded for you there, but if
you were writing your own methods, it would be a pain. There is all the
repetitious code to make multiline strings and then to add to the
List and Dictionary. That’s why you will later provide simple versatile methods to
fill a List<string> or a Dictionary<string, string> so that you only need
you to write the string data itself into a text file, with the only
overhead being a few extra newlines.
For now, run the program to see how this fake AI/virtual look like:
PS C:\Users\[username]\workspace\introcscs\Ch09CollectionLab> dotnet run
Welcome to We-Give-Answers! // this is the prompt for user action
What do you have to say?
Enter 'bye' to end our session. // input "bye" to escape the while loop and exit
>
The Main method: Look back into the code, in the Main method, you see that:
public static void Main(string[] args)
{
List<string> guessList = GetParagraphs(); // create a filled string list guessList from GetParagraph
Dictionary<string, string> responses = GetDictionary(); // create a filled dictionary response from GetDictionary
string prompt = "\n> "; // create a string variable and initialize it as prompt
Console.WriteLine(@"Welcome to We-Give-Answers! // prompt user input;
What do you have to say?"); // the @ means the string is a verbatim string literal; escape sequence is ignored
Console.Write("\nEnter 'bye' to end our session."); // \n means print a new line
string fromUser; // create another string variable
do // use do-while loop to loop at least once and keep looping
{ // until the condition is met
fromUser = UI.PromptLine(prompt).ToLower().Trim(); // user UI's PromptLine to read user input and save it to fromUser
if (fromUser != "bye") // condition: if user does not enter 'bye'...
{
string answer = Response(fromUser, guessList, responses); // call Response(); throw the args to Response()
Console.WriteLine('\n' + answer); // print returned string from Response in a new line
}
} while (fromUser != "bye"); // condition: when user input "bye", terminate the while loop
Console.WriteLine(@" // Good bye with verbatim string literal
We-Give-Answers
thanks you for your patronage.
Call again if we can help you
with any other problem!");
}
Both the GetParagraphs() and GetDictionary() in this class actually does one
thing: To add texts to the List/Dictionary variables:
The GetParagraph method: The GetParagraph() method, taking no arguments, returns a string list of paragraphs:
public static List<string> GetParagraphs() // when called, return a string list
{
List<string> all = new List<string>(); // create the new "all" string list variable
all.Add(@"No other customer has ever complained // add string to the variable using "Add()"
about this before. What is your system
configuration?");
all.Add(@"That sounds odd. Could you describe // add string to the variable using "Add()"
that problem in more detail?");
// ...
all.Add("Could you elaborate on that?"); // add string to the variable using "Add()"
return all; // return the string list variable all
The GetDictionary method: The GetDictionary() method, taking no arguments,
creates and returns a dictionary of keyword:paragraph (key:value) pairs:
public static Dictionary<string, string> GetDictionary() // the method returns a Dictionary<string, string> type
{
Dictionary<string, string> d = new Dictionary<string, string>(); // create Dictionary variable d
d["crash"] = @"Well, it never crashes on our system. // add key:value pair to d
It must have something to do with your system.
Tell me more about your configuration.";
d["slow"] = @"I think this has to do with your hardware. // add key:value pair to d
// ... // keep adding...
d["linux"] = @"We take Linux support very seriously.
But there are some problems.
Most have to do with incompatible glibc versions.
Can you be a bit more precise?";
return d; // return dictionary d to caller
The Response method: Response() takes three arguments and returns:
a paragraph value from the responses dictionary (created by
GetDictionary()) if the user input matches the paragraph’s key; ora random paragraph from the string list guessList (created by
GetParagraphs()).
public static string Response(string fromUser, List<string> guessList,
Dictionary<string, string> responses)
{
char[] sep = "\t !@#$%^&*()_+{}|[]\\:\";<>?,./".ToCharArray(); // define separators
string[] words = fromUser.ToLower().Split(sep); // make fromUser lower case and split the words
foreach (string word in words) { // loop through the words
if (responses.ContainsKey(word)) { // if a word (keyword) matches a "responses" dictionary key
return responses[word]; } } // return the value (msg) by that key
return guessList[rand.Next(guessList.Count)]; // if the word is not a key in "response", return a random "guess"
}
9.4.2.3. The FakeHelp Class
help_not_defaults.txt: First, look into your lab project for the first data file: help_not_defaults.txt, and the beginning is shown below:
You can see that it includes the data for the welcome and goodbye strings, as seen in
FakeHelpVerbose (fake_help_verbose.cs), followed by all the data to go in
the list variable guessList of random answers.
One complication is that many of these strings take up several lines, in what we call a paragraph. We follow a standard convention for putting paragraphs into plain text: Put a blank line after a paragraph to mark its end. As you can see, that is how help_not_defaults.txt is set up.
Now look in your copy of the class FakeHelp (fake_help.cs), you will see that it is
very similar to class FakeHelpVerbose in fake_help_verbose.cs:
11public static void main()
12{
13 StreamReader reader = new StreamReader("help_not_defaults.txt");
14 // special data is in the first two paragraphs
15 string welcome = FileUtil.ReadParagraph(reader);
16 string goodbye = FileUtil.ReadParagraph(reader);
17 List<string> guessList = // rest of the file gives a
18 FileUtil.GetParagraphs(reader); // list of random responses
19 reader.Close();
20 reader = new StreamReader("help_not_responses.txt");
21 Dictionary<string, string> responses =
22 FileUtil.GetDictionary(reader);
23 reader.Close();
24 Console.Write(welcome);
25 string prompt = "\n> ";
26 Console.WriteLine("Enter 'bye' to end our session.");
27 string fromUser;
28 do
29 {
30 fromUser = UI.PromptLine(prompt).ToLower().Trim();
31 if (fromUser != "bye")
32 {
33 string answer = Response(fromUser, guessList, responses);
34 Console.Write("\n" + answer);
35 }
36 } while (fromUser != "bye");
37 Console.Write("\n" + goodbye);
38}
The
StreamReaderis set up to read from the right file.The the
FileUtilmethodsReadParagraph,GetParagraphs, andGetDictionaryare used to provide the text data needed.
All of the additions you need to make are in the bodies of method
definitions in the class FileUtil. Look back to Main in fake_help.cs to
see how the methods from FileUtil are actually used:
.. definitions in the class FileUtil. Look back to Main in FakeAdvise to
It creates the
ListguessListand theDictionaryresponsesusing more general functions that you need to fill in.The stubs are put in the class
FileUtilfor easy reuse.The
Maincalls these methods and chooses the files to read.The results will look the same as the original program to the user, but the second version will be easier for a programmer to read and generalize: It will be easier in other situations where you want lots of canned data in your program (like in a game you might write).
The stub should run as is (mostly saying things are not implemented).
Test out your work at every stage!
9.4.2.4. ReadParagraph
The first method to complete in
file_util.cs
is useful by itself and later for use in the
GetParagraphs and GetDictionary that you will complete. See the stub:
The first call to ReadParagraph, using the file illustrated above, should
return the following (showing the escape codes for the newlines):
"Welcome to We-Give-Answers!\nWhat do you have to say?\n"
and then the reader should be set to read the goodbye paragraph
(the next time ReadParagraph is called).
To code, you can read lines one at a time, and append them to the part of the
paragraph read so far. There is one thing to watch out for: The
ReadLine function throws away the following newline ("\n") in the input. You
need to preserve it, so be sure to explicitly add a newline, back onto
your paragraph string after each nonempty line is added. The returned
paragraph should end with a single newline.
Throw away the empty line in the input after the paragraph. Make sure you stop after reading the empty line. It is very important that you advance the reader to the right place, to be ready to read the next paragraph.
Be careful of a pitfall with files: You can only read a given chunk once:
If you read again, with the exact same syntax,
you get the next line of the file. The ReadLine method
has the side effect of advancing the reading position in the file.
Testing: This first short ReadParagraph function should actually be most of
the code that you write for the lab! The program is set up so you can immediately
run the program and test ReadParagraph: It is called to read in the welcome string
and the goodbye string for the program, so if those come correctly to the screen, you
can advance to the next two parts.
9.4.2.5. GetParagraphs
Since you have ReadParagraph at your disposal, you now only need to
insert a few remaining lines of code to complete the next method
GetParagraphs, that reads to the end of the file, and likely
processes more than one paragraph.
Look again at help_not_defaults.txt, to see how the data is set up.
This lab requires very few lines of code. Be sure to read the examples and instructions carefully (several times). A lot of ideas get packed into the few lines!
Testing: After writing GetParagraphs, the random
responses in the lab project program should work as the user enters lines in the program.
9.4.2.6. GetDictionary
The last stub to complete in file_util.cs
is GetDictionary. Its
stub also takes a StreamReader as parameter. In
Main this method is called to read from
help_not_responses.txt.
Here are the first few lines:
Here is the stub of the function to complete, reading such data: