stop iterating after returning a true? - c#

(couldn't think of a better title, feel free to edit it to a title that describes the question better)
I have the following method:
bool CalculateNewState(int adjacent, bool currentState)
{
if (currentState == true)
{
foreach (int n in liveRule)
{
if (adjacent == n)
{
return true;
}
}
return false;
}
else
{
foreach (int n in becomeAliveRule)
{
if (adjacent == n)
{
return true;
}
}
return false;
}
}
This is for a game of life clone. What I want to implement is that a user can make his own rules.
The bool currentState tells the method whether the cell is alive or not. the int adjacent tells the method how many alive neighbors the cell has.
What I want to achieve with this is that when the user says:
2,3 and 5 neighbors keep the cell alive. That it will iterate through an array (liveRule) that holds 2,3 and 5. when any match occurs it should return true, else false.
What happens here is that, after returning a true, it keeps iterating and will eventually return whether the last element in liveRule matched.
What do I need to do, to stop iterating after a match has occurred?
It is of course possible I'm taking the wrong approach to this problem. I started from the suggestions here.
(tried to describe it to the best of my abilities, but it still seems quite unclear)
This is C# in Unity3D.

The code you've implemented says "if adjacent is unequal to any of 2, 3 or 5, then return". Obviously adjacent cannot be equal to all of them!
Start over. Rename your methods so that they are more clear. Booleans should answer a true/false question, so choose names that ask a question:
bool IsCellAlive(int adjacentCount, bool isAlive)
{
if (isAlive)
return liveRule.Contains(adjacentCount);
else
return deadRule.Contains(adjacentCount);
}
"Contains" is slower than a foreach loop, so this might cause a performance problem. Don't worry about it for now; you haven't even got the code correct yet. Write the code so that it is obviously correct, and then use a profiler to find the slow spot if it is not fast enough.
Remember: make it correct, then make it clear, then make it fast.

Your return statements will exit the CalculateNewState method immediately. If you find that the iteration is continuing, either you are not hitting the return statements (adjacent == n is never true), or possibly CalculateNewState is being called repeatedly from elsewhere in your code.
You can probably rewrite it much more simply to something like:
if (currentState)
return liveRule.Contains(adjacent);
return becomeAliveRule.Contains(adjacent);

Well you can always use a "break" statement to terminate the loop. Do something like:
bool CalculateNewState(int adjacent, bool currentState)
{
if(currentState)
{
return IsStateMatch(adjacent, liveRule);
}
else
{
return IsStateMatch(adjacent, becomeAliveRule);
}
}
bool IsStateMatch(int adjacent, int[] rules)
{
bool finalState = false;
if(rules != null)
{
for(int i = 0; i < rules.length; i++)
{
if(adjacent == rules[i])
{
finalState = true;
break;
}
}
}
return finalState;
}
I broke down the methods a little more, just for readability, but I think this is the basic idea. Now, I do agree with the other posters about what could be happening. If your loop is continuing after a break / return statement, then you most likely have buggy code elsewhere incorrectly calling the method.

It looks like your equality test is the culprit... shouldn't you be testing adjacent == n instead of adjacent != n? That way it will return true for the matches and only return false if no match.
The iterator will NOT continue after a return exits the loop.

Can you use a for loop instead of foreach with an additional variable?
bool CalculateNewState(int adjacent, bool currentState)
{
if (currentState == true)
{
bool match = false;
for(int n = 0; n < liveRule.length && !match; n++)
{
if (adjacent != n)
{
match = true;
}
}
return match;
}
else
{
bool match = false;
for(int n = 0; n < becomeAliveRule.length && !match; n++)
{
if (adjacent != n)
{
match = true;
}
}
return match;
}
}

Related

chain up multiple IFs - evaluate next only if current is false

I have a method that checks multiple conditions to execute further, only to proceed to next if the current condition evaluates to false, otherwise the method will exit without evaluating further conditions. And the number of conditions vary in different implementations (subclasses).
I'm limited by my creativity to make it look any better than using the dreaded goto statement. Is there any better way to do the following:
public bool DoSomething()
{
bool result = true;
if (exclusion1)
{
result = false; goto Exit_Now;
}
if (exclusion2)
{
result = false; goto Exit_Now;
}
if (exclusion3)
{
result = false; goto Exit_Now;
}
if (exclusion4)
{
result = false; goto Exit_Now;
}
if (exclusion5)
{
result = false; goto Exit_Now;
}
if (result)
{
//do something
}
Exit_Now:
return result;
}
EDIT: In response to the answers, I understand using "else if" and conditional OR '||' operator are the obvious choices:
Subquery: which is more performant? I ask because this happens inside a loop and each evaluation takes about 30-40 ms. What is supposed to be finished in under a minute is taking up to two minutes without the goto statements in the code given above. Hence, the query. Thanks for all the help.
If you can fit your exclusion tests into the if statement, just use else if statements;
if (exclusion1)
{
result = false;
}
else if (exclusion2)
// etc ...
else if (result)
{
//do something
}
But I find it's much simpler, and easier to read, to just return early;
if (exclusion1)
return false;
One way to simplify this is to treat the exclusions as a guard clause:
public bool DoSomething()
{
if (exclusion1 ||
exclusion2 ||
exclusion3 ||
exclusion4 ||
exclusion5)
{
return false;
}
//do something
return true;
}
This also has the benefit of removing the nesting of the //do something towards the end.
you can always do this:
result = !(exclusion || exclustion2 ...|| exclusionN);

not all code paths return a value but in any case there is value return

I just learned Method Declaring and i don't know too much how to use it, i tried to make an algorithm that takes 2 numbers and return their smallest common divide, and if there is no common divider, return -1, thats the code:
class Program
{
static int Div(int a, int b)
{
int max = Math.Max(a, b);
bool div = false;
for(int i = 2; i <= max / 2; i++)
{
if (a % i == 0 && b % i == 0)
{
return i;
div = true;
i = max;
}
}
if (div == false)
{
return -1;
}
}
static void Main(string[] args)
{
Console.WriteLine("Please Enter 2 Numbers");
int num = int.Parse(Console.ReadLine());
int num2 = int.Parse(Console.ReadLine());
Console.WriteLine(Div(num, num2));
}
}
it tells me that there is an unreachable code, and not all code paths return a value, but why? if i get 2 numbers that does have a commong divider it will return it, and if not it will return -1, no execptions I think, thanks in advance
The compiler is not clever enough. But the last if is redundant anyway because it's always false there, so you can write following which also avoids the compiler error:
static int Div(int a, int b)
{
int max = Math.Max(a, b);
for (int i = 2; i <= max / 2; i++)
{
if (a % i == 0 && b % i == 0)
{
return i;
}
}
return -1;
}
The part after the return in the loop was unreachable and unnecessary, so i've removed it.
When you use return you exit the function immediately, no code beyond that line will execute therefore the lines after aren't reachable.
return i;
div = true; <<
i = max; <<
In your case, seems like you just want to set those values before you return.
if (a % i == 0 && b % i == 0)
{
return i;
div = true;
i = max;
}
The 2 lines after the return are never reached. Put them before the return. Also I don't think you need a div bool at all. It's redundant and can be optimized away.
Proving whether an arbitrary method can reach the end of the method without hitting a return or throwing an exception is provably an unsolvable problem. You can always construct a method such that the compiler would be unable to prove whether or not the endpoint is reachable, if you try hard enough. However, it's important for the compiler to not allow any programs that have a return value but no reachable endpoint.
As a consequence of this, there are false positives. The compiler does it's best to determine if a program has a reachable endpoint, and if it fails to prove it, it will error, even if you and I both know that the endpoint isn't actually reachable.
You'll need to change your code such that the compiler is able to prove that the endpoint isn't reachable, and the easiest way to do that is to remove the if (div == false) line and just always return -1;. You and I know that div will never be true there, but the compiler isn't sophisticated enough to prove it.
The return in the first if clause in the for loop is before the rest of the code, so there are 2 lines of code that will never get hit, these 2:
div = true;
i = max;
The reason they'll never get hit is because if the if statement is true, it'll immediately return, and if it's false it'll go to the second if.
2 reasons : The line div=true is unreachable, the code after return is not executed. Replace
return i;
div = true;
i = max;
by
int res=i;
div = true;
i = max;
return res;
And the last 'if' clause has no 'else' clause allowing to return in all cases;

Counting a string to ensure the input is within a min/max boundary

For a part of my project, I want to enforce the rule that the user input can only be within a min/max word boundary. With a minimum of 1 word, and a maximum of 50 words. The boolean isn't changing from the default set value of false. Here is my code:
bool WordCount_Bool = false;
//Goto the method that handles the calculation of whether the users input is within the boundary.
WordCount_EH(WordCount_Bool);
//Decide whether to continue with the program depending on the users input.
if (WordCount_Bool == true)
{
/*TEMP*/MessageBox.Show("Valid input");/*TEMP*/
/*Split(split_text);*/
}
else
{
MessageBox.Show("Please keep witin the Min-Max word count margin.", "Error - Outside Word Limit boundary");
}
Method handling the array and the change of the boolean:
private bool WordCount_EH(bool WordCount_Bool)
{
string[] TEMPWordCount_Array = input_box.Text.Split(' ');
int j = 0;
int wordcount = 0;
for (int i = 100; i <=0; i--)
{
if (string.IsNullOrEmpty(TEMPWordCount_Array[j]))
{
//do nothing
}
else
{
wordcount++;
}
j++;
}
if (wordcount >= 1)
{
WordCount_Bool = true;
}
if (wordcount < 1)
{
WordCount_Bool = false;
}
return WordCount_Bool;
}
Thank you all in advance.
Side note: I realize that the for loop will throw an exception or at least is not optimal for its purpose so any advice will be much appreciated.
Extra Side note: Sorry I should have said that the reason i haven't used length is that wherever possible I should do my own code instead of using built-in functions.
The short answer is you should just return a true or false value from your WordCount_EH method like others have said
But just to clear up why it doesn't work. C# by default passes arguments by value. With Value types such as Boolean the actual value of true or false is stored in the variable. So when you pass your Boolean value into your method all you are doing is saying please put this bool value into my new variable (the method parameter). When you make changes to that new variable it only changes that variable. It has no relation to the variable that it was copied from. This is why you don't see a change in original bool variable. You may have named the variables the same but they are infact two different variables.
Jon Skeet explains it fantastically here http://jonskeet.uk/csharp/parameters.html
Here you go this should solve it:
if(input_box.Text.Split(' ').Length>50)
return false;
else
return true;
You need to pass WordCount_Bool by ref if you want to change it in WordCount_EH:
private bool WordCount_EH(ref bool WordCount_Bool) { ... }
bool WordCount_Bool = false;
WordCount_EH(ref WordCount_Bool);
although in this case you might as well use the return value:
bool WordCount_Bool = false;
WordCount_Bool = WordCount_EH(WordCount_Bool);
If you want to pass argument by reference, you need to do as per #Lee suggestion.
For your logic implementation, you can use following code to avoid array indexing.
// It would return true if you word count is greater than 0 and less or equal to 50
private bool WordCount_EH()
{
var splittedWords = input_box.Text.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();
return (splittedWords.Count > 0 && splittedWords.Count <= 50);
}

Why do these errors appear? c# - hangman game

I'm fairly new to coding (especially c#) - this is an assignment for a programming fundamentals class - I'm not looking for the answer - I'm looking for someone to explain why I get these two 'error's for a boolean method I'm supposed to create to check if the user's guess for a letter or the full word in a game of hangman.
The errors I get are - 'Unreachable Code detected - for the idx++ part - which doesn't make sense as I've used it in other separate methods..
And Program.CheckGuess(char[], char[], char[], string: not all code paths return a value.
I know I'm not fully finished the aspect. It's probably staring at me in the face - just looking for some guidance. Thanks.
static bool CheckGuess(char[] secrets, char[] mask, char[] letters, string guess)
{
int misses = 0; bool condition = false;
for (int idx = 0; idx < secret.Length; idx++)
{
guess.ToCharArray();
if (mask[idx] == guess[idx])
{
//reveal character or word
condition = true;
}
else
{
misses = misses + 1;
condition = false;
}
return condition;
}
}
You should understand that a return statement, when executed, makes the control jump out of the method and back to the caller.
In your code, your return is statement is placed inside the for loop. When an iteration of the for loop is executed, the control jumps out of the method immediately and goes back to the caller of the method.
As you know, the last part in a for loop header (idx++) is executed when an iteration has finished executing. However, in your case, an iteration will never finish because it just jumps back to the caller when control reaches return. This is why the first error occurred.
You should also understand that every method which doesn't have void as the return type needs to return no matter what.
So what if the for loop's condition (the middle part) is never true? The for loop will never be executed, right? If the for loop isn't executed, then what should the method return?
The error says that not all code path returns a value because the method would not return if the for loop isn't executed.
To fix this, you just need to move the return statement out of the for loop:
static bool CheckGuess(char[] secrets, char[] mask, char[] letters, string guess)
{
int misses = 0; bool condition = false;
for (int idx = 0; idx < secret.Length; idx++)
{
guess.ToCharArray();
if (mask[idx] == guess[idx])
{
//reveal character or word
condition = true;
}
else
{
misses = misses + 1;
condition = false;
}
}
return condition;
}
Because you have a return statement.
When this return inside your for loop is reached, the program jumps out of the loop and thus makes you i++ unreachable.

Undesired conditions hit when checking for list equality

Currently facing a rather.. trivial issue.
I have two error-handling conditions:
1. Triggers true if two lists are inequal.
For example:
2. Triggers true if the cachedList.Length is > than the newList.Length.
For example:
First method to check string equality is this:
if (!checkEquality(cachedList, newList))
{
// do something
}
Where checkEquality() is:
public bool checkEquality(List<string> cachedList, List<string> newList)
{
if (cachedList.SequenceEqual(newList))
{
return true;
}
else {
return false;
}
}
The second method I use is:
if (cachedList.Count > newList.Count)
{
// Do something
}
With this said, and understandingly, when a scenario where condition no. 2 is hit, where the cached list is greater than the new list, both my conditions get hit. Both the "inequal" and "greater than" condition is hit, and it's causing undesired behavior in my code.
In order to not satisfy both these conditions when error-handling number 2 is hit, I need to think of an alternative to detect "inequality" in method number 1.
EDIT: I decided to put in a condition to check if the counts of newList and cachedList are equal, and only check for their equality given their count is equal. Is this the right way to approach this?
public bool checkEquality(List<string> oldFirstList, List<string> newFirstList)
{
if (oldFirstList.Count == newFirstList.Count)
{
if (oldFirstList.SequenceEqual(newFirstList))
{
return true;
}
else
{
return false;
}
}
return true;
}
The second problem it´s right the cachedList.Count > newList.Count, and that´s the reason why the if is true.
if (cachedList.Count > newList.Count)
{
// Do something
}
This will "do something" because it´s true the condition
And your first problem, try something like this:
Instead of this:
if (!checkEquality(cachedList, newList))
{
// do something
}
Try this directly:
if (cachedList.SequenceEqual(newList))
{
return true;
}
else
{
return false;
}
This will return false;
According to the documentation for SequenceEqual, the length check is already being done there. Unless you have no other criteria other than length and equality, there is no need to wrap SequenceEqual into your own method. You can even define a type of IEqualityComparer<T> if you want to compare more than references.

Categories