I am writing a method to take user input for a menu with three options: 1,2,3. My do while loop runs, however my while logic is still accepting unwanted input. Why is my code not looping for inputs outside of my set range of values?
I have tried different logical operators, removing logical operators and setting while Option < Value.
private static MenuOption ReadUserOption()
{
int Option;
Console.WriteLine("Please make a selection");
Console.WriteLine("1, will run TestName, 2 will run Guess that number, 3 Wil quit the program.");
do
{
Option = Convert.ToInt32(Console.ReadLine());
return (MenuOption)(Option - 1);
} while (Option < 1 || Option > 3);
}
My goal is for any user input outside of <1 and >3 for the loop to continue until a value within that range is entered. In its current state if I enter 0 the loop will accept that value and output -1.
You just need to move the return statement outside the loop
private static MenuOption ReadUserOption()
{
int Option;
Console.WriteLine("Please make a selection");
Console.WriteLine("1, will run TestName, 2 will run Guess that number, 3 Wil quit the program.");
do
{
Option = Convert.ToInt32(Console.ReadLine());
} while (Option < 1 || Option > 3);
return (MenuOption)(Option - 1);
}
Related
I'm new to C# and i would really need your help with a project.
The idea is to ask the user for 10 numbers between 1-20. The numbers that the user enters are stored in an array. In the next phase a random number i generated and then the program compare all the numbers that the user previously entered with the random number. If one of numbers matches the program write something like "You win!".
My current solution is okay and working but I want a better exception handling than the current one. Here is my problem:
As you can see in my code below I rely on a loop and try/catch to ensure that the user enters a valid number, but after testing several times I discovered that if you enter a valid input, let say the first time but not the second, the unvalid input is still sent to the for-loop and to the next index.
I want to ensure that the user enters a valid number and if not the for-loop would temporarily "pause" until the next VALID number is entered.
bool start = true; //Create a loop.
{
while (start == true)
{
try
{
for (int x = 0; x < vektor.Length; x++) //To fill my array.
{
Console.WriteLine("Enter a number between 1 and 20:");
vektor[x] = int.Parse(Console.ReadLine());
start = false;
}
}
catch
{
Console.WriteLine("Error, you need to enter a number!");
}
}
}
Make a method that asks the user a question and doesn't give an answer until it's valid:
public int Ask(string question, int lower, int upper){
while(true)
{
Console.WriteLine(question);
string input = Console.ReadLine();
bool valid = int.TryParse(input, out int inputInt); //valid is true if it was a number
valid = valid && inputInt >= lower && inputInt <= upper; //but also test was it in range?
if(valid)
return inputInt; //if not valid, repeat the question because the loop is infinite
}
}
valid will be true if the user enters a number, but if they entered 40 for a 1 to 20 range, then the second validity assessment is:
valid = true /*it was a number*/ && true /*40 is >= 1*/ && false /*40 is not <= 20*/
So valid becomes false. We can only escape the Ask() method, returning the valid number if valid is true, otherwise the loop goes round again
--
Now you can have a list of numbers, say you want 10, we can loop and add numbers to a list until we get 10:
List<int> numbers = new List<int>();
while(numbers.Count < 10)
{
int validNumber = Ask("Enter a nubmer between 1 and 20: ", 1, 20);
numbers.Add(validNumber);
}
You can do this as an array if you like:
int[] numbers = new int[10];
for(int x = 0; x<numbers.length; x++)
{
int validNumber = Ask("Enter a nubmer between 1 and 20: ", 1, 20);
numbers[x] = validNumber;
}
Because you know that the Ask method will never return unless the input is valid, so the loop "pauses"
So I wrote a lottery program.
The program works as the following:
the user inputs 6 numbers ranging from 1 to 46.
the program chooses 6 numbers ranging from 1 to 46.
the program compares the arrays for matching numbers.
the program shows the user how many matching number he got right and also if he won the lottery or not.
end
now , I want to add an option to the user , if the user wants to try again he can just press Y and the program will jump him to the point where he inputs numbers.
But , I don't know how to achieve that without using goto, I don't want to use goto because I know it's bad practice to use it.
Would love to get some recommendations.
I know that I am still missing the N portion of the code, but I just wanted to show what I've tried so far.
char tryAgain;
if (gamelost || gamewon == true)
{
tryAgain = 'Y';
Console.WriteLine("Do you want to try again? Y/N");
tryAgain = char.Parse(Console.ReadLine());
if (tryAgain == 'Y')
{
goto gameAgain;
}
else
{
return;
}
}
}
Use a loop. You need to check the only condition upon which you exit the loop. Note that this code doesn't sanitize user's input.
using static System.Console;
void do_lottery()
{
while (true)
{
Write("Enter 6 digits, divided by comma: ");
var input = ReadLine();
var user_numbers = input.Split(",").Select(n => int.Parse(n));
var numbers_to_guess = new[] { 6, 23, 12, 46, 8, 2 };
if (user_numbers.All(n => numbers_to_guess.Any(z => z == n)))
{
WriteLine("You won!");
}
else
{
WriteLine("You lose!");
}
Write("Do you wanna play once again? (Y/N): ");
var answer = ReadLine().ToUpper();
if (answer != "Y") break; //Exit loop
}
WriteLine("Lottery finished.");
}
I'm a novice when it comes to programing. I'm working on a sort of grocery shopping list. I have a string list, where the user can add groceries to:
List<string> list = new List<string>();
Now if the user wants to remove a certain object(grocery) in the list i would like him to do it with numbers instead of typing in the grocery name in the console window, which i have accomplished here:
case 2:
Console.WriteLine("What would you like to remove from the list?");
int removeGroc = Convert.ToInt32(Console.ReadLine());
list.RemoveAt(removeGroc);
break;
What I want to do is make sure to check that if the user enters for example number 5 but there are only 3 objects in the list, so the user will be asked to enter a number again since there are only 3 objects in the list(0, 1 and 2). I've searched everywhere and tried different things but they don't seem to work or my knowledge is to bad to understand it. So how would i go about doing this? I have a jist of what i need to do but I dont know how to do it. I'm thinking that i need to find the "id" of the list and then check if it exists, but I can't seem to find how to do this online.
Here is the edit which worked thanks to the comments if any other novice sees this:
Console.WriteLine("What would you like to remove from the list?");
var removeGroc = Console.ReadLine();
int removeGrocId;
bool parseSuccess = int.TryParse(removeGroc, out removeGrocId);
if (removeGrocId < list.Count)
list.RemoveAt(removeGrocId);
else
Console.WriteLine("Write a valid number!");
You can do it with
list.Count; //return the number of the items in the list
So you validate it with the number of the items in the list:
if(removeGroc > listCount){ //do someting }
I've found it really useful to use a helper method that will get a number from the user. This method uses TryParse to convert the input to a number, which is really handy because it returns a bool that indicates success, and then the converted number is set to an out parameter. Note that in your method above, if the user enters an invalid number, like "two", it will throw an exception.
The method below also takes in an optional string "prompt", which is displayed to the user, and then it loops until they enter a valid value:
private static int GetIntFromUser(string prompt)
{
int input;
do
{
Console.Write(prompt);
} while (!int.TryParse(Console.ReadLine(), out input));
return input;
}
Now, to get an integer from the user, we would just do:
int removeGroc = GetIntFromUser("What would you like to remove from the list?");
This can be improved slightly by adding a feature where instead of asking the question again in a new line (which can slowly eat up the console window space if they keep entering incorrect data), we can use the Console.CursorTop and Console.SetCursorPosition to overwrite the current line with blank spaces (clearing their original input) and then write the question again on the same line:
private static int GetIntFromUser(string prompt)
{
int result;
var cursorTop = Console.CursorTop;
do
{
// Set the cursor to the beginning of the line,
// write a blank line, and set it to the beginning again
Console.SetCursorPosition(0, cursorTop);
Console.Write(new string(' ', Console.WindowWidth));
Console.SetCursorPosition(0, cursorTop);
Console.Write(prompt);
} while (!int.TryParse(Console.ReadLine(), out result));
return result;
}
Alright, now we just need to add a way to specify valid entries, so that if they enter a number but it's not valid for our scenario, it will continue to ask them for valid input.
The first thing I did was write a bunch of overloads of this method that took in things like minValue, maxValue, even a List<int> validNumbers and List<int> invalidNumbers, and then had logic to check if the number they entered met all these criteria.
But since we have the ability to pass a function to a method, I opted instead to just let the client pass in their own validation function that takes in an int and returns a bool. This way the same method can be re-used for all kinds of scenarios:
private static int GetIntFromUser(string prompt, Func<int, bool> validator = null)
{
int result;
var cursorTop = Console.CursorTop;
do
{
Console.SetCursorPosition(0, cursorTop);
Console.Write(new string(' ', Console.WindowWidth));
Console.SetCursorPosition(0, cursorTop);
Console.Write(prompt);
} while (!int.TryParse(Console.ReadLine(), out result) ||
(validator != null && !validator.Invoke(result)));
return result;
}
Now we have a method that will take any type of validation we want, and will apply it to the user input. For your example, the requirements are that the number is greater than or equal to 0, and less than or equal to list.Count - 1 (to get a valid index in the list). This can be written as a lambda method like:
i => i >= 0 && i <= list.Count - 1
So, applying this to your example, we can now simply do something like:
case 2:
{
int minVal = 0;
int maxVal = list.Count - 1;
int removeGroc = GetIntFromUser($"Enter the item to remove ({minVal} - {maxVal}): ",
i => i >= minVal && i <= maxVal);
list.RemoveAt(removeGroc);
break;
}
What i want to do is to make it that inside a loop, the computer checks whether the number entered is firstly not a decimal, and at the same time i want to make sure that the number is within the range 1 - 100. My code now works in regards to having the first function about the number not being a decimal, so when i enter a decimal, an error message is displayed that tells the user to keep adding another number until an integer is added, and it then runs to the next part. However it doesn't seem to work when i put in a number outside of the range, the error message doesn't pop up and the conditions just don't seem to work. What i want to know is how do i get these two parts, the decimal and the range checking to work simultaneously. I'm really new to coding so could any explanations be simple so that i could understand. Thank you in advance!
string inputcost;
string inputmoney;
int validcost;
int validmoney;
int changereq;
Console.Write("Please Enter The Cost, In Pennies, Of The Item You Have Purchased: ");
inputcost = Console.ReadLine();
bool result = int.TryParse(inputcost, out validcost);
while (!int.TryParse(inputcost, out validcost))
{
if (result == true )
{
Console.Write("Valid Value");
}
if (result == false)
{
Console.Write("You Cannot Enter Decimals. Please Enter A Valid Integer Value.");
Console.WriteLine();
inputcost = Console.ReadLine();
}
if (validcost < 100 && validcost > 1)
{
Console.Write("valid value");
}
else
{
Console.Write("invalid value.please enter a number between 1 and 100 ");
Console.ReadLine();
}
}
The line
while (!int.TryParse(inputcost, out validcost))
means that you enter the while loop only when the user types something that cannot be converted to an integer. If it is a valid integer the code inside the while loop is never reached and thus, your test on the valid range is never executed
Instead put everything inside the an infinite loop and provide a way to break the program (type x to quit)
while (true)
{
Console.Write("Please Enter The Cost, In Pennies, Of The Item You Have Purchased: (type x to quit)");
inputcost = Console.ReadLine();
// Check if the user wants to stop executing the program
if(inputcost == "x")
break;
// Check if it is a valid integer
bool result = int.TryParse(inputcost, out validcost);
if (!result)
{
Console.WriteLine("You Cannot Enter Decimals (or strings). Please Enter A Valid Integer Value.");
}
else if (validcost > 100 || validcost < 1)
{
Console.WriteLine("invalid value.please enter a number between 1 and 100 ");
}
else
{
Console.WriteLine("Valid value");
// other code block that works with the input number....
}
}
Alternativly use another condition for your loop, something that first checks for an integer and afterwards if it is in range:
while (!int.TryParse(inputcost, out validcost)) || validCost < 1 || validCost > 100)
{
Console.WriteLine("Please enter an integer between 1 and 100");
inputCost = Console.ReadLine();
}
All the code that should be executed when your inout is valid should now gow beyond the loop, not inside it.
There is something wrong with my code. I am teaching myself c# and one of the challenges in this chapter was to prompt the user for 10 numbers, store them in an array, than ask for 1 additional number. Then the program would say whether the additional number matched one of the numbers in the array. Now what I have below does work, but only if I enter in a comparison number that is less than 10 which is the size of the array.
I'm not sure how to fix it. I am not sure how to do the comparison. I tried a FOR loop first which kind of worked, but ran through the loop and displayed the comparison against all 10 numbers so you would get 9 lines of No! and 1 line of Yes!. I put in a break; which stopped it counting all 10 but if I entered the number 5 for comparison, then I would get 4 lines of No! and 1 of Yes!. The below has been the only way I could get it to work reliably but only as long as the number isn't out of the bounds of the array.
I can see why I get the error when the number is above 10, I just don't know what to use to compare it but still allow the user to enter in any valid integer. Any assistance would be great!
int[] myNum = new int[10];
Console.WriteLine("Starting program ...");
Console.WriteLine("Please enter 10 numbers.");
for (int i = 0; i <= 9; ++i)
{
Console.Write("Number {0}: ", i + 1);
myNum[i] = Int32.Parse(Console.ReadLine());
}
Console.WriteLine("Thank you. You entered the numbers ");
foreach (int i in myNum)
{
Console.Write("{0} ", i);
}
Console.WriteLine("");
Console.Write("Please enter 1 additional number: ");
int myChoice = Int32.Parse(Console.ReadLine());
Console.WriteLine("Thank you. You entered the number {0}.", myChoice);
int compareArray = myNum[myChoice - 1];
if (compareArray == myChoice)
{
Console.WriteLine("Yes! The number {0} is equal to one of the numbers you previously entered.", myChoice);
}
else
{
Console.WriteLine("No! The number {0} is not equal to any of the entered numbers.", myChoice);
}
Console.WriteLine("End program ...");
Console.ReadLine();
You were on the right track- you want to loop through the array in myNum and compare each element to the variable myChoice. If you don't want to print whether each element of the array is a match, create a new variable and use it to keep track of whether you've found a match or not. Then after the loop you can check that variable and print your finding. You'd usually use a bool variable for that- set it false to start, then true when you find a match.
bool foundMatch = false;
for (int i = 0; i < 10; i++) {
if (myNum[i] == myChoice) {
foundMatch = true;
}
}
if (foundMatch) {
Console.WriteLine("Yes! The number {0} is equal to one of the numbers you previously entered.", myChoice);
}
If you include the System.Linq namespace (or if you change the type of myNum to be something that implements ICollection<T>, like List<T>), you can use myNum.Contains(myChoice) to see if the value myChoice matches one of the values in myNum. array.Contains returns a boolean that is true if the specified value is found in the array and false if it is not.
You can update your code to use this like so:
//int compareArray = myNum[myChoice - 1]; // This line is no longer needed
if (myNum.Contains(myChoice))
{
Console.WriteLine("Yes! The number {0} is equal to one of the numbers you previously entered.", myChoice);
}
else
{
Console.WriteLine("No! The number {0} is not equal to any of the entered numbers.", myChoice);
}
If you're looking for numbers that are definitely between 1 and 10, then before you use
int compareArray = myNum[myChoice - 1];
check if it's over the value of 10. For example:
while(myChoice > 10)
{
Console.Write("Please choose a number less than or equal to 10: ");
myChoice = Int32.Parse(Console.ReadLine());
}
The benefit of putting it inside a while loop instead of an if tag means that, when the user enters another number, the value of myChoice will be rewritten, and compared against. If they enter a number over 10, it'll keep responding Please choose a number less than or equal to 10. until the number they input is below or equal to 10:` Then, your program will continue.
However, if you want to compare it against the array, rather than put in a fixed number comparison, consider the following while loop:
while(myChoice > myNum.Length)
{
Console.Write("Please choose a number less than or equal to {0}: ", myNum.Length);
myChoice = Int32.Parse(Console.ReadLine());
}
This will work for any sized array then, without you having to change the while loops content. By using this system, you can then ensure that you won't get an IndexOutOfBounds exception, so long as you subtract 1 when using it as an index.
You are looking to compare a final, 11th value and trying to determine if its in an array of 10 previous entries?
Try:
for(int i = 0; i < array.length - 1; i++;)
{
If(array[i] == input)
return true;
}
return false;
You should be able to figure out how to implement this completely yourself, as you did want to do it as an exercise.
Edit: If someone wants to check this or complete it in correct syntax, go ahead. I posted this rough outline from a phone.