so I'm currently taking a course on C# programming to get freshened up.
Turned out I forgot some important things!
namespace FitnessFrog
{
class Program
{
static void Main()
{
int runningTotal = 0;
bool keepGoing = true;
while(keepGoing)
{
// Prompt the user for minutes exercised
Console.Write("Enter how many minutes you exercised or type \"quit\" to exit: ");
string input = Console.ReadLine();
if (input == "quit")
{
keepGoing = false;
}
else
{
try
{
int minutes = int.Parse(input);
runningTotal = runningTotal + minutes;
if(minutes <= 0)
{
Console.WriteLine("Eh, what about actually exercising then?");
continue;
}
else if(minutes <= 10)
{
Console.WriteLine("Better than nothing, am I right?");
}
else if (minutes <= 24)
{
Console.WriteLine("Well done, keep working!");
}
else if (minutes <= 60)
{
Console.WriteLine("An hour, awesome! Take a break, ok?");
}
else if (minutes <= 80)
{
Console.WriteLine("Woah, remember to drink if you're going to exercise THAT long!");
}
else
{
Console.WriteLine("Okay, now you're just showing off!");
}
Console.WriteLine("You've exercised for " + runningTotal + " minutes");
}
catch(FormatException)
{
Console.WriteLine("That is not valid input");
continue;
}
// Repeat until the user quits
}
}
}
}
}
So I'm trying to make it say "This is not valid input" when you type a string instead of an integer.
Thanks in advance! <3
int minutes = int.Parse(input); - you should use TryParse() instead of Parse()
int minutes;
bool parsed = int.TryParse(input, out minutes);
if (parsed)
{
// your if statements
}
else
{
Console.WriteLine("That is not valid input");
}
You should use int.TryParse instead for Parse, since it having internal exception handling mechanisms, And you can use it's return value(true/false)to check whether the operation is successful or not, for a successful conversion it will return true, and the return value for a failure conversion will be false
int minutes;
if(!int.TryParse(input,out minutes)
{
Console.WriteLine("invalid input");
}
else
{
// Proceed
}
If you are receiving input from your users, you will want to consider actually using the Int32.TryParse() method to determine if the parse was successful or not :
int minutes;
// Attempt the parse here
if(Int32.TryParse(input, out minutes))
{
// The parse was successful, your value is stored in minutes
}
else
{
// The parse was unsuccessful, consider re-prompting the user
}
Related
Can someone help me modify my work? Help me add:
An error message when the user tries to enter decimal values.
A third operand for the calculator.
An error message when the user tries to enter any string value other than “exit”.
Here's my code:
class Program
{
static void Main(string[] args)
{
do
{
Console.Write("x = ");
string str = Console.ReadLine();
if (str == "exit")
{
Console.WriteLine("The Programme has stopped");
continue;
}
else
{
int x = Convert.ToInt32(str);
Console.Write("y = ");
int y = Convert.ToInt32(Console.ReadLine());
int sum = x / y;
Console.WriteLine("Result: {0}", sum);
}
}
while (true);
}
}
I'd be very grateful.
Here is a function you can use:
public static bool HasDecimals(decimal x) {
return Decimal.Round(x, 0) != x;
}
If I were going to do this, I'd create a function that I can use to handle most of the user interaction (emitting the prompt, parsing the input string, deciding if "Exit" was entered). In the code below, I kinda-sorta use the standard TryGetXxx pattern.
In this code below, if the TryGetDecimalValueWithPrompt returns true, then a properly parsed number is returned in the output. If it returns false, then the user has chosen to quit.
So, I start with that function:
public static bool TryGetDecimalValueWithPrompt(string prompt, out decimal outputValue)
{
while (true)
{
Console.Write(prompt + " > ");
var response = Console.ReadLine();
if (response.Equals("exit", StringComparison.OrdinalIgnoreCase) || response.Equals("quit", StringComparison.OrdinalIgnoreCase))
{
outputValue = 0.0m;
return false;
}
if (decimal.TryParse(response, out outputValue))
{
return true;
}
//otherwise, failure, so try again
Console.WriteLine("Sorry, incorrect format, try entering a correctly formatted decimal again");
}
}
The while(true) statement says Loop Forever. In this case, Forever lasts until the user has entered a properly formatted number or one of the "exit" keywords.
Then I construct my program around it:
if (!TryGetDecimalValueWithPrompt("Enter the first operand", out var operand1))
{
return;
}
if (!TryGetDecimalValueWithPrompt("Enter the second operand", out var operand2))
{
return;
}
if (operand2 == 0.0m)
{
Console.WriteLine("Sorry, you can't divide by zero");
return;
}
Console.WriteLine($"The result of op1/op2 is {operand1 / operand2}");
If you don't want to allow decimals being entered, change the TryGetDecimalValueWithPrompt function to work with integers instead:
public static bool TryGetIntValueWithPrompt(string prompt, out int outputValue)
{
while (true)
{
Console.Write(prompt + " > ");
var response = Console.ReadLine();
if (response.Equals("exit", StringComparison.OrdinalIgnoreCase) || response.Equals("quit", StringComparison.OrdinalIgnoreCase))
{
outputValue = 0;
return false;
}
if (int.TryParse(response, out outputValue))
{
return true;
}
//otherwise, failure, so try again
Console.WriteLine("Sorry, incorrect format, try entering a correctly formatted integer again");
}
}
If you work with integers, remember that integer division always yields an integer. For example, if you use integers in 7 / 2, the result will be 3, not 3.5. If you want 3.5, do something like 7 / (decimal) 2 (at that point, you are dividing an integer by a decimal and you'll get a decimal).
By the way, if you wanted to prompt for the operator (+, -, *, or /), you could create a TryGetOperator function in the same pattern and just check whatever you get from the user with something like:
var operators = new[] { "+", "-", "*", "/" };
bool goodOperator = operators.Contains(inputFromUser);
So, I'm building this little guessing game and I recently added a try/catch to stop the console from crashing if the user inputted a wrong character (besides numbers of course). Right now it works well but it restarts the entire game, I've tried to just have the catch re-run the script starting at the "for" loop, but it breaks and the random number originally generated doesn't match.
public static void StartGame()
{
Console.Clear();
Random ran = new Random();
decimal returnValue = (ran.Next(1, 100));
Console.WriteLine("Welcome to my guessing game. I'm thinking of a number between 1 and 100, can you guess it?");
Console.WriteLine("Hint: 'Way too off' means you're greater than 25 from the answer!");
try
{
for (int guessnumber = 1; guessnumber < 6; guessnumber++)
{
var Guess = Convert.ToInt32(Console.ReadLine());
//The Guess variable is simply whatever the user inputs, which is read and used by the for loop each time it is inputed.
if (Guess == returnValue)
{
Console.WriteLine("Well done!");
Console.ReadKey();
Game.NewGame();
}
else if (Guess < returnValue)
{
Console.WriteLine("Guess higher!");
}
else if (Guess > returnValue)
{
Console.WriteLine("Guess lower!");
}
if (guessnumber == 5)
{
Console.WriteLine($"The correct answer was {returnValue}");
Console.ReadKey();
Game.NewGame();
//This if statement activates when the "guessnumber" counter has reached 5, in which case it will tell the user the correct answer, and end with a return statement.
}
//result is the absolute value of
decimal result = Math.Abs(returnValue - Guess);
if (result > 25)
Console.WriteLine("Way too off!");
if (result < 5)
{
Console.WriteLine("Very close!!");
}
if (result < 2)
{
Console.WriteLine("RED HOT!!!");
}
}
}
catch (System.FormatException)
{
Console.WriteLine("Incorrect character inputted, restarting game. . .");
System.Threading.Thread.Sleep(2000);
StartGame();
}
}
public static void NewGame()
{
Console.Clear();
string input = " ";
Console.WriteLine("Game over, would you like to play again? Y/N");
input = Console.ReadLine();
input = input.ToUpper();
if (input == "Y")
{
Console.WriteLine("Ok! Re-Initializing game...");
StartGame();
}
else
{
System.Environment.Exit(0);
}
}
}
}
As another answer stated, you can just move your try/catch inside the for loop, so the loop continues.
But you really shouldn't be relying on exception handing for something that isn't exceptional, like parsing user input.
Instead, we can use the int.TryParse method to try to parse a string to an int. The nice thing about this method is that it returns true if the parse was successful, and it sets an out parameter to the parsed value.
We can also put it in it's own method that takes in a string to be used to prompt the user, which makes the code more reusable:
public static int GetIntFromUser(string prompt)
{
int result;
bool askedOnce = false;
do
{
if (askedOnce) Console.WriteLine("Invalid input, please try again.");
Console.Write(prompt);
askedOnce = true;
} while (!int.TryParse(Console.ReadLine(), out result));
return result;
}
Now our main code is greatly simplified (also notice that the Random instance should be a class field, not created on every call to StartGame, and notice that the upper bound specified in the call to ran.Next is exclusive, so if you want to include 100 as a possible answer, make the max value 101):
private static Random ran = new Random();
public static void StartGame()
{
Console.Clear();
int randomNumber = ran.Next(1, 101);
Console.WriteLine("Welcome to my guessing game");
Console.WriteLine("I'm thinking of a number between 1 and 100, can you guess it?");
for (int guessCount = 1; guessCount < 6; guessCount++)
{
var guess = GetIntFromUser($"Guess a number (try #{guessCount}): ");
if (guess == randomNumber)
{
Console.WriteLine("Well done!");
Console.ReadKey();
Game.NewGame();
}
else if (guessCount == 5)
{
Console.WriteLine("That was your last guess.");
Console.WriteLine($"The correct answer was: {randomNumber}.");
Console.ReadKey();
Game.NewGame();
}
else
{
decimal result = Math.Abs(randomNumber - guess);
if (result > 25) Console.Write("You're way off! ");
else if (result < 5) Console.Write("Very close!! ");
else if (result < 2) Console.WriteLine("You're RED HOT!!! ");
Console.WriteLine(guess < randomNumber ? "Guess higher!" : "Guess lower!");
}
}
}
Move the Try Catch handling inside for loop. What this does is, that exceptions are handled during each guess iteration.
What you had originally was exception handling for all iterations.
Also, Dont call the StartGame Function again in your catch block. You want to allow 6 (per the for loop) Guesses and not Infinite.
Ex:
for (int guessnumber = 1; guessnumber < 6; guessnumber++)
{
try
{
}
catch (System.FormatException)
{
}
}
The simple answer is as follows:
You don't control application flow with exception handling. Catching exceptions are for exceptional circumstances, a user getting input wrong isn't exceptional... it's guaranteed.
Never ever ever ever ever (+1000) use Convert.... or int.Parse to take user input... Users make mistakes all the time, use the TryParse type methods instead, they return a bool to say if the data was successfully parsed so you can then deal with it.
Eg
var success = int.TryParse(Console.ReadLine(), out var guess);
However, you can take it one step further, and add a loop (add pepper and salt to taste)
int guess = 0;
while(!int.TryParse(Console.ReadLine(), out guess))
Console.WriteLine("Omg you had one job, just enter a number");
Additional Resources
Int32.TryParse Method
Converts the string representation of a number to its 32-bit signed
integer equivalent. A return value indicates whether the operation
succeeded.
I need the program to continue and prompt the user for a new value after an exception throw.
Program throws a run time error when hitting the exception, says it is unhandled
using System;
using static System.Console;
class SwimmingWaterTemperature
{
static void Main()
{
// Your code here
int temp = 0;
Console.WriteLine("Enter temperature or type 999 to quit");
do
{
temp = Convert.ToInt32(Console.ReadLine());
bool comfort = CheckComfort(temp);
}
while (temp != 999);
}
public static bool CheckComfort(int temp)
{
// your logic here
bool comfort;
if (temp >= 70 && temp <= 85)
{
Console.WriteLine("{0} Degrees is comfortable for swimming.", temp);
Console.WriteLine("Enter another temperature or 999 to quit");
comfort = true;
return comfort;
}
else if ((temp >= 32 && temp <= 70) || (temp >= 85 && temp <= 212) && temp != 999)
{
Console.WriteLine("{0} Degrees is not comfortable for swimming.", temp);
Console.WriteLine("Enter another temperature or 999 to quit");
comfort = false;
return comfort;
}
else if (temp == 999)
{
comfort = false;
return comfort;
}
else
{
throw new System.ArgumentException("Value does not fall within expected range");
Console.WriteLine("Enter another temperature or 999 to quit");
}
}
}
"Runtime error, unhandled exception"
A common rule of thumb is: Exceptions should be exceptional.
You should never, ever, use exceptions for control flow, we have a lot of other constructs that are better for that. There's absolutely no surprise if the user inputs something invalid, that's a valid usage of your application, so the application should not treat the case where the user goes off script as unexpected. In fact, you can expect it and test for it.
So, in your case, it's much, much better to refactor the code.
You know that 999 is the quit command (that can also be done better, but lets keep it)
You know that the valid range is 32 to 212, so you can have a method
that checks that.
Something along these lines is a much better approach:
static void Main()
{
// Your code here
int temp = 0;
do
{
// we can do at the start of every loop, no need to have the same code in multiple places
Console.WriteLine("Enter temperature or type 999 to quit");
temp = Convert.ToInt32(Console.ReadLine());
// no need to do additional processing if we got the quit sequence
if (temp != 999) {
// and here we KNOW that we are not in a quit sequence
// now check if the entered value is valid
bool isValid = CheckValidTemperature(temp);
if (isValid) {
// here we KNOW that the temperature is in the valid range
bool comfort = CheckComfort(temp);
if (comfort) {
Console.WriteLine("{0} Degrees is comfortable for swimming.", temp);
} else {
Console.WriteLine("{0} Degrees is not comfortable for swimming.", temp);
}
} else {
// here we KNOW that the temperature in NOT in the valid range
// no need for exceptions, we just show a message
Console.WriteLine("Value does not fall within expected range");
}
}
}
while (temp != 999);
}
public static bool CheckValidTemperature(int temp)
{
// the range 32 - 212 is valid, everything else is invalid
return (temp >= 32 && temp <=212);
}
public static bool CheckComfort(int temp)
{
// your logic here - no need to validate anything, as we know that it is valid
// however, we could validate here, and if it's invalid now, that would indeed be exceptional
//if (!CheckValidTemperature(temp)) {
// // quite ok to throw here, as this should never happen under normal circumstances
// throw new ArgumentException("Value does not fall within expected range");
//}
// this can be some complicated logic
if (temp >= 70 && temp <= 85)
{
return true;
}
else
{
return false;
}
}
I'll leave the case when the user enters something that is not a number at the prompt as a extension that will need to be implemented :D
try
{
throw new System.ArgumentException();
}
catch (ArgumentException)
{
Console.WriteLine("Value does not fall within the expected range.");
Console.WriteLine("Enter another temperature or 999 to quit");
comfort = false;
return comfort;
}
I have a method which counts the amount of times a user has withdrawn from the atm(as there is a limit) and also counts up the amount of money the user has withdrawn in the day. However the values in the count var and in the amountWithdrawn variable are both lost upon leaving the method, how do I keep them "saved"? Also as a side note, I have a class called Account which has the balance and such, would it be best to put them there? But would also like to know if it is possible to save the variables in the method for future reference.
public decimal WithDraw()
{
int timesWithdrawn = 9;
decimal amountWithdrawnToday = 0;
decimal money = 0;
bool success = false;
if (timesWithdrawn < 10)
{
do
{
//Console.WriteLine("{0} available to withdraw.", FundsAvailable);
Console.WriteLine("How much would you like to withdraw?");
try
{
money = decimal.Parse(Console.ReadLine());
if (money % 5 == 0 && money <= account.CurrentBalance && money <= 1000)
{
success = true;
}
if (money == 0)
{
bool exit = true;
Console.WriteLine("Do you want to exit? Type \"yes\", or \"no\".");
while (exit == true)
{
string response = Console.ReadLine();
if (response.ToLower() == "yes")
{
break;
}
else
{
exit = false;
}
}
}
}
catch (FormatException)
{
Console.WriteLine("Please enter a number to withdraw.");
}
} while (success == false);
//do while this is true
Console.WriteLine(account.CurrentBalance);
Console.WriteLine("Withdrawing {0} pounds.", money);
Console.WriteLine("You have {0} remaining in your account.", account.CurrentBalance - money);
amountWithdrawnToday += money;
timesWithdrawn += 1;
Console.WriteLine("{0} pounds withdrawn today", amountWithdrawnToday);
return account.CurrentBalance -= money;
}
else
{
Console.WriteLine("You have exceeded daily withdrawls. You have withdrawn {0}", amountWithdrawnToday);
return amountWithdrawnToday;
}
}
I will suggest you need to put those variable in the Account class, also I suggest that you could put the withdraw method itself in the Account class, This could be more OOP friendly.
and to save the timesWithdrawn number, you just need to make it as class instance vairable instead of making it local variable
here is the code
class Account
{
public decimal CurrentBalance { get; set; }
public int timesWithdrawn { get; set; } = 9;
public decimal WithDraw()
{
decimal amountWithdrawnToday = 0;
decimal money = 0;
bool success = false;
if (timesWithdrawn < 10)
{
do
{
//Console.WriteLine("{0} available to withdraw.", FundsAvailable);
Console.WriteLine("How much would you like to withdraw?");
try
{
money = decimal.Parse(Console.ReadLine());
if (money % 5 == 0 && money <= CurrentBalance && money <= 1000)
{
success = true;
}
if (money == 0)
{
bool exit = true;
Console.WriteLine("Do you want to exit? Type \"yes\", or \"no\".");
while (exit == true)
{
string response = Console.ReadLine();
if (response.ToLower() == "yes")
{
break;
}
else
{
exit = false;
}
}
}
}
catch (FormatException)
{
Console.WriteLine("Please enter a number to withdraw.");
}
} while (success == false);
//do while this is true
Console.WriteLine(CurrentBalance);
Console.WriteLine("Withdrawing {0} pounds.", money);
Console.WriteLine("You have {0} remaining in your account.", CurrentBalance - money);
amountWithdrawnToday += money;
timesWithdrawn += 1;
Console.WriteLine("{0} pounds withdrawn today", amountWithdrawnToday);
return CurrentBalance -= money;
}
else
{
Console.WriteLine("You have exceeded daily withdrawls. You have withdrawn {0}", amountWithdrawnToday);
return amountWithdrawnToday;
}
}
}
as you notice from the code, I removed the reference to the account variable and made the CurrentBalance as instance variable and also the timesWithdrawn.
this could preserve the value of the timesWithdrawn even after the method has been finished.
As long as the program is running it is saved there, but once quite it resets, so yes you have to save it somewhere in a database a excel table or in a text document
Saving data to a file in C#
check this out if you need some help how to do stuff like this
You could pass an 'out' parameter to the function, it's basically a variable you send to the function, which holds its value outside the function.
For example:
public void WithDraw(out int c) {
c = something ; //c must receive a value during the call
}
int myvar; // the parameter which will hold the value when the function returns
WithDraw(out myvar); //call to the function
myvar //will now hold a value from the function (something)
You could also consider returning a tuple, or putting the value you wish to save into a 'global variable'.
The title is a bit messy in regards to getting what I want out there and it's my first time on here.
Basically I have converted my string into an int :
string _val = Console.ReadLine();
tempScoreToWin = Convert.ToInt32(_val);
And what I want to know is when user a presses enter without entering a value an error will occur and the application will end.
How can I get around this?
Here is my full code:
while (true)
{ //This will allow the player to manually change the score.
//------------------------------------------------------------------------------------------
string _val = "";
ConsoleKeyInfo key;
do
{
key = Console.ReadKey(true);
if (key.Key != ConsoleKey.Backspace)
{
double val = 0;
bool _x = double.TryParse(key.KeyChar.ToString(), out val);
if (_x)
{
_val += key.KeyChar;
Console.Write(key.KeyChar);
}
}
else
{
if (key.Key == ConsoleKey.Backspace && _val.Length > 0)
{
_val = _val.Substring(0, (_val.Length - 1));
Console.Write("\b \b");
}
}
}
while (key.Key != ConsoleKey.Enter);
Console.WriteLine();
//-----------------------------------------------------------------
tempScoreToWin = Convert.ToInt32(_val); // Converting the users input (Console.ReadLine()) into an integer.
if (tempScoreToWin > 0) // If the users input is higher than zero ...
{
scoreToWin = tempScoreToWin; // Reset the scoreToWin variable with the value of tempScoreToWin.
Console.WriteLine("The score has been set to {0}.", scoreToWin); // Let the user know that the score has been changed successfully.
break; // Break out of the while loop.
}
else
{ // If the player has not put a correct integer in ...
Console.WriteLine("The score has been set at a default of {0}.", scoreToWin); // then the score will be set to the default value of scoreToWin
break; // Break out of the while loop.
}
}
Console.ReadLine();
Console.Clear();
//-----------------------------------------------------------------
Cheers!
Using TryParse will allow you to parse a string for an integer while also checking if it succeeded.
if(int.TryParse(_val, out tempScoreToWin)
{
//Parse succeeded
}
else
{
//Parse failed
}
Brilliant! That worked MrZander. Thank you guys so much for the quick answer. I really appreciate it :)
if (int.TryParse(_val, out tempScoreToWin))
{
if (tempScoreToWin > 0) // If the users input is higher than zero ...
{
scoreToWin = tempScoreToWin; // Reset the scoreToWin variable with the value of tempScoreToWin.
Console.WriteLine("The score has been set to {0}.", scoreToWin); // Let the user know that the score has been changed successfully.
break; // Break out of the while loop.
}
else
{ // If the player has not put a correct integer in ...
Console.WriteLine("The score has been set at a default of {0}.", scoreToWin); // then the score will be set to the default value of scoreToWin
break; // Break out of the while loop.
}
}
else
{
//Parse failed
}