My XNA program has a while loop (originally a for loop that had the same problem which I changed to allow cleaner exiting) that is supposed to loop through an array of class unitTank, find the first null entry and create a new object at that position, like so:
public void createBlueTank(float X, float Y)
{
Boolean done = false;
int i = 0;
while (i < blueTank.Length - 1 && done == false)
{
if (blueTank[i] == null)
{
blueTank[i] = new unitTank(0, new Vector2(X, Y), this);
done = true;
}
i++;
}
}
blueTank's creation method works fine (I have checked), the issue here is that if the loop includes any code that allows it to exit in any way, the prior code in the iteration doesn't get implemented. That is, if I remove the done = true; (or the break in the original for loop) then the loop creates a new unitTank for each null value in array blueTank in the manner intended, but if I change it to exit the loop after the first time this is done, it doesn't happen at all.
Additionally, I have noticed that if I change all the references to i inside the if statement after the check that blueTank[i] is null to i+2 (because within the testing environment indexes 0 and 1 are defined, but 2 onwards are not); or if I change the initialisation of i to int i = 2, then the loop works as expected. Is this an issue with the if statement erroneously reading blueTank[0] as null, but the assignment statement not overwriting the existing instance inside that index, and then the loop getting cancelled before it ever reaches a truly null index? If so, why is this happening?
Is this an issue with the if statement erroneously reading blueTank[0] as null, but the assignment statement not overwriting the existing instance inside that index,
I think that it makes perfect sense that either blueTank[0] or bluetank[1] actually is null at that time. Put a break-point in the debugger and you should be able to see which values are null
How to use the debugger
So just to rule out a simple typo as being the problem... you are saying that this for loop doesn't work?
for (var i = 0; i < blueTank.Length; i++)
{
if (blueTank[i] == null)
{
blueTank[i] = new unitTank(0, new Vector2(X, Y), this);
break;
}
}
Related
I feel like I'm missing something complete obvious so I apologise in advance if (when?) that is the case.
I'm trying to do something really simple, change a bool value in a struct from false to true. Obviously I can't change it directly, so I created a method within the struct that I can call which should change the value there. It doesn't seem to be the case. Here is the code and I'd appreciate any insight;
public Dictionary<int, List<ScanLineNode>> allScanLineNodes = new Dictionary<int, List<ScanLineNode>>();
public void MethodName(ScanLineNode node [...])
{
//This will perform a raycast from the Node's position in the specified direction. If the raycast hits nothing, it will return Vector3.zero ('Row is complete'), otherwise will return the hit point
Vector3 terminationPoint = node.RaycastDirection(node, direction, maxDist, targetRaycast, replacementColour, backgroundColour);
ScanLineNode terminationNode = new ScanLineNode();
//Previously attempted to store a local reference to this row being used, but also did not work
//List<ScanLineNode> rowNodes = allScanLineNodes[node.rowNumber];
[...]
if (terminationPoint == Vector3.zero)
{
//Definitely reaches this point, and executes this function along the row, I have added breakpoints and checked what happens in this for loop. After running 'RowComplete' (which just changes 'rowComplete' from false to true) 'rowComplete' is still false. Just in case I've included the RowComplete() function below.
Debug.Log("Row Complete: " + node.rowNumber);
for (int i = 0; i < allScanLineNodes[node.rowNumber].Count; i++)
{
allScanLineNodes[node.rowNumber][i].RowCompleted();
}
}
}
ScanLineNode Struct -- Most stuff is hidden (that I don't believe is affecting this), I have included the RowComplete() function however.
public struct ScanLineNode
{
[...]
public bool rowComplete;
[...]
public ScanLineNode([...])
{
[...]
rowComplete = false;
[...]
}
public void RowCompleted()
{
rowComplete = true;
}
}
I have also confirmed that RowCOmpleted() does not get called anywhere aside the above location, and 'rowComplete' is only called from the RowComplete() function
(from comments) allScanLineNodes is a Dictionary<int, List<ScanLineNode>>
Right; the indexer for a List<ScanLineNode> returns a copy of the struct. So when you call the method - you are calling it on a disconnected value on the stack that evaporates a moment later (is overwritten on the stack - this isn't the garbage collector).
This is a common error with mutable structs. Your best bet is probably: don't make mutable structs. But... you could copy it out, mutate it, and then push the mutated value back in:
var list = allScanLineNodes[node.rowNumber];
var val = list[i];
val.RowCompleted();
list[i] = val; // push value back in
But immutable is usually more reliable.
Note: you can get away with this with arrays, since the indexer from an array provides access to a reference to the in-place struct - rather than a copy of the value. But: this isn't a recommendation, as relying on this subtle difference can cause confusion and bugs.
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.
I am making a game in c# and I need to set up a loop to check if one of the player's score hits 6. When it does, static bool endgame would be true and the loop I used for player turns will break to display the winner. I keep getting the error "The field "program.endgame" is assigned but its value is never used" Do not know why I get it but need a fix
static bool endgame = false;
static void Main()
{
for (int r = 0; r < PlayerNumber; r++)
{// make a move for player i
if (players[r].Score == 6)
{
Console.WriteLine(players[r].Nick + " wins the game.");
endgame = true;
break;
}
}
}
It's just a warning, not an error. You are getting the warning because you never reference the endgame variable. The compiler is thinking "you could just remove this variable and your program would be exactly the same" which is true.
If you are assigning the variable for your own debugging purposes, or because you plan on using it later, feel free to ignore the warning.
The part you are looking for is the following, but it's still useless, if you're not planning on using it.
for (int r = 0; r < Player Number && !endgame; r++)
This is not an error, but a Warning, which doesn't stopping you from Running the application, but warns you that you're declaring a variable and assigning it, but never using its value.
Unless you plan to do anything with the endgame variable, you can remove it. The break will end the loop.
But if you had any code later that checks endgame, you won't get that error any more.
What is wrong with the following for loop syntax the crv variable is an array and I want an increment of 2:
for(int i<0; i<crv.Count;i+2)
{
//Code Here
}
My compiler only says Semicolon expected which is not a very useful feedback...
You need to start out initializing i to zero, not comparing it to zero. Additionally your last statement doesn't actually change i, it just returns a value of i+2 and does nothing with that value, you need to actually set i to that result.
for(int i = 0; i < crv.Count;i+=2)
{
//Code Here
}
The biggest error is that i+2 is not reassigned to i.
for(int i = 0; i<crv.Count;i = i+2)
{
//Code Here
}
You are throwing away the increment and i never changes value.
Then, you are not initializing i but checking whether it is less than 0.
Please note: first section is assignment You can't use comparison as int i<0;, instead it should be int i=0 or int i = -10 or anything similar as required.
Also in the increment section, either assign the updated value back to i
for(int i =0; i<crv.Count; i+=2)
{
//Code Here
}
or do the same in the body (just mentioning the option, which is useful in some specific scenarios)
for(int i =0; i<crv.Count;)
{
//Code Here
i+=2;
}
While most of these answers do tell you how to fix your code they don't tell you why it doesn't work which I think is important for you to understand.
a for loop consists of three parts, separated by semicolons.
for(part1;part2;part3)
part1 is executed only once - when the execution of the loop first begins. (this is normally where you assign an initial value to your counter)
part2 is then executed next, checking if its value is true or false.
If is true, then the body of the loop is executed
Then part3 is executed, (as you're attempting to do) this is normally where you increment
Then part2 is checked again, if its true, it goes through the process again, if its false it exists the loop
The first part of the for loop decides on i's initial value. in your example, you have "<", which isn't a solid value. Try i=0 instead. also, the last part reads as i, in addition to 2, instead of adding two each iteration. try i+=2 instead.
Is there any reason to assign parameter values to local variables inside a method in order to use those values without changing them? I.e. like the following:
private void MyMethod(string path)
{
string myPath = path;
StreamReader mystream = new StreamReader(myPath);
...
}
Or can I always put it like this (and the code above is redundant and just not clean):
private void MyMethod(string path)
{
StreamReader mystream = new StreamReader(path);
...
}
I know it works both ways, but I'd like to be sure there isn't anything I missed in my understanding.
The only time you need to do this (assign locally) is if you are in a foreach loop or using Linq. Otherwise you can run into issues with modified closures.
Here is a snippet from an MSDN blog (All content below is from the link).
http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx
But I'm getting ahead of myself. What's the output of this fragment?
var values = new List<int>() { 100, 110, 120 };
var funcs = new List<Func<int>>();
foreach(var v in values)
funcs.Add( ()=>v );
foreach(var f in funcs)
Console.WriteLine(f());
Most people expect it to be 100 / 110 / 120. It is in fact 120 / 120 / 120. Why?
Because ()=>v means "return the current value of variable v", not "return the value v was back when the delegate was created". Closures close over variables, not over values. And when the methods run, clearly the last value that was assigned to v was 120, so it still has that value.
This is very confusing. The correct way to write the code is:
foreach(var v in values)
{
var v2 = v;
funcs.Add( ()=>v2 );
}
Now what happens? Every time we re-start the loop body, we logically create a fresh new variable v2. Each closure is closed over a different v2, which is only assigned to once, so it always keeps the correct value.
Basically, the problem arises because we specify that the foreach loop is a syntactic sugar for
{
IEnumerator<int> e = ((IEnumerable<int>)values).GetEnumerator();
try
{
int m; // OUTSIDE THE ACTUAL LOOP
while(e.MoveNext())
{
m = (int)(int)e.Current;
funcs.Add(()=>m);
}
}
finally
{
if (e != null) ((IDisposable)e).Dispose();
}
}
If we specified that the expansion was
try
{
while(e.MoveNext())
{
int m; // INSIDE
m = (int)(int)e.Current;
funcs.Add(()=>m);
}
then the code would behave as expected.
It's exactly the same thing, the only difference is that in the first case you make a copy of the reference (which is destroyed anyway when the method gets out of scope, which happens when the execution ends).
For better readability, stick with the second case.
I prefer the second option. It makes no sense to create a new variable with the parameter. Also, from a reading perspective, it makes more sense to create a stream from a path (the one you received) instead of instantiating a "myPath" variable.