So I'm learning C#, and I'm trying to make a simple text based RPG, but when I run the character creation this keeps happening:
5 Points Left
Strength?
Input: 4
Point amount too high! Press Enter.
Here's The Code.
public static void Start()
{
Console.Clear();
int charcreatepts = 10;
Console.WriteLine ("{0} Points Left", charcreatepts);
Console.WriteLine ("Intelligence?");
int CCPint1 = Convert.ToInt32 (Console.ReadLine ());
charcreatepts = charcreatepts - CCPint1;
if (CCPint1 > charcreatepts) {
Console.WriteLine ("Point amount too high! Press Enter.");
Console.ReadLine ();
Start ();
}else{
Console.Clear ();
Console.WriteLine ("{0} Points Left", charcreatepts);
Console.WriteLine ("Strength?");
int CCPint2 = Convert.ToInt32 (Console.ReadLine ());
charcreatepts = charcreatepts - CCPint2;
if (CCPint2 > charcreatepts) {
Console.WriteLine ("Point amount too high! Press Enter.");
Console.ReadLine ();
Start ();
}else{
Console.Clear ();
Console.WriteLine ("{0} Points Left", charcreatepts);
Console.WriteLine ("Social Skills?");
int CCPint3 = Convert.ToInt32 (Console.ReadLine ());
charcreatepts = charcreatepts - CCPint3;
if (CCPint3 > charcreatepts) {
Console.WriteLine ("Point amount too high! Press Enter.");
Console.ReadLine ();
Start();
}
}
}
}
}
I'm trying to get it so if you want, you can use the 5 remaining points on in this case, strength, but for some reason I can't even use 4.
It looks like you are subtracting too early. Given: charcreatepts = charcreatepts - CCPint1, and charcreatepts = 5 and CCPint1 = 4 then charcreatepts = 5 - 4 = 1
Then:
if (CCPInt1 > charcreatepts) { ... } would be if (4 > 1) { ... }
You should check if CCPint1 is greater than charcreatepts before you try to calculate the new value.
Related
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 1 year ago.
Improve this question
I am working on a homework problem for the school. The user is to enter 7 temperatures. These temperatures are to be displayed back to the user and then the average temperature of the 7 is to be displayed. When I am working on the problem I am running into the problem that 1 of the temperatures that were entered is not being registered into the array. I can't seem to understand what I am doing wrong.
class Program
{
private static double[] temperatureArray = new double[10];
static void Main()
{
Heading();
TempInput();
Read();
}
private static void Heading()
{
WriteLine("\t Weekly Temerature Report");
WriteLine("\t " + DateTime.Today.ToShortDateString());
WriteLine("Enter 7 Temperatures");
WriteLine("**********************************************");
}
private static void TempInput()
{
double total = 0;;
string inputValue;
int i = 0;
int number;
double average = 0;
double ctr = 1;
Write("Enter Temperature {0} ", ctr);
inputValue = ReadLine();
while (ctr <= 7)
{
if (int.TryParse(inputValue, out number) == false)
{
WriteLine("Invalid input");
i -= 1;
}
else
{
//good input
temperatureArray[i] = double.Parse(inputValue);
i += 1;
ctr += 1;
Write("Enter Temperature {0} ", ctr );
inputValue = ReadLine();
}
}
for (int n = 0; n<i;n++)
{
WriteLine(temperatureArray[n]);
total += temperatureArray[n];
average = total / 7;
}
Write("average temp is {0}", average);
}
}
Your problem is that your code is structured in a way that the last input is never added to the temperatureArray. When you ask for the last input then the variable ctr has already reached the value that exits the loop (7) So the code exits the loop without inserting the last value in the array.
A fast fix could be to add this line after the loop exit
while(ctr < 7)
{
.....
else
{
//good input
temperatureArray[i] = double.Parse(inputValue);
i += 1;
ctr += 1;
Write("Enter Temperature {0} ", ctr );
inputValue = ReadLine();
}
}
// catch the last input.
temperatureArray[i] = double.Parse(inputValue);
but a better approach is to restructure your code and ask for the input immediately when you enter the loop
while(ctr < 7)
{
Write("Enter Temperature {0} ", ctr);
inputValue = ReadLine();
if(!double.TryParse(inputValue, out double temp))
{
WriteLine("Error");
continue;
}
else
{
temperatureArray[ctr] = temp;
ctr++;
}
}
Move this code inside a loop
Write("Enter Temperature {0} ", ctr);
inputValue = ReadLine();
So, the loop will be something like that:
while (ctr <= 7)
{
Console.Write("Enter Temperature {0} ", ctr);
inputValue = Console.ReadLine();
if (int.TryParse(inputValue, out number) == false)
{
Console.WriteLine("Invalid input");
}
else
{
//good input
temperatureArray[i] = double.Parse(inputValue);
i += 1;
ctr += 1;
}
}
Here, at first, we read the input, then validate it.
So, today I decided to start learning C# from scratch. I've managed to make a little math problems program. The thing is, whenever the user just presses enter without entering a value (or anything which isn't a number), the program crashes. I've read something about TryParse but I just can't get it.
Here's my code (part of it):
{
Random numberGenerator = new Random();
int num01 = numberGenerator.Next(1, 20);
int num02 = numberGenerator.Next(1, 20);
Console.WriteLine("Welcome, user.");
Console.ReadKey();
Fail2:
Console.WriteLine("¿What's " + num01 + "x" + num02 + "?");
int res1 = Convert.ToInt32(Console.ReadLine());
if (res1 == num01*num02)
{
Console.WriteLine("Your answer is correct");
Console.ReadKey();
}
else
{
goto Fail;
}
Thanks in advance!
Hello & welcome to StackOverflow! I have a couple of suggestions:
Avoid using goto
Replace all your Convert.X with X.TryParse whenever it's the user who gives you the value, since you don't know what it could be
Random numberGenerator = new Random();
int num01 = numberGenerator.Next(1, 20);
int num02 = numberGenerator.Next(1, 20);
Console.WriteLine("Welcome, user.");
Console.ReadKey();
// Always use a loop instead of goto statements!
while (true)
{
Console.WriteLine("¿What's " + num01 + "x" + num02 + "?");
// Old line: int res1 = Convert.ToInt32(Console.ReadLine());
// Problem: this assumes that Console.ReadLine() returns a valid number, e.g. "3"
// but as you said, the user can trick you and put something else
if (!int.TryParse(Console.ReadLine(), out int res1))
continue; // This will rerun the loop from the top, so the user will need to re-write a response
if (res1 == num01*num02)
{
Console.WriteLine("Your answer is correct");
Console.ReadKey();
}
else
{
break; // stop the outer loop on top
}
}
Use int.TryParse like this...
int res1 = 0;
if (!int.TryParse(Console.ReadLine(), out res1))
{
//failed;
}
if (res1 == num01*num02)
...
https://learn.microsoft.com/en-us/dotnet/api/system.int32.tryparse?view=netcore-3.1
I've read that using "goto" in C# is not recommended
However, my code uses goto and so far, errors appeared when trying to avoid "goto"
anum1r:
Console.Write ("What is the first number? ");
try {
num1 = Convert.ToDouble (Console.ReadLine ());
} catch (System.FormatException) {
Console.Beep ();
Console.WriteLine ("");
Console.WriteLine ("You have entered an invalid number!");
Console.WriteLine ("");
goto anum1r;
}
anum2r:
Console.Write ("What is the second number? ");
try {
num2 = Convert.ToDouble (Console.ReadLine ());
} catch (System.FormatException) {
Console.Beep ();
Console.WriteLine ("");
Console.WriteLine ("You have entered an invalid number!");
Console.WriteLine ("");
goto anum2r;
}
answer = num1 + num2;
How do I transform this code without using GOTO. ty
Use a while loop:
double num1;
while (true) {
Console.Write ("What is the first number? ");
try {
num1 = Convert.ToDouble (Console.ReadLine ());
break;
} catch (System.FormatException) {
Console.Beep ();
Console.WriteLine ("");
Console.WriteLine ("You have entered an invalid number!");
Console.WriteLine ("");
}
}
As you need this code twice, it is also a good idea to refactor it in a separate method like #James' answer. (Though it needs an extra parameter to modify the user prompt.)
You could use a while loop
private double? GetNumber()
{
double? result = null;
try {
result = Convert.ToDouble (Console.ReadLine ());
} catch (System.FormatException) {
Console.Beep ();
Console.WriteLine ("");
Console.WriteLine ("You have entered an invalid number!");
Console.WriteLine ("");
}
return result;
}
...
// prompt for first number
double? num1 = null;
while (!num1.HasValue)
{
Console.Write ("What is the first number? ");
num1 = GetNumber();
}
// prompt for second number
double? num2 = null;
while (!num2.HasValue)
{
Console.Write ("What is the second number? ");
num2 = GetNumber();
}
// calculate result
answer = num1.Value + num2.Value;
There are two good ways to improve your code:
Extract into a separate method the logic for repeatedly asking the user for a number until they enter a valid one. (Use a loop construct to handle looping rather than a goto.)
Use double.TryParse() to avoid having to catch a format exception.
If you put both of those together, you get code that looks something like this:
using System;
namespace Demo
{
public static class Program
{
private static void Main()
{
double first = askForNumber("What is the first number? ");
Console.WriteLine();
double second = askForNumber("What is the second number? ");
Console.WriteLine("\nYou entered {0} and {1}", first, second);
}
private static double askForNumber(string prompt)
{
while (true)
{
Console.Write(prompt);
double result;
if (double.TryParse(Console.ReadLine(), out result))
return result;
Console.Beep();
Console.WriteLine("\nYou have entered an invalid number!\n");
}
}
}
}
You can use a for-loop and a collection like a double[], also use double.TryParse:
int numbers = 10;
double[] allNumbers = new double[numbers];
for (int i = 0; i < numbers; i++)
{
Console.Write("What is the {0}. number? ", i + 1);
double num;
if (double.TryParse(Console.ReadLine().Trim(), out num))
{
allNumbers[i] = num;
}
else
{
i--; // ask the user until we have the numbers
Console.Beep();
Console.WriteLine("");
Console.WriteLine("You have entered an invalid number!");
Console.WriteLine("");
}
}
double answer = allNumbers.Sum(); // LINQ so add using System.Linq;
Another way is to extract a method for this purpose:
private static double? ReadNumberFromConsole()
{
double num;
if (double.TryParse(Console.ReadLine().Trim(), out num))
return num;
else
return null;
}
That makes the code more readable:
for (int i = 0; i < numbers; i++)
{
Console.Write("What is the {0}. number? ", i + 1);
double? num = ReadNumberFromConsole();
if (num.HasValue)
{
allNumbers[i] = num.Value;
}
else
{
i--; // ask the user until we have the numbers
Console.Beep();
Console.WriteLine("");
Console.WriteLine("You have entered an invalid number!");
Console.WriteLine("");
}
}
I would also highly recommend avoid using Convert.ToDouble on user input.
Using exceptions as an input validating system is wrong on every level.
Use something like this instead:
double GetNumberFromUser() {
double Num = double.NaN;
while(!double.tryParse(Console.ReadLine(), out Num) && !double.IsNaN(Num))
{
Console.Beep();
Console.WriteLine("");
Console.WriteLine("You have entered an invalid number!");
Console.WriteLine("");
}
return Num;
}
why test for IsNaN also? read this.
You MAY simply use a loop:
double PromptForNumber(string message) {
while (true) {
Console.Write(message + " ");
try {
return Convert.ToDouble(Console.ReadLine());
} catch (FormatException) {
Console.Beep();
Console.WriteLine();
Console.WriteLine("You have entered an invalid number!");
Console.WriteLine();
}
}
}
Used as:
double num1 = PromptForNumber("What is the first number?");
double num2 = PromptForNumber("What is the second number?");
BUT here you're also using exceptions where they're not necessary. Invalid user input is not exceptional and there are better ways to handle that:
double PromptForNumber(string message) {
while (true) {
Console.Write(message + " ");
double number;
if (Double.TryParse(Console.ReadLine(), out number))
return number;
Console.Beep();
Console.WriteLine("\nYou have entered an invalid number!\n");
}
}
Note that this way you'll also handle OverflowException that you left out in your original code.
Do you need 100 inputs? One line of code:
var inputs = Enumerable.Range(1, 100)
.Select(x => PromptForNumber(String.Format("Enter number #{0}:", x)));
private Double InputNum1
{
Console.Write ("What is the first number? ");
try
{
num1 = Convert.ToDouble (Console.ReadLine ());
return num1;
}
catch (System.FormatException)
{
Console.Beep ();
Console.WriteLine ("");
Console.WriteLine ("You have entered an invalid number!");
Console.WriteLine ("");
InputNum1();
}
}
you can use a while to query for numbers until they are valid:
double? num1 = null;
while (num1==null){
Console.Write ("What is the first number? ");
try {
num1 = Convert.ToDouble (Console.ReadLine ());
} catch (System.FormatException) {
Console.Beep ();
Console.WriteLine ("");
Console.WriteLine ("You have entered an invalid number!");
Console.WriteLine ("");
}
}
Hi what have I done wrong, I'm getting the error "Control cannot fall through from one case label to another" at line 15 (Switch (z))
using System;
namespace test
{
class MainClass
{
public static void Main (string[] args)
{
Console.WriteLine ("Velkommen til pCalc! Vælg hvad du skal I menuen:");
Console.WriteLine ("1. Phythagoras");
Console.WriteLine ("2. Cirklens areal og omkreds");
Console.WriteLine ("3. + - * eller /");
int z = Convert.ToInt32(Console.ReadLine());
switch (z)
{
case 1:
Console.WriteLine ("Her skal du angive 2 værdier, a og b for at beregne c");
Console.WriteLine ("Skriv a værdien: ");
double a = double.Parse (Console.ReadLine ());
Console.Clear ();
Console.WriteLine ("Skriv værdien for b: ");
double b = double.Parse (Console.ReadLine ());
Console.Clear ();
Console.WriteLine (Math.Sqrt((Math.Pow(a, 2))+(Math.Pow(b, 2))));
break;
case 2:
Console.WriteLine ("Skriv radius a cirklen: ");
double r = double.Parse (Console.ReadLine ());
double areal = (Math.Pow (r, 2) * Math.PI);
Console.Clear ();
Console.WriteLine (areal);
Console.WriteLine ("Vil du også vide omkredsen? Skriv 1 for Ja, 2 for Nej");
int q = Convert.ToInt32 (Console.ReadLine ());
switch (q) {
case 1:
Console.WriteLine (r * 2 * Math.PI);
break;
case 2:
break;
}
}
}
}
}
You have to terminate every case (even the last one!) with a break statement. Specifically in your case:
case 2:
Console.WriteLine ("Skriv radius a cirklen: ");
double r = double.Parse (Console.ReadLine ());
double areal = (Math.Pow (r, 2) * Math.PI);
Console.Clear ();
Console.WriteLine (areal);
Console.WriteLine ("Vil du også vide omkredsen? Skriv 1 for Ja, 2 for Nej");
int q = Convert.ToInt32 (Console.ReadLine ());
switch (q) {
case 1:
Console.WriteLine (r * 2 * Math.PI);
break;
case 2:
break;
}
break; // ← mandatory!
One clarification here.
Answers here show you must have a break, and that is mostly true except in one coding case. If the "break" is unreachable, then it's not required and leaving it out quiets the compiler warning.
Consider if a case "returns" either directly or through a series of conditionals.
<code>
case 1:
if (Red) { return 6;} else {return 10;}
case 2:
if (Blue) {return 4;} else {return 50;}
Both conditional conditions must return (or break, I suppose) but as long as all code streams get you out of the switch, the compiler is fine with it.
Not Homework..So I've got a simple console program to read exam scores and prints out the average and grade. So far it's the following:
public static void Main ()
{
int sum = 0;
int count = 0;
double average = 0;
Console.WriteLine ("Enter all your exam scores one by one. When finished, enter -99");
string scores = Console.ReadLine ();
while (scores != "-99") {
sum += int.Parse (scores);
count++;
scores = Console.ReadLine ();
}
if (scores == "-99") {
average = sum / count;
if (average >= 90)
Console.WriteLine ("Your average score is {0}. This is good for a letter grade of A", average);
Console.WriteLine(....more scores etc...);
Now I want to check for invalid entries with TryParse. I thought I'd stick in another while loop before the other and change the original one like this:
Console.WriteLine ("Enter all your exam scores one by one. When finished, enter -99");
string scores = Console.ReadLine ();
while (int.TryParse(scores, out numbers) == false){
Console.WriteLine("Please enter a valid integer")
scores = Console.ReadLine();
sum += int.Parse(scores);
count++;
}
while (scores != "-99" && int.TryParse(scores, out numbers) == true) {
sum += int.Parse (scores);
count++;
scores = Console.ReadLine ();
}
if (scores == "-99") {
average = sum / count;
if (average >= 90)
Console.WriteLine ("Your average score is {0}. This is good for a letter grade of A", average); ...etc...
The problem here is that if the user enters valid entries at first and then enters an invalid one, the compiler can't get back to the first while loop to check for the invalid entry. So I tried to swap the positions of the while loops. But this has the same effect; it can't get back to the first while loop to check for valid entries after an invalid one is entered. The answer is most likely simple, but I'm stuck.
The issue you are having is that you break from the first loop when the TryParse returns true, but have no recourse to re-enter the loop. Instead you should nest your loops. The loop with the sentinel should be the outer loop, and the loop that validates and re-prompts the user should be the inner loop. Here is an example:
while(scores != "-99")
{
scores = Console.ReadLine();
while((int.TryParse(scores, out numbers) == false)
{
//validation failed, re-prompt user for better number
Console.WriteLine("Bad value, try again")
scores = Console.ReadLine()
}
//do stuff here with the valid score value
}