PictureBox.bounds.intersectswith doesn't seem to work - c#

i am writing a game and i have a simple enemy AI that only follows you, i need the enemys to not go on top of each other so i tried this code but it doesn't work they stil going on top of each other (except of maybe 2 who don't and i have no idea why).
here is the code that check's if they intersects
for (int i = 0; i < z.Length ; i++)
{
for (int j = 0; j < z.Length ; j++)
{
if (zombie[i].Bounds.IntersectsWith(zombie[j].Bounds) && i != j)
{
z[i].setAllowed(false);
}
else
{
z[i].setAllowed(true);
}
}
}
The code is inside a timer and setAllowed tells the zombie class weather the zombie can move or not.

Your "allowed" values are being overriden during the loop. For instance:
(1) i == 2, j == 1 => let's say that SetAllowed(false) is executed (collision, expected behavior)
(2) (next iteration) i == 2, j == 2 => i == j so SetAllowed(true) is executed (overriding correct behavior)
(3) Even when i != j, you can override the "allowed" value when a next zombie does not collide.
Try something like that:
for (int i = 0; i < z.Length ; i++)
{
bool allowed = true;
for (int j = 0; j < z.Length ; j++)
{
if (i == j)
continue;
if (zombie[i].Bounds.IntersectsWith(zombie[j].Bounds))
{
allowed = false;
break;
}
}
z[i].setAllowed(allowed);
}
Of course there can be other problems somewhere else in your logic, but this is a start from the code you provide.

Related

Need 'System.IndexOutOfRangeException' solution

if (Int32.Parse(strTotals) == 0 && nTotalCount != 0)
{
nTotalCount = 0;
for (int j = 0; j < 66; j++)
{
if (GameHistoryPicBox1[j].InvokeRequired)
{
GameHistoryPicBox1[j].BeginInvoke(new MethodInvoker(() =>
{
if ((j + j / 6) % 2 == 0)
GameHistoryPicBox1[j].Image = Properties.Resources.al1; // Line2
else
GameHistoryPicBox1[j].Image = Properties.Resources.al2; // Line4
}));
}
else
{
if ((j + j / 6) % 2 == 0)
GameHistoryPicBox1[j].Image = Properties.Resources.al1;
else
GameHistoryPicBox1[j].Image = Properties.Resources.al2;
}
}
}
I have been checking nTotalCount value by using thread.
If nTotalCount is zero, then I must clean all game picture box image.
So I was implement above code.
Unfortunately, I got the error:
An unhandled exception of type 'System.IndexOutOfRangeException'
on Line 2 and 4.
And the j value was 66.
Is it possible that j value could be 66?
This is because of how closures work. Your lambda expression that you're creating and passing to the MethodInvoker references the j variable by reference. Thus when this piece of code is being executed (which can be almost any time, as it's asynchronous) the j variable can have any value from 0 to 66. And it can be 66 after the loop has finished.
A quick fix is to make a copy of j:
int index = j;
GameHistoryPicBox1[index].BeginInvoke(new MethodInvoker(() =>
{
if ((index + index / 6) % 2 == 0)
GameHistoryPicBox1[index].Image = Properties.Resources.al1; // Line2
else
GameHistoryPicBox1[index].Image = Properties.Resources.al2; // Line4
}));
You can read more about this here.
The variable j is being passed into the closure, and because the call is asynchronous, it is actually executed at some point after the loop completes. You cannot be sure what the value of j will be when the delegate is executed.
Try passing the value of j in as a parameter to the delegate, like this:
GameHistoryPicBox1[j].BeginInvoke(new Action<int>((x) =>
{
if ((x + x / 6) % 2 == 0)
GameHistoryPicBox1[x].Image = Properties.Resources.al1;
else
GameHistoryPicBox1[x].Image = Properties.Resources.al2;
}), j);
You've been bitten by the loop-variable-in-a-closure-bug.
Instead of
for (int j = 0; j < 66; j++)
{
//blahblahblah
}
write
for (int jj = 0; jj < 66; jj++)
{
int j = jj;
//blahblahblah
}

Conway's Game of Life logic error

I'm taking a class that uses C# and our first assignment is to implement Conway's game of Life. We must do this by reading in a text file formatted something like this:
*
*
***
***
We then have to display the next 10 generations on the screen.
I have the file read into a string array, then I copy it to another array. I then go through it character by character and change the copied array to match what the next generation should be. My problem is that the code I have to count the live neighbors isn't working and I can't figure out why. I displayed the number of live neighbors for each cell on the screen and about half of them are wrong. I know the error is occurring with cells on the edge of the "board," but I can't figure out how to fix it.
Now, I don't want the whole thing written for me, that'd be a bit pointless. I just can't figure out where my logic is off. Any help would be appreciated. Also, I'm aware that my code is pretty poor, overall. This was just the only way I could figure it out. Sorry.
class Program
{
static void Main(string[] args)
{
//gets file name from command arguments
//checks to make sure file exists, exits if file does not exist
if (!File.Exists(Environment.GetCommandLineArgs()[1])) { System.Environment.Exit(1); }
//gets file name from command arguments then reads file into array of strings
string[] gen0 = File.ReadAllLines(Environment.GetCommandLineArgs()[1]);
string[] gen1 = gen0;
char alive = '*';
char dead = ' ';
//displays first generation
foreach (string s in gen0)
{
Console.WriteLine(s);
}
Console.WriteLine("=====================================");
//counts live neighbors of a cell
int count = 0;
for (int i = 0; i < gen0.Length; i++)
{
count = 0;
for (int j = 0; j < gen0[i].Length; j++)
{
//check top left neighbor
if (i > 0 && j > 0 && j < gen0[i-1].Length )
{
if (gen0[i - 1][j - 1] == alive) { count++; }
}
//check above neighbor
if (i > 0 && j < gen0[i-1].Length)
{
if (gen0[i - 1][j] == alive) { count++; }
}
//check top right neighbor
if (i > 0 && j + 1 < gen0[i - 1].Length)
{
if (gen0[i - 1][j + 1] == alive) { count++; }
}
//check left neighbor
if (j > 0)
{
if (gen0[i][j - 1] == alive) { count++; }
}
//check right neighbor
if (j + 1 < gen0[i].Length)
{
if (gen0[i][j + 1] == alive) { count++; }
}
//check bottom left neighbor
if (i + 1 < gen0.Length && j > 0 && j < gen0[i+1].Length)
{
if (gen0[i + 1][j - 1] == alive) { count++; }
}
//check below neighbor
if (i + 1 < gen0.Length && j < gen0[i+1].Length)
{
if (gen0[i + 1][j] == alive) { count++; }
}
//check bottom right neighbor
if (i + 1 < gen0.Length && j + 1 < gen0[i].Length && j + 1 < gen0[i+1].Length)
{
if (gen0[i + 1][j + 1] == alive) { count++; }
}
//Console.WriteLine(count);
//kills cells
if (count < 2 || count > 3)
{
gen1[i] = gen1[i].Remove(j, 1);
gen1[i] = gen1[i].Insert(j, dead.ToString());
}
//births cells
if (count == 3)
{
gen1[i] = gen1[i].Remove(j, 1);
gen1[i] = gen1[i].Insert(j, alive.ToString());
}
}
}
foreach (string s in gen1)
{
Console.WriteLine(s);
}
}
}
Your problem is very simple - you're resetting count in the wrong place. Put it inside the loop and it will (probably) work.
Regarding the rest of the code, if you want to make it significantly easier to follow just give your game area a one-element border.
You'll need to pad the file you read in (blank line above and below, blank characters to the left and right), and alter your loops to:
for (int i = 1; i < gen0.Length - 1; i++)
and
for (int j = 1; j < gen0[i].Length - 1; j++)
but your central count calculation can then be reduced down to a single calculation:
count = (gen0[i - 1][j - 1] == alive) ? 1 : 0 +
(gen0[i - 1][j] == alive) ? 1 : 0 +
... etc ...
which should make for cleaner code and ensure that any other errors you may make are significantly easier to spot.
So the first bug I see is that you don't actually copy the board for the next iteration.
gen1 = gen0;
The code above only assigns the gen1 reference to the same object as gen0. So when you modify gen1, you actually modify gen0 as well... causing inconsistencies in latter iterations. Try this:
gen1 = (string[])gen0.Clone();
Second bug is that int count = 0 should be in the second loop instead of first:
for (int i = 0; i< gen0.Length; i++)
{
// not here
// int count = 0
for (int j = 0; j < gen0[i].Length; j++)
{
// here
int count = 0
...
}
...
}
This way you reset the count for every cell instead of every row.

Many else and if statements?

I am reading a csv file which has column names in first line and values in line >1. I need to get the position of the column name. The only way I can think of is to do either switch or ifs. I read it somewhere that in my case , it is faster (better) to do the ifs. However the file has many columns (~120). Just wondering if there is an alternative(s).
private static void Get_Position(string line, performance p)
{
string[] line_split = line.Split(',');
for (int i = 0; i < line_split.Length; i++)
{
if (line_split[i].Contains(#"(0)\% Processor Time"))
{
p.percore[0] = i;
}
else if (line_split[i].Contains(#"(1)\% Processor Time"))
{
p.percore[1] = i;
}
else if (line_split[i].Contains("Private Bytes"))
{}
else if (line_split[i].contains("DPC")
{
}
//on and on and on with else ifs
What is preventing you from using a loop?
for (int i = 0; i < line_split.Length; i++)
{
for(var j = 0; j < 120; j++)
{
if(line_split[i].Contains(#"(" + j + ")\% Processor Time"))
{
p.percore[j] = i;
}
}
...
To maintain the same functionality as if else if then you could use a break inside the conditional.
Edit: The edit now made it clear that there is no clear pattern to the string in contains. Still, if you are writing out 120 if/else if statements you should store what you will be looking for in some type of collection. For example, a List would work. Then access the index j of the collection in your loop:
...
var listOfSearchItems = new List<string>() { "Private Bytes", "DPC" };
for (int i = 0; i < line_split.Length; i++)
{
for(var j = 0; j < 120; j++)
{
if(line_split[i].Contains(listOfSearchItems[j])
{
p.percore[j] = i;
}
}
...

Multi threading not executing properly

I have a function here that calls another function in multiple threads. In the second functions, the value of each element of refValuesd[,] is 1. But when I check the elements of the same 2D array in the graph1() function after the multiple threads are called, I get different values for the elements of refValuesd[,].I am a novice in multithreading.
void graph1()
{
for (int j = 0; j < 366; j++) //loop to refresh element values
{
refValues[j] = 0;
threshValues[j] = 0;
y_Values[j] = 0;
y__Values[j] = 0;
yValues[j] = 0;
for (int k = 0; k < 1000; k++)
{
threshValuesd[k,j] = 0;
refValuesd[k,j] = 0;
y__Valuesd[ k,j] = 0;
y_Valuesd[k,j] = 0;
yValuesd[k,j] = 0;
}
}
List<string>[] list = new List<string>[4];//manpower details
list = A.mandetselect();
int number = A.Countmandet();//retuns an integer value
string[] trade = list[1].ToArray();
string[] license = list[2].ToArray();
string[] training = list[3].ToArray();
string[] display_status = list[4].ToArray();
List<string>[] listc = new List<string>[14];//Project details
listc = A.Select();
int numberc = A.Count();
string abc = "";
int q = 0;
for (int j = 0; j < number; j++)
{
if (!display_status[j].Equals("NO") && (selection == "ALL" || (selection == "ALL-LAE" && license[j] != "") || (selection == "ALL-NON LAE" && license[j] == "") || (selection == "AVIONICS -ALL" && trade[j] == "Avionics") || (selection == "AVIONICS-NON LAE" && trade[j] == "Avionics" && license[j] == "") || (selection == "AVIONICS-LAE" && trade[j] == "Avionics" && license[j] != "") || (selection == "AIRFRAME-ALL" && trade[j] == "Airframes") || (selection == "AIRFRAME-NON LAE" && trade[j] == "Airframes" && license[j] == "") || (selection == "AIRFRAME-LAE" && trade[j] == "Airframes" && license[j] != "")))
{
int z = numberc;
string[] nameofproj = listc[0].ToArray();
int copy = q;
int copy2 = j;
string a = abc;
string[] name = list[0].ToArray();
List<string>[] lista = new List<string>[5];
string[] status = listc[13].ToArray();
thread[copy] = new Thread(() => graph1threader(a, name[copy2], lista, z, nameofproj, status, copy));
thread[copy].Start();
q++;
}
}
for (int j = 0; j < 366; j++)
{
for (int k = 0; k < q; k++)
{
threshValues[j] += threshValuesd[k, j];
refValues[j] += refValuesd[k, j];
y__Values[j] += y__Valuesd[k, j];
y_Values[j] += y_Valuesd[k, j];
yValues[j] += yValuesd[k, j];
}
}
for (int j = 0; j < 366; j++)
{
DateTime temp = G.AddDays(j);
string temper = temp.ToShortDateString();
y__Values[j] = y__Values[j] - y_Values[j];
xNames[j] = temper;
}
chart1.Series[1].Points.DataBindXY(xNames, y_Values);
chart1.Series[2].Points.DataBindXY(xNames, y__Values);
chart1.Series[3].Points.DataBindXY(xNames, refValues);
chart1.Series[4].Points.DataBindXY(xNames, threshValues);
chart1.Series[5].Points.DataBindXY(xNames, yValues);
}
Here is the function that is executed on multiple threads:
void graph1threader(string abc,string nameofj,List<string>[] lista,int numberc,string[] nameofproj,string[] status,int copy )
{
DBConnect A = new DBConnect();
int x = copy;
string[] projname;
string[] country;
string[] start;
string[] end;
abc = nameofj.Replace(" ", "_");
lista = A.manprojselect(abc);
projname = lista[0].ToArray();
country = lista[2].ToArray();
start = lista[3].ToArray();
end = lista[4].ToArray();
for (int k = 0; k < 366; k++)//basic
{
refValuesd[x, k]++;
refValuesd[copy,k].ToString());
threshValuesd[x, k] = 0.8;
string Status = "";
int flag = 0;
for (int l = 0; l < A.Countproj(abc); l++)
{
for (int m = 0; m < numberc; m++)
{
if (nameofproj[m] == projname[l])
{
Status = status[m];
}
}
DateTime shuru = DateTime.ParseExact(start[l],
"dd-MM-yyyy hh:mm:ss",
CultureInfo.InvariantCulture);
DateTime anth = DateTime.ParseExact(end[l],
"dd-MM-yyyy hh:mm:ss",
CultureInfo.InvariantCulture);
if (temp >= shuru && temp <= anth)
{
if (Status != "PLANNED" && Status != "LO" && flag == 0)
{
y_Valuesd[x,k]++;//BASIC UTILISATION
flag = 1;
}
if (Status == "IP" || Status == "OTD")
y__Valuesd[x,k]++;//EXCESS
if (Status == "PLANNED")
{
yValuesd[x,k]++;//UNUTILISED
}
}
}
}
}
There's probably a few problems in there, but two I can spot:
Firstly, the threads are trying to do refValuesd[x, k]++ which isn't threadsafe.
Try this instead:
Interlocked.Increment(ref refValuesd[x, k]);
Secondly, you are not waiting for all the threads to terminate before using the data they've generated. Try adding this just before the for (int j = 0; j < 366; j++) line:
foreach (var thread in threads)
thread.Join();
It looks like you have much to learn, so I recommend that you read this free ebook:
http://www.albahari.com/threading/
Make sure you surround access to refvalued with lock sections and you will start in the right direction. You have to design your locking not to create race conditions and deadlocks as well.
EDIT: So, having reviewed your code, here are a few comments
It looks like you kick off the graph function, which in turn executes the graph1threader function on multiple threads. I won't question whether or not that is necessary - the assumption is that you've already decided it is.
Order of events
It looks like you don't stop to wait for all the graph1threader threads to complete before continuing in your second loop. So here is a question:
Do you want the graph1threader jobs to complete before you continue?
If so, have you looked at Task? Instead of creating threads, you could almost literally swap Thread with Task and then, once you have completed the creation of all your Task objects and started them, you could put Task.WaitAll after your for (int j = 0; j < number; j++) loop to wait for them to complete before you then do the third for loop in graph1:
thread[copy] = new Task(() => graph1threader(a, name[copy2], lista, z, nameofproj, status, copy));
thread[copy].Start();
q++;
}
}
Task.WaitAll(thread);
for (int j = 0; j < 366; j++)
{
for (int k = 0; k < q; k++)
{
threshValues[j] += threshValuesd[k, j];
refValues[j] += refValuesd[k, j];
y__Values[j] += y__Valuesd[k, j];
y_Values[j] += y_Valuesd[k, j];
yValues[j] += yValuesd[k, j];
}
}
If you don't want to use Task (or can't) Thread.Join will also work, but Task supports cancellation easier than Thread so if you have a UI with long running operations it will make things easier for you.
Shared fields
The following variables are used by both functions (please ignore any incorrect variables types, it is the names that are important):
double[,] threshValuesd;
int[,] refValuesd;
int[,] y__Valuesd;
int[,] y_Valuesd;
int[,] yValuesd;
I am calling this list bookmark A to be used later
All these potentially need protecting against multi-threaded race conditions etc.
How to protect the shared fields
Regardless of whether you wait or not, you need to protect your shared fields in graph1threader. So, if I've read your code properly:
you pass a unique, incremented value to graph1threader (using q++ in your 2nd for loop in graph1)
Therefore the following lines will not compete to set values between threads in graph1threader:
refValuesd[x, k]++;
threshValuesd[x, k] = 0.8;
y_Valuesd[x,k]++;
y__Valuesd[x,k]++;
yValuesd[x,k]++;
(Side note: these variable names are incomprehensible to me, you might try naming them in a more descriptive way than yValuesd, y_Valuesd and y__Valuesd to help you debug this later).
However, even if threads don't compete to update values in the same array slot, you probably have problems coming in the form of memory barriers and read/write access to a single array slot. Therefore, I would recommend doing this, quite simply declare a class field:
private readonly object SyncRoot = new object();
and then around all access to any of the shared fields I mentioned above bookmark A you need to use (picking your first loop as an example):
lock (this.SyncRoot) {
for (int j = 0; j < 366; j++)
{
for (int k = 0; k < q; k++)
{
threshValues[j] += threshValuesd[k, j];
refValues[j] += refValuesd[k, j];
y__Values[j] += y__Valuesd[k, j];
y_Values[j] += y_Valuesd[k, j];
yValues[j] += yValuesd[k, j];
}
}
}
Keep lock calls as infrequent as possible, but as close to the shared resource as possible. By that I mean that you could lock inside the inner for loop if you wanted to, but that will be slower, however you may need that to allow other threads to proceed more frequently if they also lock the same object.
NOTE: This technique of using a shared lock assumed you wanted the graph1threader threads to be running at the same time as your third for loop in graph1 (i.e. my comment about Task objects wasn't required). If this is not the case, I think you could create a local object within each function and lock on that instead. Each thread would therefore have a different lock object. Because no thread accesses the same slot in your arrays at the same time, this would just enforce memory barriers and ensure that all threads saw the same values when they read them.
Sorry this was so long, it was hard to know where to start without know more about the assumptions you went through to build this code.

Index was out of range error

I have been looking for the reason why I get this error message for several days now! And I need help to solve this or to improve the code. It's hard to understand why this error happens and find the reason, when it just happens sometimes and not all the time! But my guess is that it has to do with the list and the numbers of items in the lists. It's in the second part of the code where the error event happens. I have also tried to add the objects that I want to remove in a special "to remove list", but why should this not work? Help is appreciated! Thanks!
public void CollisionControlMissileHitAsteroid(ContentManager content)
{
for (int i = 0; i < missilesList.Count(); i++)
{
// Stora asteroider
for (int j = 0; j < asteroidsBigList.Count(); j++)
{
if (missilesList.ElementAt(i).Bounds().Intersects(asteroidsBigList.ElementAt(j).Bounds())) // Fel här ??
{
for(int x = 0; x < 2; x++)
AddNewSmallAsteroidToList(new AsteroidSmall(content, asteroidsBigList.ElementAt(j).Position));
missilesList.RemoveAt(i);
i--;
asteroidsBigList.RemoveAt(j);
j--;
}
}
if (missilesList.Count() > 0 && asteroidsSmallList.Count > 0)
{
for (int k = 0; k < asteroidsSmallList.Count(); k++)
{
if (missilesList.ElementAt(i).Bounds().Intersects(asteroidsSmallList.ElementAt(k).Bounds())) // THIS IS WHERE THE ERROR EVENT HAPPENS!
{
missilesList.RemoveAt(i);
i--;
asteroidsSmallList.RemoveAt(k);
k--;
}
}
}
}
}
EDIT:
Is this where I should place the break? Ask beacause it still happens! I can play for five minutes until it happens!
if (missilesList.Count() > 0 && asteroidsSmallList.Count() > 0)
{
for (int k = 0; k < asteroidsSmallList.Count(); k++)
{
if (missilesList.ElementAt(i).Bounds().Intersects(asteroidsSmallList.ElementAt(k).Bounds()))
{
missilesList.RemoveAt(i);
i--;
asteroidsSmallList.RemoveAt(k);
k--;
break; // ???????
}
}
}
You are right in thinking that it's to do with the bounds of the list. I've never come up with a satisfactory way of removing listitems or array elements within a loop other than, as you say, building up a list of indexes and removing them outside of the loop.
Having said that, have you tried going through the list backwards, like -
for (int k = asteroidsSmallList.Count() - 1; k >= 0; k--)
{
...
Suppose you start off with one missile and two asteroids. The missile (i=0) hits the first asteroid (j=0) - but you're then continuing with i=-1 and j=0. You should be breaking out of the inner loop and continue with the next iteration of the outer loop there instead. After all, you're "done" with the missile - it can't hit any other asteroids, big or small.
(And yes, as per xanatos's comments, it would be more idiomatic to use the Count property instead of the Count() method.)
I think that the problem is obvious because your code runs in a for loop. In the first for loop you got i=0. Read my comments inside
for (int i = 0; i < missilesList.Count(); i++)
{
// Stora asteroider
for (int j = 0; j < asteroidsBigList.Count(); j++)
{
if (missilesList.ElementAt(i).Bounds().Intersects(asteroidsBigList.ElementAt(j).Bounds())) // Fel här ??
{
for(int x = 0; x < 2; x++)
AddNewSmallAsteroidToList(new AsteroidSmall(content, asteroidsBigList.ElementAt(j).Position));
missilesList.RemoveAt(i);
// In the first iteration of the outer for loop i=0, so what if the line below is executed
// you will get negative index Hope this help
i--;
asteroidsBigList.RemoveAt(j);
j--;
}
}

Categories

Resources