I didn't know what else to use in this case but an if statement.
What I am trying to do is I am getting a value string direction; from a Windows form and checking if it has the value I am looking for. Then checking if the turtleDir which is a string value indicating the direction turtleDir has.
The problem comes here at else if statements, when the turtleDir is lookingleft it does all of the else if statements. What I want it to do is after it has done that else if statement it needs to stop and wait for the next command. not go through all the statements.
Can someone please advise me on how to fix it and what I am doing wrong?
Here is the code:
else if ( Program.form.direction == "right" )
{
if ( turtleDir == "left" )
{
angle = -1.6f;
turtleDir = "lookingLeft";
Program.form.direction = "";
}
else if ( turtleDir == "lookingLeft" )
{
angle = 3.15f;
turtleDir = "lookingDown";
}
else if ( turtleDir == "lookingDown" )
{
angle = 1.6f;
turtleDir = "lookingRight";
}
else if ( turtleDir == "lookingRight" )
{
angle = 0.0f;
turtleDir = "lookingUp";
}
}
You can use a switch statement on strings, too:
switch (turtleDir) {
case "left":
angle = -1.6f;
turtleDir = "lookingLeft";
Program.form.direction = "";
break;
case "lookingLeft":
angle = 3.15f;
turtleDir = "lookingDown";
break;
// other cases
}
This way, the switch block is always exited after your instructions are done. You can also specify what to do when the string matches none of these values by adding a case default: at the end. Remember each of these cases needs to be terminated by a break statement (or return/throw but i don't think you need those in this case).
If still every case is executed, your problem lies somewhere else. If a method contains this code and is called starting with e.g. turtleDir == "left", each successive call of the method will let turtleDir cycle until every case has been executed and turtleDir ends up with the final value "lookingUp". So look at your control flow and maybe keep track whether you already performed this check. Maybe keep track of the elapsed time and change turtleDir only if it has been in a particular state for a while (i don't know your requirements).
EDIT: You should set Program.form.direction = "" in every case statement. That's why your code gets executed over and over again. Also, if no direction is entered, clear it, too.
You can use an empty return;- Statement, but then you leave your method too...
Use a switch
switch (turtleDir)
{
case "left":
angle = -1.6f;
turtleDir = "lookingLeft";
Program.form.direction = "";
break;
case "lookingLeft":
angle = 3.15f;
turtleDir = "lookingDown";
break;
case "lookingDown":
angle = 1.6f;
turtleDir = "lookingRight";
break;
case "lookingRight":
angle = 0.0f;
turtleDir = "lookingUp";
break;
default:
// Optional, but place any actions if non of the above is matched
break;
}
There is something else going on here....
Only one branch of an IF/ELSE-IF statement will be executed. You might want to refactor to a SWITCH statement for readability reasons; but not because it would change your behaviour.
Look at this code:
if(0 == 0) { Console.WriteLine("Branch 1"); }
else if(true==true) { Console.WriteLine("Branch 2"); }
else if(false==false) { Console.WriteLine("Branch 3"); }
ALL of the conditions are true. And the first one executes. ONLY the first one.
In this code - only the second two are true:
if(0 == 2) { Console.WriteLine("Branch 1"); }
else if(true==true) { Console.WriteLine("Branch 2"); }
else if(false==false) { Console.WriteLine("Branch 3"); }
And ONLY the second one executes.
A series of else-if's won't all execute if the condition is true.
My guess is that you are looping through this really fast or something and the next iteration is entering the IF logic and executing the next branch. You might need to post more code so that you get more helpful answers for your particular situation.
The best way to track this down, IMHO, is to just place a breakpoint on the start of your IF logic and step-through the code one execution at a time. You should see that it only goes into one ELSE-IF branch and exits, and you can see if/why it re-enters.
Finally, the SWITCH statement doesn't allow you to implicitly execute multiple branches either.
switch(test)
{
case "one":
Console.WriteLine("Branch 1");
case "two":
Console.WriteLine("Branch 2");
}
That won't even compile. I believe in C/C++ you could fall though case statements unless you explicitly added break; or similar control statement. In C# that's not the case.
Related
I'm writing a method that I will use in another code so I'm writing it separately first.
The code returns a boolean based on the first char of the input (yes, Yes, y, yeah, No, ...). But when the input is different from Y or N it starts acting up. In eg3 It stays in the loop until The Console.Read encounters a Y or an N or there are no chars left. In the last case, it will ask again for input.
Am I using the Console.Read wrong or is there another error in my code?
Thanks in advance
EDIT: Is the solution, in the end, an efficient one?
eg1:
Yes or No?
YeahIthinkso <--my input
True
eg2:
Yes or No?
Negative <--my input
False
eg3:
Yes or No?
Idontknow <--my input
You can only answer with Yes or No
Yes or No?
You can only answer with Yes or No
Yes or No?
You can only answer with Yes or No
Yes or No?
False
The Code:
static void Main(string[] args)
{
char YN = 'x';
bool ans = false;
while (YN == 'x')
{
Console.WriteLine("Yes or No?");
YN = char.ToUpper(Convert.ToChar(Console.Read()));
switch (YN)
{
case 'Y':
ans = true;
break;
case 'N':
ans = false;
break;
default:
Console.WriteLine("You can only answer with Yes or No");
YN = 'x';
break;
}
}
Console.WriteLine(ans);
Alternate solution based on #StuartLC's answer:
bool ans = true, loop = true;
do
{
switch (Console.ReadLine().ToUpper().FirstOrDefault())
{
case 'Y':
ans = true;
loop = false;
break;
case 'N':
ans = false;
loop = false;
break;
default:
Console.WriteLine("You can only answer with Yes or No");
break;
}
} while (loop==true);
Console.WriteLine(ans);
As per #Lasse's comment - if the user types in multiple characters, you'll loop on each character in the string typed in by the user, resulting in the printing a new line of output for each character the user typed. Instead, use of ReadLine will parse the input as a single string, and then the Linq extension FirstOrDefault() will safely obtain the first char in the string:
YN = char.ToUpper(Console.ReadLine().FirstOrDefault());
As an aside, instead of starting a while loop with a forced false condition, C# also supports a do-while loop syntax which fits your requirement better, i.e. at least one iteration through the loop, with a check at the end of the loop:
do
{
Console.WriteLine("Yes or No?");
YN = char.ToUpper(Console.ReadLine().FirstOrDefault());
switch (YN)
{
case 'Y':
ans = true;
break;
case 'N':
ans = false;
break;
default:
Console.WriteLine("You can only answer with Yes or No");
YN = 'x';
break;
}
}
while (YN == 'x');
Re OP's follow up question
Can I now remove the 'YN' completely and put a switch (Console.ReadLine().FirstOrDefault().ToUpper()) in the beginning and a while (ans == true || ans ==false) in the end?
Not quite - since ans is a boolean, it can only have two states (true or false), and you need to model at least 3 states (true, false, and invalid). Although you could use a nullable boolean (bool?) to model the 3 states (where null = invalid), I personally dislike using null to indicate something isn't known, as this invariably leads to the NullReferenceException abyss, and C# hasn't (yet) opted for the "Option" type / Monad (like Java's Optional).
If you're OK with C#8 pattern matching and tuples, you could possibly make the code a bit more concise and refactored as follows, by splitting out the concerns of 'is the input valid' and 'what is the valid input value'?. You could also refactor the switch expression into it's own method to split out the concerns of 'UI' from the parsing logic, which is always a good idea.
static void Main(string[] args)
{
bool ans;
bool isValid;
do
{
Console.WriteLine("Yes or No?");
(ans, isValid) = ParseInput(Console.ReadLine());
if (!isValid)
{
Console.WriteLine("You can only answer with Yes or No");
}
}
while (!isValid);
Console.WriteLine(ans);
(bool ans, bool isValid) ParseInput(string input) =>
char.ToUpper(input.FirstOrDefault()) switch
{
'Y' => (true, true),
'N' => (false, true),
_ => (default, false)
};
}
I have a method which has result at the end,I would want to detect if number is not 0 and if it's -4.
0 Means good
-4 Means something that can be solve
And anything else is bad.
Like
if ( Result != 0)
{
MessageBox.Show("It's bad!")
}
else if ( Result == -4)
{
Thread.Sleep(20000);
MyMethod.TryAgain();
}
else
{
MessageBox.Show("It's good");
}
My problem is that -4 is not 0,so if i get result -4 it takes my Result != 0 method. How can I solve it? Thank you in advance.
Use switch and case.
switch (Result) {
case 0:
MessageBox.Show("It's good");
break;
case -4:
Thread.Sleep(20000);
MyMethod.TryAgain();
break;
default:
MessageBox.Show("It's bad!");
break;
}
Microsoft documentation: https://msdn.microsoft.com/en-us/library/06tc147t(v=vs.110).aspx
Just reorder your if-structure to the following:
if ( Result == 0)
{
MessageBox.Show("It's good")
}
else if ( Result == -4)
{
Thread.Sleep(20000);
MyMethod.TryAgain();
}
else
{
MessageBox.Show("It's bad");
}
So your initial problem, that the Result != 0 case is evaluated first, is gone.
Simply change order of branches
if (Result == -4) \\ solve
else if (Result != 0) \\ bad
else \\ good
When you are building a chain of non-exclusive conditions, start with the strongest one (i.e. the most specific condition). Otherwise the code for the weaker condition will execute, blocking access to more specific ones.
In your case, Result == -4 implies that Result != 0, meaning that the first condition is more specific than the second one. Hence you should check Result == -4 before Result != 0. Otherwise, Result == -4 would never be reached.
C# offers multiple ways of implementing this logic. As long as you follow a general rule of ordering your conditionals from most specific to least specific, picking a particular implementation is up to you.
Sorry, wrong code. See comment below.
switch(Result) {
case 0:
MessageBox.Show("It's bad!");
break;
case -4:
Thread.Sleep(20000);
MyMethod.TryAgain();
break;
default:
MessageBox.Show("It's good");
break;
}
if (((turn % 2) != 0) && (vsComputer))
{
int generateAI = generateRandomAI(AI);
switch (generateAI)
{
case 0:
computerMedio();
break;
case 1:
computerDifficile();
break;
}
}
I want my 0/1 value to be the same for all the game.
With the code I wrote, on every move it selects a different AI mode.
It shouldn't be that hard to achieve, but I can't find a solution.
Thanks everyone!
Your issue is:
int generateAI = generateRandomAI(AI);
You are generating a new random value on every invocation of this code block. If you wish to keep the same value for all execution, just generate the value once and keep it in scope.
Ok I solved in the following way
public Boolean difficult;
in the newGame() method I generate the number which lasts for all the game.
then,
switch (generateAI)
{
case 0:
difficult = false;
break;
case 1:
difficult = true;
break;
}
into the game:
if (((turn % 2) != 0) && (vsComputer))
{
if (difficult)
{
computerDifficile();
}
else
{
computerMedio();
}
}
Is there a way in .NET to replace a code where intervals are compared like
if (compare < 10)
{
// Do one thing
}
else if (10 <= compare && compare < 20)
{
// Do another thing
}
else if (20 <= compare && compare < 30)
{
// Do yet another thing
}
else
{
// Do nothing
}
by something more elegant like a switch statement (I think in Javascript "case (<10)" works, but in c#)? Does anyone else find this code is ugly as well?
One simplification: since these are all else-if instead of just if, you don't need to check the negation of the previous conditions. I.e., this is equivalent to your code:
if (compare < 10)
{
// Do one thing
}
else if (compare < 20)
{
// Do another thing
}
else if (compare < 30)
{
// Do yet another thing
}
else
{
// Do nothing
}
Since you've already affirmed that compare >= 10 after the first if, you really don't need the lower bound test on the second (or any of the other) ifs...
It's not pretty, but switch was originally implemented by hashing in C, so that it was actually faster than an if...else if chain. Such an implementation doesn't translate well to general ranges, and that's also why only constant cases were allowed.
However, for the example you give you could actually do something like:
switch(compare/10) {
case 0:
// Do one thing
break;
case 1:
// Do another thing
break;
case 2:
// Do yet another thing
break;
default;
// Do nothing
break;
}
How do you break out of a foreach loop while within a switch block?
Normally, you use break but if you use a break within a switch block it will just get you out of a switch block and the foreach loop will continue execution:
foreach (var v in myCollection)
{
switch (v.id)
{
case 1:
if (true)
{
break;
}
break;
case 2;
break
}
}
What I'm currently doing when I need to break out of the foreach while within the switch block is setting a bool value placed outside of the loop to true and checking the value of this bool every time the foreach is entered and before entering the switch block. Something like this:
bool exitLoop;
foreach (var v in myCollection)
{
if (exitLoop) break;
switch (v.id)
{
case 1:
if (true)
{
exitLoop = true;
break;
}
break;
case 2;
break
}
}
This works but I keep thinking there must be a better way of doing this I am unaware of...
EDIT: Wonder why this was not implemented in .NET the really neat way it works in PHP as mentioned by #jon_darkstar?
$i = 0;
while (++$i) {
switch ($i) {
case 5:
echo "At 5<br />\n";
break 1; /* Exit only the switch. */
case 10:
echo "At 10; quitting<br />\n";
break 2; /* Exit the switch and the while. */
default:
break;
}
}
Your solution is pretty much the most common option in this case. That being said, I'd put your exit check at the end:
bool exitLoop;
foreach (var v in myCollection)
{
switch (v.id)
{
case 1:
if (true)
{
exitLoop = true;
}
break;
case 2;
break
}
// This saves an iteration of the foreach...
if (exitLoop) break;
}
The other main option is to refactor your code, and pull the switch statement and foreach loop out into a separate method. You could then just return from inside the switch statement.
The boolean is one way. Another is using labels and goto. I know folks consider goto to be a cardinal sin, but used judiciously (VERY judiciously), it can be useful. In this case, place a label just past the end of the foreach loop. When you want to exit the loop, simply goto that label. For example:
foreach(var v in myCollection) {
switch(v.Id) {
case 1:
if(true) {
goto end_foreach;
}
break;
case 2:
break;
}
}
end_foreach:
// ... code after the loop
EDIT: some people have mentioned taking the loop out into a separate method so that you can use return. I see the benefit of this as it doesn't require goto and it also simplifies the original function that contained the loop. However, if the loop is simple and is the primary purpose of the function that contains it, or if the loop makes use of out or ref variables, then it's probably best to just leave it in place and use the goto. In fact, because the goto and the label stand out, it probably makes the code clearer rather than clunkier. Putting it in a separate function could make simple code harder to read.
You could extract your foreach cycle to the separate method and use return statement. Or you could do like this:
foreach (object collectionElement in myCollection)
{
if (ProcessElementAndDetermineIfStop(collectionElement))
{
break;
}
}
private bool ProcessElementAndDetermineIfStop(object collectionElement)
{
switch (v.id)
{
case 1:
return true; // break cycle.
case 2;
return false; // do not break cycle.
}
}
Honestly? This is perhaps the only situation where it is completely valid and proper to use goto:
foreach (var v in myCollection) {
switch (v.id) {
case 1:
if (true)
// document why we're using goto
goto finished;
break;
case 2;
break
}
}
finished: // document why I'm here
It's not really different from your exitLoop flag, but it might be more readable if you extract a method...
foreach (var v in myCollection)
{
if(!DoStuffAndContinue(v))
break;
}
bool DoStuffAndContinue(MyType v)
{
switch (v.id)
{
case 1:
if (ShouldBreakOutOfLoop(v))
{
return false;
}
break;
case 2;
break;
}
return true;
}
There's always the option of restructuring your code so that you can return from the switch statement.
Based on MSDN documentation on the break statement, it only allows to stop the top-most scope.
This case is one where you could use a goto statement to leave your foreach loop.
If you don't want to use a goto statement, your solution seems to be the best one.
As a side note, you could improve your code by testing the exitLoop flag at the end of the iteration, saving the cost of one enumerator call.
Some languages (i know PHP is one, not sure about others) allow you to specify how many control structures you'd like to break out of with
break n;
where 1 is implied if you just do break
break 2 would do what you describe, were it available in C#. I don't believe that's the case so your exit flag is probably the best solution.
Lame, I know, but that's all you can do about it.
You could always transform it into a while loop and add 'exitLoop' as a condition which must be met. Inside the switch, you can call continue to skip the rest of the current pass and since you would have set exitLoop to false, it'd exit much like break would do. Even though it's not exactly what you're asking, perhaps it's more elegant that way?
Another way to do that is using goto, but extracting to a method would be preferable
int[] numbers = { 1, 2, 3, 4, 5 };
foreach (var number in numbers)
{
switch (number)
{
case 1:
break;
case 2:
goto breakLoop;
default:
break;
}
}
breakLoop:
Console.Write("Out of loop");
You can do it with Try/Catch..
But it might not be the best idea in the world, because it causes performance problems and does show nasty lines in the debug window.
try
{
foreach (var v in myCollection)
{
switch (v.id)
{
case 1:
if (true)
{
throw new SystemException("Break");
}
break;
case 2;
break;
}
}
} catch {}
Transform the switch() statement into a "if() else if() [...] else" series of statements so that the break exits from the foreach() loop.