Using a letter as a valid user input (console project) - c#

I'm writing an app where the console asks the user a question that has five possible answers (these being a)b)c)d)e) answers). I'm trying to find a way to make the console recognise the letter that the user is inputing and then tell the user whether the answer is correct or incorrect. Here's what I have so far, although it doesn't seem to work. Any help would be appreciated.
Console.ReadLine ();
Console.WriteLine ("Q9: Of the following, which is greater than one half?");
Console.WriteLine ("A: 2/5");
Console.WriteLine ("B: 4/7");
Console.WriteLine ("C: 4/9");
Console.WriteLine ("D: 5/11");
Console.WriteLine ("E: 6/13");
string ans9;
Console.ReadLine ();
if (ans9 == b) {
Console.WriteLine ("Correct");
} else if (ans9 != b) {
Console.WriteLine ("Incorrect");

The Console reads the line as a string so you need to check it with:
if (ans9 == "b")
But you might want to also thing about casing. What happens if the user enters B?
if (ans9.ToLower() == "b")
You're also not assigning the value of ReadLine to ans9:
string ans9 = Console.ReadLine();
Another edit: instead of checking if ans9 is equal to "b" and then checking that its not equal to "b" you can just use an else:
if (ans9 == "b") {
Console.WriteLine("Correct");
}
else {
Console.WriteLine("Incorrect");
}

Related

C# Itinerary application - repeated inquiry before proceeding

I've been trying to refactor a C# console application that asks where a user would like to travel, records the location, repeats the question, and then either asks for another location or prints the locations the user has specified (ending the program).
Given the commented instructions in the code, I seem to have everything in place. However, in the ContinuePlanning() method it repeats a second time regardless of user response before continuing in the program and I'm having trouble figuring out why.
From what I can tell, the logic makes sense but I know I'm missing a simple step somewhere in the code. Can anyone lend some insight as to why this is occurring?
Program.cs
using System;
using System.Collections.Generic;
// Synopsis: Everyone loves a great vacation! This application helps you keep track of all the wonderful places on your bucket list.
namespace TravelPlanner
{
class Program
{
static void Main(string[] args)
{
// Display header
Console.WriteLine("");
Console.WriteLine("========================================");
Console.WriteLine(" TRAVEL PLANNER ");
Console.WriteLine("========================================");
Console.WriteLine("");
Console.WriteLine("Helping you keep track of the places you will travel. \r\n");
/*
3. PLAN ITINERARY
-------------------------
[ After completing steps #1 and #2, lets take the optimization even further...
Reviewing what you've accomplished, you will notice that each step now contains a single line
of code. We've compartmentalized each action into a method, excellent refactoring!
The while loop below contains these two actions. Looping over those actions is how we plan the
itinerary. So lets migrate the loop and the nested actions into the middle of the Plan() method.
The only thing left now is the creation of the list. Add one line that sets the value of
"locations" to the calling of that method. Planning the itinerary has now be accomplished with
one line within Main()!
The Main() method has become an outline of the application... after displaying the header, we Plan(),
then display what we've planned, and finally display a footer.
Uh, oh... don't forget the syntax problem!
] */
// Create List
List<string> locations = new List<string>();
// Repeat until all locations are added
bool planning = true;
while (planning)
{
/*
1. GET LOCATION
-------------------------
[ Migrate the following, except for the last line, into the Itinerary class' (Itinerary.cs)
GetLocation() method. Then change the last line so "location," within locations.Add()
calls that GetLocation() method. Refer to the lesson on static classes/methods to see
how you can call methods from other classes.
Also, make sure to fix the validation's logic errors!
] */
locations.Add(Itinerary.GetLocation());
/*
2. CONTINUE PLANNING
-------------------------
[ Migrate all of the following into the ContinuePlanning() method. Replace this with a
single line that sets the value of the "planning" variable to the returned value.
This validation also contains a logic error!
] */
planning = Itinerary.ContinuePlanning(planning);
}
/*
4. DISPLAY ITINERARY
-------------------------
[ The Itinerary class has allowed us to organize the code, containing all the methods (processes)
related to the planning of the itinerary: Plan(), GetLocation(), and ContinuePlanning().
Since the following code is used to display the itinerary, it should be there too.
Migrate the following into the Display() method. Then replace with a call to that method.
Of course you'll need an argument for the "locations" list to display.
Carefully read the output to spot a syntax error... we want to practice string interpolation!
] */
Itinerary.Display(locations);
// -------------------------
// Display footer
Console.WriteLine("");
Console.WriteLine("========================================");
Console.WriteLine("Safe travels on your future trips!");
Console.WriteLine("");
Console.ReadKey();
}
// End class
}
}
Itinerary.cs
using System;
using System.Collections.Generic;
// Synopsis: Collection of methods used in the planning and displaying of travel itinerary locations.
namespace TravelPlanner
{
public class Itinerary
{
// Plan itinerary
public static List<string> Plan()
{
// Create list for locations
List<string> locations = new List<string>();
return locations;
}
// Request location from user
public static string GetLocation()
{
// Initial request
Console.WriteLine("");
Console.WriteLine("--------------------");
Console.Write("Where would you like to travel? ");
string location = Console.ReadLine();
// Validate user input
while (String.IsNullOrWhiteSpace(location))
{
// Reminder not to leave blank
Console.WriteLine("Please do not leave this blank! \r\n");
// Ask again where they would like to go
Console.Write("Where would you like to travel? ");
// String for user input
string newlocation = Console.ReadLine();
}
return location;
}
// Question - another location?
public static bool ContinuePlanning(bool planning)
{
// Another location?
Console.Write("Another location? (yes/no) ");
string response = Console.ReadLine();
// Validate user input
if (response.ToLower() != "yes" || response.ToLower() != "no")
{
// Error message
Console.WriteLine("Please only enter yes or no.");
// Re-ask question
Console.Write("Another location? (yes/no) ");
response = Console.ReadLine();
}
// Continue planning?
if (response.ToLower() == "no")
{
planning = false;
}
return planning;
}
// Display itinerary locations
public static void Display(List<string> locations)
{
//Output the number of locations the user will visit
Console.WriteLine("");
Console.WriteLine("--------------------");
Console.WriteLine($" You will take {locations.Count} trip(s).");
//Output each location the user will visit
for (int i = 0; i < locations.Count; i++)
{
Console.WriteLine($" You will visit {locations[i]}.");
}
}
// End class
}
}
Thanks in advance!
"From what I can tell, the logic makes sense"
That's probably because you're reading it as someone might say it in english, but not as a logical code statement.
In English we would say, "If they didn't answer with "yes" or "no", then ask them again."
In code we phrase it differently: "If the answer wasn't "yes" and the answer wasn't "no", then ask them again"
Here's why:
The conditional logical OR operator (||) will return true if either operand is true (and evaluation will stop at the first true result):
false || false == false
false || true == true
true || false == true
true || true == true
This differs from the conditional logical AND operator (&&) which will return true only if both operands are true.
false && false == false
false && true == false
true && false == false
true && true == true
Now let's take a look at your if condition in ContinuePlanning:
if (response.ToLower() != "yes" || response.ToLower() != "no")
Now, if someone enters "yes", the first part is false but the second part is true, so the condition will evaluate to true. Similarly, if they enter "no" (or any other input), the first part is true, so the condition will evaluate to true
Instead, we want to test that both the first part AND the second part are true, so we should use the && operator:
if (response.ToLower() != "yes" && response.ToLower() != "no")
Now if they enter "yes" or "no", only of those operands will be true, so the condition will evaluate to false. If they enter any other input, then both the conditions are true, which is what we're looking for.
Another problem is that this method takes in a bool argument, modifies it to false if the user enters "no", and then returns it. The problem with this is that if the variable starts out to be false, then we return false no matter what the user enters. Also, this method doesn't need any arguments from the caller. We should just declare the variable locally instead.
We also only check once if they enter "yes" or "no", but we should do it in a loop just in case they're really clumsy typists. :)
// Question - another location?
public static bool ContinuePlanning()
{
// Start out assuming we will contiune planning
bool continuePlanning = true;
// Another location?
Console.Write("Another location? (yes/no) ");
// Get the user reponse and make it lower case
string response = Console.ReadLine().ToLower();
// Validate user input
while (response != "yes" && response != "no")
{
// Error message
Console.WriteLine("Please only enter yes or no.");
// Re-ask question
Console.Write("Another location? (yes/no) ");
response = Console.ReadLine();
}
// If the user doesn't want to continue, set our variable
if (response == "no") continuePlanning = false;
return continuePlanning;
}

How to get ! operator to work inside while loop with multiple conditions

Im trying to do a check using a while loop I want the loop to only ask the user to re-enter their value if one of three conditions are triggered. That is if the response is blank, nor a "Y" or "N". I did this by using the ! operator. I've noticed that even if the response is the correct choice the while loop still asks to re-enter a value. I also noticed that when I remove the ! operator from in front of the second condition and the user enters the right response the code after the loop block works but when i add the ! operator back to the condition the loop works even if the response is correct.
PromptMessage("If you are using a different download path for your mods enter (Y)es. Or if you want to exit out the" +
" program enter (N)o!", ConsoleColor.Green);
string CustomPath = Console.ReadLine();
CustomPath.ToUpper();
Console.WriteLine(CustomPath);
while (!CustomPath.Contains("Y") || !CustomPath.Contains("N") || String.IsNullOrEmpty(CustomPath))
{
AlertMessage("Please enter either Y to continue or N to exit");
CustomPath = Console.ReadLine();
CustomPath.ToUpper();
}
You have a couple things wrong here. First, Strings are immutable in C#, so doing this:
string foo = "some string";
foo.ToUpper();
Means that foo is still equal to "some string" after running it. You need to assign the value to a variable (it can even be the same variable). Like this:
string foo = "some string";
foo = foo.ToUpper();
//foo = "SOME STRING"
The next problem is your loop and logic. I think a much easier way to do this is using a do/while loop and checking the "validity" of the input in the while condition. The do/while loop means you will always "do" something once before checking the while condition. You always want to ask for input one time so it makes more sense to use this loop:
public static void Main()
{
//defined in outer scope
string customPath = string.Empty;
do
{
Console.WriteLine("If you are using a different download path for your mods enter (Y)es. Or if you want to exit out the program enter (N)o!");
//Calling ToUpper() before assigning the value to customPath
customPath = Console.ReadLine().ToUpper();
}
while (customPath != "N" && customPath != "Y");
}
I made a fiddle here
I think you may have your logic reversed. Do you mean to have the conditions for the while as follows?
while (!CustomPath.Contains("Y") && !CustomPath.Contains("N") && !String.IsNullOrEmpty(CustomPath))
This would be logically equivalent to the following statement (but this one is much less readable IMO)
while (!(CustomPath.Contains("Y") || CustomPath.Contains("N") || String.IsNullOrEmpty(CustomPath))
This way the loop will continue while the entered path does not have contain "Y", "N", or an empty path.
Also note that as #maccettura pointed out you will want to change to using CustomPath = CustomPath.ToUpper();
Change into this
while ((!CustomPath.Contains("Y") && !CustomPath.Contains("N")) || String.IsNullOrEmpty(CustomPath))
I realize that your code will always return true.
For example, you input 'Y'
!CustomPath.Contains("Y") => false
!CustomPath.Contains("N") => true
Since you use ||, it will always return true.

Checking what type of character the unicode character is

I am running through CodeEasy.net's c# program and I have stumbled across a problem I am struggling with. I don't understand why this does not pass.
Write a program that reads from the console one char using
Console.Read() and Convert.ToChar(...) methods. After this, the
program should output "Digit" "Letter" or "Not a digit and not a
letter" to the screen, depending on what the character is.
I have tried int charCode = int.Parse(Console.ReadLine()); as well instead of int charCode = Console.Read(); but nothing seems to work. It keeps giving me the first "if" and last "else" result, but only one of these should print so it is very confusing.
Here is my code so far:
int charCode = Console.Read();
char theRealChar = Convert.ToChar(charCode);
if (char.IsDigit(theRealChar))
{
Console.WriteLine("Digit");
}
if (char.IsLetter(theRealChar))
{
Console.WriteLine("Letter");
}
else
{
Console.WriteLine("Not a digit and not a letter");
}
Any help in making me understand this is much appreciated!
Your else statement is only associated with the second if statement. You've effectively got:
if (firstCondition)
{
// Stuff
}
// You could have unrelated code here
if (secondCondition)
{
// Stuff
}
else
{
// This will execute any time secondCondition isn't true, regardless of firstCondition
}
If you only want it to execute if neither of the earlier if statements, you need the second one to be else if:
if (char.IsDigit(theRealChar))
{
Console.WriteLine("Digit");
}
// Only check this if the first condition isn't met
else if (char.IsLetter(theRealChar))
{
Console.WriteLine("Letter");
}
// Only execute this at all if neither of the above conditions is met
else
{
Console.WriteLine("Not a digit and not a letter");
}
Seems to work fine once you add a missing else before the second if block.
if (char.IsDigit(theRealChar))
{
Console.WriteLine("Digit");
}
else if (char.IsLetter(theRealChar))
{
Console.WriteLine("Letter");
}
else
{
Console.WriteLine("Not a digit and not a letter");
}

Unorthodox approach to checking if a string is a palindrome

I'm attempting to create an unorthodox approach to working out if a string is palindrome or not. I am aware of the current .Reverse() method that you can use but this is the way that I am trying to do it:
The user will enter the string and then the program will check the first and last letters of the string. If they are the same, it will keep checking. If they are not (at the start or at any particular point) then the program will declare that it is not a palindrome. Once the program stops checking and sees that no letters are not the same, it will declare that it is a palindrome.
Here is my current code below:
using System;
using System.Collections.Generic;
namespace tasks
{
class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Enter a message and I will check if it is a palindrome: ");
string message1 = Convert.ToString(Console.ReadLine().ToLower());
char[] message = message1.ToCharArray();
int i = 0;
int j = message.Length - 1;
if (message[i] == message[j])
{
do
{
i++;
j--;
if (message[i] == message[j])
Console.Write("This is a palindrome");
else if (message[i] != message[j])
Console.Write("This is not a palindrome");
break;
} while (message[i] == message[j]);
}
else if (message[i] != message[j])
{
Console.WriteLine("This is not a palindrome");
}
}
}
(Sorry about the indentation).
If I was to type in 'haegah', the program would say that this is a palindrome. When it is clearly not. My question is, what is causing my program to do this and how can I fix it?
You've neglected to wrap { and } around Console.Write("This is not a palindrome"); break;. When you do this, only the first expression becomes conditional. The break; isn't encapsulated inside of the else branch, and will execute unconditionally thus terminating your loop in the first iteration.
This explains what I think is causing one of your problems, and how you can fix it. However, there are other problems.
By incrementing&decrementing your counters before you compare the characters, you're skipping two characters (the ones at the start and end). You can perform the incrementation & decrementation simultaneously in your loop condition with a comparison like: message[i++] == message[j--]...
Even if you fix these, your loop won't terminate sanely; the two variables will overlap, and then you'll continue until one is negative and the other is out of bounds (well, technically, they're both out of bounds)... In addition to your loop executing while message[i] == message[j], it should also only execute while i < j.
But wait, there's another problem! What do you suppose will happen when the string is an empty string? You need to guard against that condition before your loop, or use a while (...) { ... } loop.

c# loop until Console.ReadLine = 'y' or 'n'

I'm fairly new to c#, and writing a simple console app as practice. I want the application to ask a question, and only progress to the next piece of code when the user input equals 'y' or 'n'. Here's what I have so far.
static void Main(string[] args)
{
string userInput;
do
{
Console.WriteLine("Type something: ");
userInput = Console.ReadLine();
} while (string.IsNullOrEmpty(userInput));
Console.WriteLine("You typed " + userInput);
Console.ReadLine();
string wantCount;
do
{
Console.WriteLine("Do you want me to count the characters present? Yes (y) or No (n): ");
wantCount = Console.ReadLine();
string wantCountLower = wantCount.ToLower();
} while ((wantCountLower != 'y') || (wantCountLower != 'n'));
}
I'm having trouble from string wantCount; onwards. What I want to do is ask the user if they want to count the characters in their string, and loop that question until either 'y' or 'n' (without quotes) is entered.
Note that I also want to cater for upper/lower case being entered, so I image I want to convert the wantCount string to lower - I know that how I currently have this will not work as I'm setting string wantCountLower inside the loop, so I cant then reference outside the loop in the while clause.
Can you help me understand how I can go about achieving this logic?
You could move the input check to inside the loop and utilise a break to exit. Note that the logic you've used will always evaluate to true so I've inverted the condition as well as changed your char comparison to a string.
string wantCount;
do
{
Console.WriteLine("Do you want me to count the characters present? Yes (y) or No (n): ");
wantCount = Console.ReadLine();
var wantCountLower = wantCount?.ToLower();
if ((wantCountLower == "y") || (wantCountLower == "n"))
break;
} while (true);
Also note the null-conditional operator (?.) before ToLower(). This will ensure that a NullReferenceException doesn't get thrown if nothing is entered.
If you want to compare a character, then their is not need for ReadLine you can use ReadKey for that, if your condition is this :while ((wantCountLower != 'y') || (wantCountLower != 'n')); your loop will be an infinite one, so you can use && instead for || here or it will be while(wantCount!= 'n') so that it will loops until you press n
char charYesOrNo;
do
{
charYesOrNo = Console.ReadKey().KeyChar;
// do your stuff here
}while(char.ToLower(charYesOrNo) != 'n');

Categories