While loop crashing Unity, but is not infinite - c#

I'm aware (from similar posts) that infinite while loops are notorious for causing Unity3d to crash. I'm tring to impliment a while loop within something I'm working on, which I'm fairly sure isn't 'infinite', yet causes the game to crash.
The idea of the logic is to check a list of integers for consecutive numbers and use that as the basis to apply a bonus. The list contains 'effective shots', and has a new int added every time a shot is fired - the more consecutive effective shots, the higher the bonus.
Here's what I have:
int count = 0;
int firstItem = 0;
int multiples = 3;
int currentMultiple = 0;
int bonusX = 0;
foreach (int i in effectiveShots)
{
if (count == 0)
{
firstItem = i;
count = 1;
}
else if (i == firstItem + count)
{
count++;
}
}
while (count >= multiples)
{
currentMultiple = multiples;
if (count == currentMultiple + multiples)
{
bonusX += 1;
}
if (bonusX > 10 || gameOver)
break;
UnityEngine.Debug.Log(bonusX);
}
The logic to check for consective entries in the effectiveShots list was taken from #Jon Skeet's answer here. Though this appears to work, I think that this may be the issue. As soon as a shot is missed, count needs to be reset. Any ideas or suggestions?
The while loop should then be entered once the count of consecutive effective shots has reached the first multiple, i.e. 3 shots. Then, for every set of consequtive effective shots thereafter, increment the bonus, for example:
3 shots: bonusX = 1
6 shots: bonusX = 2
9 shots: bonusX = 3
12 shots: bonusX = 4
and repeat this until `count` is no longer >= 3, i.e. the player missed a shot.
The issue is that as soon as I hit 3 consequtive shots and enter this loop, the game crashes. I dont think I would call this an infinite loop, since missing a shot - setting count == 0 - would mean the while conditions are no longer true, so drop out of the loop (I think?). I also added an additional check to break out of the loop under certain circumstances, but this doesnt make a difference.
If you are able to give a steer as to how to fix this crashing, or have a suggestion on a better approach in general, it would be appreciated!

Nothing in your while loop changes the value of either count or multiples and so the condition will always evaluate to the same value => Infinite loop

Related

Unity for loop try to access a destroyed GameObject

I'm working on a brickout game clone, so I'm trying to add a multiply the ball feature to the game. This Video shows the feature.
Here is my code:
//access to all active balls
Ball[] balls = FindObjectsOfType<Ball>();
//loop for the length of the balls
for (int i = 0; i <= balls.Length; i++)
{
if (balls.Length >= 1000)
{
return;
}
else
{
// here I'm trying to fix the issue by checking if the ball exists, so I will call the function if not. return. but console show me same message
if (balls[i] != null)
{
balls[i].CallM3x();
i++;
}
}
}
The unity console message is:
IndexOutOfRangeException: Index was outside the bounds of the array.
My code above is working fine, but the issue is some balls destroy before the for loop end its work by less than a second .
Any idea how to avoid this?
There are two fundamental issues with your loop:
you're looping up to i <= balls.Length which will always throw an error (there is no a[10] in an array of length 10).
you're incrementing i again within the loop, which will skip items
Change the loop condition to i < balls.Length and remove the i++ within the loop.
Also, you don't need to check if (balls.Length >= 1000) within the loop every time - you can check that before the loop (but what's the problem with a collection with more than 10,000 items?)
the issue is some balls destroy before the for loop end its work by less than a second
I don't see how this can be a problem. You're creating an array of references that you're looping over. Even if items are destroyed within the game, the object references still exist within your array. There may be some other flag to tell you that an object is destroyed (I am not a Unity expert), but they would not change to null inside your array.
A simple way to avoid the issue of re-referencing objects you have deleted in a loop is by counting i down from balls.Length to 0 instead of up from 0 to balls.Length.
for (int i = balls.Length - 1; i >= 0; i--)
Also, you might want to look again at your for-loop: you are going up to <= balls.Length, allowing the highest index to be = balls.Length. That index is out of bounds though, because we start counting at 0. I suggest using < instead of <= here.
Ball[] balls = FindObjectsOfType<Ball>();
for (int i = 0; i < balls.Length; i++)
{
if (balls.Length >= 1000)
{
return;
}
else
{
if (balls[i] != null)
{
balls[i].CallM3x();
// i++; <- This is your problem. Remove it.
}
}
}

C# Add int numbers to a list while running a loop

I have tried to get the point across in the title as best as I can but basically what I want to do is add certain items to List while running a loop so I don't have to manually put them into an if statement. Let me please show an example so that I can explain properly.
Example :-
What I need is :- the first number would be 500 and that would be in index 0, then i want a loop to add 150 to the last number generated so that the int list would look like this,
index 0 = 500
index 1 = 650
index 2 = 800
index 3 = 950
Do this repeatedly until say the last number will read 2,000,000
Now I believe that this would be simple to run a loop and base it on conditions but I can only seem to figure out to run a loop that will increment the value in 1.
Hope I have explained well enough
Regards,
M
Now I believe that this would be simple to run a loop and base it on
conditions but I can only seem to figure out to run a loop that will
increment the value in 1.
This is not true, you can adjust the increment of the iterator as you wish.
var numbers = new List<int>();
for(int i=500; i<=2000000; i+=150)
{
numbers.Add(i);
}
For further information on this, please have a look here.
Just another implementation:
var result = new List<int>();
var number = 500;
do
{
result.Add(number);
number+= 150;
} while (number <= 2000000);

Computing the most frequent element

I have recently come across this line of code and what it does is that it goes through an array and returns the value that is seen most often. For example 1,1,2,1,3 so it will return 1 because it appears more than 2 and 3. What I am trying to do is understand how it works so what I did was I went through it with visual studio step by step but it is not ringing any bells.
Can anyone help me understand what is going on here? It would be a total plus if someone can tell me what does c do and what is the logic behind the arguments in the if statements.
int[] arr = a;
int c = 1, maxcount = 1, maxvalue = 0;
int result = 0;
for (int i = 0; i < arr.Length; i++)
{
maxvalue = arr[i];
for (int j = 0; j <arr.Length; j++)
{
if (maxvalue == arr[j] && j != i)
{
c++;
if (c > maxcount)
{
maxcount = c;
result = arr[i];
}
}
else
{
c=1;
}
}
}
return result;
EDIT: On closer examination, the code snippet has a nested loop and is conventionally counting the maximum seen element by simply keeping track of the maximum seen times and the element that was seen and keeping them in sync.
That looks like an implementation of the Boyer-Moore majority vote counting algorithm. They have a nice illustration here.
The logic is simple, and is to compute the majority in a single pass, taking O(n) time. Note that majority here means that more than 50% of the array must be filled with that element. If there is no majority element, you get an "incorrect" result.
Verifying if the element is actually forming a majority is done in a separate pass usually.
It is not computing the most frequent element - what it is computing is the longest run of elements.
Also, it is not doing it very efficiently, the inner loop only needs to compute upto i-1, not upto arr.Length.
c is keeping track of the current run length. The first "if" is to check if this is a "continouous run". The second "if" (after reaching the last element in the run) will check if this run is longer than any run you have seen so far.
In the above input sample, you are getting 1 as answer because it is the longest run. Try with an input where the element with the longest run is not the same as the most frequent element. (e.g., 2,1,1,1,3,2,3,2,3,2,3,2 - here 2 is the most frequent element, but 1,1,1 is the longest run).

While Looping an Array

I'm trying to understand a book from Don Gosselin on ASP.NET Programming with Visual C#. To solve it I just simply make it to work by adhering to while loops: one while loop is to assign a number to an array element, the other while loop is to display that array. Total array count displays 1 through 100. This should have worked but didn't. Visual Studio 2013 debugger for some reason assigns count = 100, that's why it's failing.
<%
int count = 0;
int[] numbers = new int[100];
while (count <= 100)
{
numbers[count] = count;
++count;
}
while (count <= 100)
{
Response.Write(numbers[count] + "<br />");
++count;
}
%>
You should set count to 0 after first while loop:
int count = 0;
int[] numbers = new int[100];
while (count <= 100)
{
numbers[count] = count;
++count;
}
count = 0;
while (count <= 100)
{
Response.Write(numbers[count] + "<br />");
++count;
}
You need to reset the count to 0 before you attempt the next while statement. Currently, the first loop ends when it reaches a count equal to 101. WHen you proceed to the next while, the count is 101 so the loop automatically ends. Just set count = 0; before the second while loop.
This seems like a very convoluted and unrealistic way of using while loops and arrays. In order to understand it better, it may be worth thinking about it per step.
var i = 0;
while (i < 100)
{
Response.Write(++i + "<br />");
}
The first important distinction is between i++ and ++i. The former utilises the value, and then increments by one; the latter, increments the number and then utilises the value.
In C#, you should really be working with Collections, rather than Arrays. Arrays are zero-indexed, and are renowned for causing serious errors, including exposing potential exploits. Being statically allocated, there is no failsafe when attempting to access indicies outside of the bounds of the Array. Collections, on the other hand, are (for the most part) one-indexed, dynamically allocated, and provide fallbacks when accessing indicies. The most commonly used Collection is a List.
var i = 1;
var list = new List<int>();
while (i <= 100)
{
list.Add(i++);
}
For the second while loop, it's not really suitable to use a while loop here, for any practical example. The excercise is forcing while loops where they are not needed. In this instance, the aim is to iterate through each element in the array (List) and dump its contents to the screen. Because we want to perform an action for each element, a while loop may cause issues. If the array has less than 100 elements, the program will crash, if the array has more than 100 elements, we'll miss some of them. By using a foreach loop, instead of a while, we can eliminate these potential errors.
foreach (var num in list)
{
Response.Write(num + "<br />");
}
Now, I realise that the excercise is about while loops, however, it is teaching you to use them in the wrong way. A much better way - and how you'll most often use them - is to perform an action until a particular condition is met, rather than for simple iteration. By this, I mean, a condition is set to false, then inside the while loop, we manipulate a variable, test the condition, and if it's still false, we go round again. The most common example of this is to work out factorials of numbers.
var num = 5;
var factorial = 1;
while (counter > 1)
{
factorial *= num--;
}
Response.Write(String.Format("{0}! = {1}", input, factorial));
The other main way in which while loops are used is to force an infinite loop, unless a break condition is met. I'll show a very arbitrary use of this here, but a real world example would be the loop() method in Arduino C coding, or a HTTP Listener that constantly repeats the same procedures, until stopped.
var stop = 13;
Response.Write("Pick a number between 1 and 100...<br /><br />");
while (true)
{
var num = new Random().Next(1, 101);
Response.Write(num + " ..... ");
if (num == stop) break;
Response.Write("You got lucky!<br />");
}
Response.Write("Unlucky for you!);
The best way to learn these things is to practice them. Pick a task and find out just how many ways there are to complete it. There is one last important distinction to mention though. a while loop tests the condition at the beginning of the loop. A do while loop, tests the condition at the end.
while(false)
{
// This code will never be run.
}
Compared to:
do
{
// This code will be run once only.
}
while(false)
As a final thought, here's how I'd write the original code (using a LINQ foreach loop):
var numbers = new List<int>();
for (var count = 1; count <= 100; count++)
{
numbers.Add(count);
}
numbers.ForEach(num => Response.Write(num + "<br />")));

C# loop - break vs. continue

In a C# (feel free to answer for other languages) loop, what's the difference between break and continue as a means to leave the structure of the loop, and go to the next iteration?
Example:
foreach (DataRow row in myTable.Rows)
{
if (someConditionEvalsToTrue)
{
break; //what's the difference between this and continue ?
//continue;
}
}
break will exit the loop completely, continue will just skip the current iteration.
For example:
for (int i = 0; i < 10; i++) {
if (i == 0) {
break;
}
DoSomeThingWith(i);
}
The break will cause the loop to exit on the first iteration - DoSomeThingWith will never be executed. This here:
for (int i = 0; i < 10; i++) {
if(i == 0) {
continue;
}
DoSomeThingWith(i);
}
Will not execute DoSomeThingWith for i = 0, but the loop will continue and DoSomeThingWith will be executed for i = 1 to i = 9.
A really easy way to understand this is to place the word "loop" after each of the keywords. The terms now make sense if they are just read like everyday phrases.
break loop - looping is broken and stops.
continue loop - loop continues to execute with the next iteration.
break causes the program counter to jump out of the scope of the innermost loop
for(i = 0; i < 10; i++)
{
if(i == 2)
break;
}
Works like this
for(i = 0; i < 10; i++)
{
if(i == 2)
goto BREAK;
}
BREAK:;
continue jumps to the end of the loop. In a for loop, continue jumps to the increment expression.
for(i = 0; i < 10; i++)
{
if(i == 2)
continue;
printf("%d", i);
}
Works like this
for(i = 0; i < 10; i++)
{
if(i == 2)
goto CONTINUE;
printf("%d", i);
CONTINUE:;
}
When to use break vs continue?
Break - We're leaving the loop forever and breaking up forever. Good bye.
Continue - means that you're gonna give today a rest and sort it all out tomorrow (i.e. skip the current iteration)!
(Corny stories ¯¯\(ツ)/¯¯ and pics but hopefully helps you remember.
Grip Alert: No idea why those words are being used. If you want to skip the iteration, why not use the word skip instead of continue? This entire Stack overflow question and 1000s of developers would not be confused if the proper name was given.)
break would stop the foreach loop completely, continue would skip to the next DataRow.
There are more than a few people who don't like break and continue. The latest complaint I saw about them was in JavaScript: The Good Parts by Douglas Crockford. But I find that sometimes using one of them really simplifies things, especially if your language doesn't include a do-while or do-until style of loop.
I tend to use break in loops that are searching a list for something. Once found, there's no point in continuing, so you might as well quit.
I use continue when doing something with most elements of a list, but still want to skip over a few.
The break statement also comes in handy when polling for a valid response from somebody or something. Instead of:
Ask a question
While the answer is invalid:
Ask the question
You could eliminate some duplication and use:
While True:
Ask a question
If the answer is valid:
break
The do-until loop that I mentioned before is the more elegant solution for that particular problem:
Do:
Ask a question
Until the answer is valid
No duplication, and no break needed either.
All have given a very good explanation. I am still posting my answer just to give an example if that can help.
// break statement
for (int i = 0; i < 5; i++) {
if (i == 3) {
break; // It will force to come out from the loop
}
lblDisplay.Text = lblDisplay.Text + i + "[Printed] ";
}
Here is the output:
0[Printed] 1[Printed] 2[Printed]
So 3[Printed] & 4[Printed] will not be displayed as there is break when i == 3
//continue statement
for (int i = 0; i < 5; i++) {
if (i == 3) {
continue; // It will take the control to start point of loop
}
lblDisplay.Text = lblDisplay.Text + i + "[Printed] ";
}
Here is the output:
0[Printed] 1[Printed] 2[Printed] 4[Printed]
So 3[Printed] will not be displayed as there is continue when i == 3
Break
Break forces a loop to exit immediately.
Continue
This does the opposite of break. Instead of terminating the loop, it immediately loops again, skipping the rest of the code.
Simple answer:
Break exits the loop immediately.
Continue starts processing the next item. (If there are any, by jumping to the evaluating line of the for/while)
By example
foreach(var i in Enumerable.Range(1,3))
{
Console.WriteLine(i);
}
Prints 1, 2, 3 (on separate lines).
Add a break condition at i = 2
foreach(var i in Enumerable.Range(1,3))
{
if (i == 2)
break;
Console.WriteLine(i);
}
Now the loop prints 1 and stops.
Replace the break with a continue.
foreach(var i in Enumerable.Range(1,3))
{
if (i == 2)
continue;
Console.WriteLine(i);
}
Now to loop prints 1 and 3 (skipping 2).
Thus, break stops the loop, whereas continue skips to the next iteration.
Ruby unfortunately is a bit different.
PS: My memory is a bit hazy on this so apologies if I'm wrong
instead of break/continue, it has break/next, which behave the same in terms of loops
Loops (like everything else) are expressions, and "return" the last thing that they did. Most of the time, getting the return value from a loop is pointless, so everyone just does this
a = 5
while a < 10
a + 1
end
You can however do this
a = 5
b = while a < 10
a + 1
end # b is now 10
HOWEVER, a lot of ruby code 'emulates' a loop by using a block.
The canonical example is
10.times do |x|
puts x
end
As it is much more common for people to want to do things with the result of a block, this is where it gets messy.
break/next mean different things in the context of a block.
break will jump out of the code that called the block
next will skip the rest of the code in the block, and 'return' what you specify to the caller of the block. This doesn't make any sense without examples.
def timesten
10.times{ |t| puts yield t }
end
timesten do |x|
x * 2
end
# will print
2
4
6
8 ... and so on
timesten do |x|
break
x * 2
end
# won't print anything. The break jumps out of the timesten function entirely, and the call to `puts` inside it gets skipped
timesten do |x|
break 5
x * 2
end
# This is the same as above. it's "returning" 5, but nobody is catching it. If you did a = timesten... then a would get assigned to 5
timesten do |x|
next 5
x * 2
end
# this would print
5
5
5 ... and so on, because 'next 5' skips the 'x * 2' and 'returns' 5.
So yeah. Ruby is awesome, but it has some awful corner-cases. This is the second worst one I've seen in my years of using it :-)
Please let me state the obvious: note that adding neither break nor continue, will resume your program; i.e. I trapped for a certain error, then after logging it, I wanted to resume processing, and there were more code tasks in between the next row, so I just let it fall through.
To break completely out of a foreach loop, break is used;
To go to the next iteration in the loop, continue is used;
Break is useful if you’re looping through a collection of Objects (like Rows in a Datatable) and you are searching for a particular match, when you find that match, there’s no need to continue through the remaining rows, so you want to break out.
Continue is useful when you have accomplished what you need to in side a loop iteration. You’ll normally have continue after an if.
if you don't want to use break you just increase value of I in such a way that it make iteration condition false and loop will not execute on next iteration.
for(int i = 0; i < list.Count; i++){
if(i == 5)
i = list.Count; //it will make "i<list.Count" false and loop will exit
}
Since the example written here are pretty simple for understanding the concept I think it's also a good idea to look at the more practical version of the continue statement being used.
For example:
we ask the user to enter 5 unique numbers if the number is already entered we give them an error and we continue our program.
static void Main(string[] args)
{
var numbers = new List<int>();
while (numbers.Count < 5)
{
Console.WriteLine("Enter 5 uniqe numbers:");
var number = Convert.ToInt32(Console.ReadLine());
if (numbers.Contains(number))
{
Console.WriteLine("You have already entered" + number);
continue;
}
numbers.Add(number);
}
numbers.Sort();
foreach(var number in numbers)
{
Console.WriteLine(number);
}
}
lets say the users input were 1,2,2,2,3,4,5.the result printed would be:
1,2,3,4,5
Why? because every time user entered a number that was already on the list, our program ignored it and didn't add what's already on the list to it.
Now if we try the same code but without continue statement and let's say with the same input from the user which was 1,2,2,2,3,4,5.
the output would be :
1,2,2,2,3,4
Why? because there was no continue statement to let our program know it should ignore the already entered number.
Now for the Break statement, again I think its the best to show by example. For example:
Here we want our program to continuously ask the user to enter a number. We want the loop to terminate when the user types “ok" and at the end Calculate the sum of all the previously entered numbers and display it on the console.
This is how the break statement is used in this example:
{
var sum = 0;
while (true)
{
Console.Write("Enter a number (or 'ok' to exit): ");
var input = Console.ReadLine();
if (input.ToLower() == "ok")
break;
sum += Convert.ToInt32(input);
}
Console.WriteLine("Sum of all numbers is: " + sum);
}
The program will ask the user to enter a number till the user types "OK" and only after that, the result would be shown. Why?
because break statement finished or stops the ongoing process when it has reached the condition needed.
if there was no break statement there, the program would keep running and nothing would happen when the user typed "ok".
I recommend copying this code and trying to remove or add these statements and see the changes yourself.
As for other languages:
'VB
For i=0 To 10
If i=5 then Exit For '= break in C#;
'Do Something for i<5
next
For i=0 To 10
If i=5 then Continue For '= continue in C#
'Do Something for i<>5...
Next

Categories

Resources