so in unity im creating randomly generating rooms. inside of these rooms i will "randomly" place objects, enemy,objects,items etc. based on nodes. nodes are transform objects that are separated from each other by 1 unit. the idea is that i can now pick a node and instantiate something at that node. The code works great when the room is 10x10(x,z since its a 3d game) i get a nice grid pattern it also works as expected when x is any multiple of 2. however when z changes from 10 it doesn't create the grid properly. there is also a problem if the room changes locations other then 0,0.
floor is a child object of the room.
void RoomSetup()
{
bool first = true;
int collCount = -1;
GameObject placeHolder = new GameObject("temp");
float colls;
float offX, offZ;
colls = floor.transform.localScale.x - 1;
print(colls);
for (int i = 0; i < ((floor.transform.localScale.x-1)
*(floor.transform.localScale.z-1)); i++)
{
//creating a for loop that stops when its greater then the area of the rectangle, subtract one from x,z so theres a one unit of padding from the walls.
offX = floor.transform.lossyPosition.x;
offZ = floor.transform.lossyPosition.z;
//getting the offset of the room in world space this is where i believe the issues arise
collCount++;
GameObject temp = new GameObject(i + " Node");
temp.transform.SetParent(floor.transform);
temp.AddComponent<BoxCollider>();
temp.GetComponent<BoxCollider>().isTrigger = true;
if(!first)
{
temp.transform.position = new Vector3((placeHolder.transform.position.x + 1), 6, placeHolder.transform.position.z);
placeHolder = temp;
if (collCount >= colls)
{
print("new line on " + temp.name + " coll " + collCount);
collCount = 0;
placeHolder.transform.position = new Vector3((-(floor.transform.localScale.x / 2) + 1)+offX, 6, (placeHolder.transform.position.z - 1)-offZ);
}
}
if (first)
{
// print(colls);
temp.transform.position = new Vector3((-(floor.transform.localScale.x / 2) + 1) + offX, 6, floor.transform.localScale.z - offZ);
placeHolder = temp;
first = false;
}
nodes.Add(temp);
}
}
Here are some pictures to help illustrate the issue
the first image is when the room is at 0,0 and it creates a nice grid pattern
when the room is offest it creates the grid still at 0,0
i figured it out, it happend to do with with the local and world scale/pos of the floor and the room
void RoomSetup()
{
bool first = true;
int collCount = -1;
GameObject placeHolder = new GameObject("temp");
float colls;
colls = floor.transform.localScale.x - 1;
offX = floor.transform.localScale.x;
offZ = floor.transform.localScale.z;
offX = (offX / 2) - offX + 1;
offZ = (offZ / 2) - 1;
offX = offX + floor.transform.position.x;
offZ = (offZ + floor.transform.position.z);
print(colls);
for (int i = 0; i < ((floor.transform.localScale.x-1) * (floor.transform.localScale.z-1)); i++)
{
collCount++;
//print(collCount);
GameObject temp = new GameObject(i + " Node");
temp.transform.SetParent(floor.transform);
temp.AddComponent<BoxCollider>();
temp.GetComponent<BoxCollider>().isTrigger = true;
if(!first)
{
temp.transform.position = new Vector3((placeHolder.transform.position.x + 1), 6, placeHolder.transform.position.z);
placeHolder = temp;
if (collCount >= colls)
{
print("new line on " + temp.name + " coll " + collCount);
collCount = 0;
temp.transform.position = new Vector3(floor.transform.localPosition.x + offX, 6, placeHolder.transform.position.z - 1);
placeHolder = temp;
}
}
if (first)
{
// print(colls);
temp.transform.position = new Vector3(floor.transform.localPosition.x+offX, 6, floor.transform.localPosition.z+offZ);
placeHolder = temp;
first = false;
}
nodes.Add(temp);
}
}
works as intended, creates a grid of nodes on the floor of anyroom square room
Related
I have a 2D grid of cells, like so:
I want to find the "centroids," or the places in each room that can see the most other cells. For example, "centroid" 1 can see 500 other cells, "centroid" 2 can see 400 other cells (NOT included in the first 500), and so on (if there's a better name for this let me know).
I'm currently doing this with the code below.
public void SetCentroids(CellWalkableState[,] grid)
{
centroids = new List<((int, int), int)>();
List<(int, int)> cellsCopy = new List<(int, int)>();
for (int i = 0; i < cells.Count; i++)
{
cellsCopy.Add(cells[i]);
}
Debug.Log(DateTime.Now.ToString("o") + " - Setting centroids for room with " + cells.Count + " cells");
var perCellInView = cellsCopy.AsParallel().Select(x => (x, StaticClass.FindInView(x, grid))).ToList();
var force_start = perCellInView.First();
Debug.Log(DateTime.Now.ToString("o") + " - got in view");
var perCellInViewOrdered = perCellInView.AsParallel().OrderByDescending(xxx => xxx.Item2.Count);
var force_start_1 = perCellInViewOrdered.First();
Debug.Log(DateTime.Now.ToString("o") + " - sorted");
List<(int, int)> roomCellsAdded = new List<(int, int)>();
while(roomCellsAdded.Count < (cells.Count*0.9))
{
if(cellsCopy.Count == 0)
{
Debug.LogError("something is wrong here.");
}
var centroid = perCellInViewOrdered.First().x;
var centroidCells = perCellInViewOrdered.First().Item2;
if(centroidCells.Count == 0)
{
Debug.Log("this shouldnt be happening");
break;
}
roomCellsAdded.AddRange(centroidCells);
centroids.Add((centroid, centroidCells.Count));
Debug.Log(DateTime.Now.ToString("o") + " - added centroids, " + roomCellsAdded.Count + " cells in view");
var loopPerCellInView = perCellInView.AsParallel().Where(x => centroids.Select(y => y.Item1).Contains(x.x) == false).Select(x => (x.x, x.Item2.Except(roomCellsAdded).ToList())).ToList();
Debug.Log(DateTime.Now.ToString("o") + " - excluded");
perCellInViewOrdered = loopPerCellInView.AsParallel().OrderByDescending(xxx => xxx.Item2.Count);
Debug.Log(DateTime.Now.ToString("o") + " - resorted");
}
}
public static List<(int, int)> FindInView((int,int) start, CellWalkableState[,] grid)
{
List<(int, int)> visible = new List<(int, int)>() { start };
bool alive = true;
int r = 1;
var length_x = grid.GetLength(0);
var length_y = grid.GetLength(1);
List<(int, int)> searched = new List<(int, int)>();
List<double> angles = new List<double>();
while(alive)
{
//alive = false;
int newR = r;
int count = CountFromR(newR);
var angleInc = 360.0 / count;
var rNexts = Enumerable.Repeat(1, count).ToArray();
for (int i = 0; i < count; i++)
{
var angle = angleInc * i;
if(angles.Contains(angle) == false)
{
angles.Add(angle);
float cos = Mathf.Cos((float)(Mathf.Deg2Rad * angle));
float sin = Mathf.Sin((float)(Mathf.Deg2Rad * angle));
var b = r;
var p = i % (r * 2);
var d = math.sqrt(math.pow(b, 2) + math.pow(p, 2));
var dScaled = d / r;
bool keepGoing = true;
while(keepGoing)
{
var rCur = dScaled * (rNexts[i]);
var loc = (start.Item1 + Mathf.RoundToInt(rCur * cos), start.Item2 + Mathf.RoundToInt(rCur * sin));
if (searched.Contains(loc) == false)
{
searched.Add(loc);
if (loc.Item1 >= 0 && loc.Item1 < length_x && loc.Item2 >= 0 && loc.Item2 < length_y)
{
if (grid[loc.Item1, loc.Item2] == CellWalkableState.Interactive || grid[loc.Item1, loc.Item2] == CellWalkableState.Walkable)
{
visible.Add(loc);
}
else
{
keepGoing = false;
}
}
else
{
keepGoing = false; // invalid, stop
}
}
else
{
if (visible.Contains(loc) == false)
{
keepGoing = false; // can stop, because we can't see past this place
}
}
if(keepGoing)
{
rNexts[i]++;
}
}
}
}
angles = angles.Distinct().ToList();
searched = searched.Distinct().ToList();
visible = visible.Distinct().ToList();
if(rNexts.All(x => x <= r))
{
alive = false;
}
else
{
r = rNexts.Max();
}
}
return visible;
}
static int CountFromR(int r)
{
return 8 * r;
}
The "short" summary of the code above is that each location first determines what cells around itself it can see. That becomes a list of tuples, List<((int,int), List<(int,int)>)>, where the first item is the location and the second is all cells it views. That main list is sorted by the count of the sublist, such that the item with the most cells-it-can-vew is first. That's added as a centroid, and all cells it can view are added to a second ("already handled") list. A modified "main list" is formed, with each sublist now excluding anything in the second list. It loops doing this until 90% of the cells have been added.
Some output:
2021-04-27T15:24:39.8678545-04:00 - Setting centroids for room with 7129 cells
2021-04-27T15:45:26.4418515-04:00 - got in view
2021-04-27T15:45:26.4578551-04:00 - sorted
2021-04-27T15:45:27.3168517-04:00 - added centroids, 4756 cells in view
2021-04-27T15:45:27.9868523-04:00 - excluded
2021-04-27T15:45:27.9868523-04:00 - resorted
2021-04-27T15:45:28.1058514-04:00 - added centroids, 6838 cells in view
2021-04-27T15:45:28.2513513-04:00 - excluded
2021-04-27T15:45:28.2513513-04:00 - resorted
2021-04-27T15:45:28.2523509-04:00 - Setting centroids for room with 20671 cells
This is just too slow for my purposes. Can anyone suggest alternate methods of doing this? For all of the cells essentially the only information one has is whether they're "open" or one can see through them or not (vs something like a wall).
An approximate solution with fixed integer slopes
For a big speedup (from quadratic in the number of rooms to linear), you could decide to check just a few integer slopes at each point. These are equivalence classes of visibility, i.e., if cell x can see cell y along such a line, and cell y can see cell z along the same line, then all 3 cells can see each other. Then you only need to compute each "visibility interval" along a particular line once, rather than per-cell.
You would probably want to check at least horizontal, vertical and both 45-degree diagonal slopes. For horizontal, start at cell (1, 1), and move right until you hit a wall, let's say at (5, 1). Then the cells (1, 1), (2, 1), (3, 1) and (4, 1) can all see each other along this slope, so although you started at (1, 1), there's no need to repeat the computation for the other 3 cells -- just add a copy of this list (or even a pointer to it, which is faster) to the visibility lists for all 4 cells. Keep heading right, and repeat the process as soon as you hit a non-wall. Then begin again on the next row.
Visibility checking for 45-degree diagonals is slightly harder, but not much, and checking for other slopes in which we advance 1 horizontally and some k vertically (or vice versa) is about the same. (Checking for for general slopes, like for every 2 steps right go up 3, is perhaps a bit trickier.)
Provided you use pointers rather than list copies, for a given slope, this approach spends amortised constant time per cell: Although finding the k horizontally-visible neighbours of some cell takes O(k) time, it means no further horizontal processing needs to be done for any of them. So if you check a constant number of slopes (e.g., the four I suggested), this is O(n) time overall to process n cells. In contrast, I think your current approach takes at least O(nq) time, where q is the average number of cells visible to a cell.
I'm making a telegram bot with c#.
I want to read a number of names (not more than 20 tough thy could be less) and give them to the user as keyboardMarkup. With a one dimensional array they go all in one line and it's unreadable. I wanted to make 4 line with 5 names so i tried a 4x5 array. But i get this error
Error CS0029 Cannot implicitly convert type 'NetTelegramBotApi.Types.KeyboardButton[,]' to 'NetTelegramBotApi.Types.KeyboardButton[][]'
if (text == "/lista")
{
// Read a text file line by line.
listapz = System.IO.File.ReadAllLines("listapz.txt");
string selezione = "Seleziona il paziente:";
int i = 0;
int x = 0;
int y = 0;
var arrays = new KeyboardButton[4,5];
for (i = 0; i < listapz.Length; i++)
{
y = i / 5;
x = i - (y * 5);
arrays[y,x] = new KeyboardButton("$" + (i + 1) + " " + listapz[i]);
selezione += "\n$" + (i + 1) + " " + listapz[i] + "";
}
var keyb = new ReplyKeyboardMarkup()
{
Keyboard = arrays,
OneTimeKeyboard = true,
ResizeKeyboard = true
};
var reqAction = new SendMessage(update.Message.Chat.Id, selezione) { ReplyMarkup = keyb };
bot.MakeRequestAsync(reqAction).Wait();
Console.WriteLine(reqAction);
continue;
}
any solution?
You can create new one dimensional array for every line
Then
keyb.row(first_array) //you need get only values in python it will like keyb.row(*array)
keyb.row(second_array) //and so on
and add all keyboards in one reply_markup=keyb
I have searched through many posts and cannot find what I need. I see solutions to find the closest number to a target but I need one that finds that number, then can select the closest number on the other side of a "parabola" shaped set of data that is not completely symmetrical. I essentially use:
List<int> list = new List<int> { 2, 5, 7, 10 };
int number = 9;
int closest = list.Aggregate((x,y) => Math.Abs(x-number) < Math.Abs(y-
number) ? x : y);
This is how I find my first target number. Now I need to find a second number that is almost equal in value but on the other side of a parabola (I really need the indexes of these numbers but I can put the pieces together). My methods keeps coming up a single number. Essentially I need to move to an approximately symmetric index across a parabola to select an equivalent number. To put this in context, I am calculating beam width, i.e. the distance between the sides of a parabola at a specific point. Please let me know if this makes sense and if I need to explain more before you down vote me. I have done extensive research and testing. It is difficult for me to provide more code because it is coming from a $500,000 testing system that does not have internet so I can't copy and paste my code. I can go the extra yard if more code is needed though, just trying to avoid compromising an expensive embedded Windows system.
Here is a related post that I need to go a step further from
located here
Edit adding full code:
fileName = textBox10.Text;
SetupControlState(true);
if (comboBox2.SelectedIndex == 0)
{
cent = false;
}
else if (comboBox2.SelectedIndex == 1)
{
cent = true;
}
testHPositions = new List<double>();
testHMeasurements = new List<double>();
testVPositions = new List<double>();
testVMeasurements = new List<double>();
double horzRange = Double.Parse(textBox12.Text);
double vertRange = Double.Parse(textBox11.Text);
double refGain = Double.Parse(textBox14.Text);
double stepSize = Double.Parse(textBox13.Text);
testBorePos = new double[1, 2];
_worker = new BackgroundWorker();
_worker.WorkerSupportsCancellation = true;
testBoreRun.Enabled = false;
button2.Enabled = true;
_worker.RunWorkerAsync();
_worker.DoWork += new DoWorkEventHandler((state, args) =>
{
// try
// {
dev1 = new VisaDevice("inst0", "TCPIP0::192.168.0.10::inst0::INSTR"); //textBox1.Text);
if (!cent)
{
Double startfreq = double.Parse(textBox2.Text) * 1000000000;
Double stopfreq = double.Parse(textBox1.Text) * 1000000000;
dev1.SendBlocking("FREQ:STAR " + startfreq.ToString(), true);
string responseFreq = "";
dev1.QueryBlocking("FREQ:STAR?", ref responseFreq, true);
dev1.SendBlocking("FREQ:STOP " + stopfreq.ToString(), true);
dev1.QueryBlocking("FREQ:STOP?", ref responseFreq, true);
}
else if (cent)
{
Double freq = double.Parse(textBox9.Text) * 1000000000;
Double span = double.Parse(textBox8.Text) * 1000000000;
dev1.SendBlocking("FREQ:CENT " + freq.ToString(), true);
string responseFreq = "";
dev1.QueryBlocking("FREQ:CENT?", ref responseFreq, true);
dev1.SendBlocking("FREQ:SPAN " + span.ToString(), true);
dev1.QueryBlocking("FREQ:SPAN?", ref responseFreq, true);
// this.InvokeEx(f => f.stringReadTextBox.AppendText("Spectrum Analyzer Connected" + Environment.NewLine));
}
string progID;
Util U = new Util();
progID = "ASCOM.iOptron.Telescope";
if (progID != "")
{
PauseClass pause;
pause = new PauseClass();
Telescope T = new Telescope(progID);
T.Connected = true;
pause.Pause(5000);
T.Tracking = false;
T.TargetDeclination = 1;
T.TargetRightAscension = 1;
this.InvokeEx(f => f.stringReadTextBox.AppendText(" Connected to " + progID + Environment.NewLine));
this.InvokeEx(f => f.stringReadTextBox.AppendText(" Connected to Spectrum Analyzer" + Environment.NewLine));
T.SlewToAltAz(180.00, 45 - vertRange);
double Alt = T.Altitude;
for (int i = 0; i < ((vertRange * 2) / stepSize) + 1; i++)
{
if (_worker.CancellationPending)
break;
T.SlewToAltAz(180, Alt + stepSize * i);
this.InvokeEx(f => f.stringReadTextBox.AppendText("Test Altitude = " +(T.Altitude - 45).ToString("F") + Environment.NewLine));
testVPositions.Add(T.Altitude);
dev1.SendBlocking("INIT", true); //Start single measurement
string respOPC = "", responseState = "", responseMarkerY = "";
dev1.QueryBlocking("*OPC?", ref respOPC, true); //Wait for operation complete
dev1.QueryBlocking("STAT:QUES:MEAS?", ref responseState, true); //Check State
dev1.QueryBlocking("CALC:MARK:Y?", ref responseMarkerY, true); // Get the result
this.InvokeEx(f => f.stringReadTextBox.AppendText(responseMarkerY + Environment.NewLine));
testVMeasurements.Add(Double.Parse(responseMarkerY));
if (testVMeasurements.Count > ((vertRange * 2) / stepSize))
{
this.InvokeEx(f => f.stringReadTextBox.AppendText("Vertical Scanning Is Complete!" + Environment.NewLine));
double maxVamp = testVMeasurements.Max();
int index2 = testVMeasurements.IndexOf(testVMeasurements.Max());
double maxVPos = testVPositions[index2];
testBorePos[0, 1] = maxVPos;
this.InvokeEx(f => f.stringReadTextBox.AppendText("Vertical Max Amplitude = " + maxVamp + Environment.NewLine));
this.InvokeEx(f => f.stringReadTextBox.AppendText("Vertical Position of Max Amplitude = " + (maxVPos - 45).ToString("F") + Environment.NewLine));
}
}
if (!_worker.CancellationPending)
{
T.SlewToAltAz(180.00 - horzRange, testBorePos[0, 1]);
}
double Az = T.Azimuth;
for (int i = 0; i < ((horzRange * 2) / stepSize) + 1; i++)
{
if (_worker.CancellationPending)
break;
if (vertRange > 20)
{
this.InvokeEx(f => f.stringReadTextBox.AppendText("Vertical Range Cannot Be Greater than +/- 20 Degreez" + Environment.NewLine));
break;
}
T.SlewToAltAz(Az + stepSize * i,testBorePos[0,1]);
this.InvokeEx(f => f.stringReadTextBox.AppendText("Test Azimuth = " + (T.Azimuth-180).ToString("F") + Environment.NewLine));
testHPositions.Add(T.Azimuth);
dev1.SendBlocking("INIT", true); //Start single measurement
string respOPC = "", responseState = "", responseMarkerY = "", responseMarkerX = "";
// string responseFreq = "";
dev1.QueryBlocking("*OPC?", ref respOPC, true); //Wait for operation complete
dev1.QueryBlocking("STAT:QUES:MEAS?", ref responseState, true); //Check State
dev1.QueryBlocking("CALC:MARK:Y?", ref responseMarkerY, true); // Get the result
dev1.QueryBlocking("CALC:MARK:X?", ref responseMarkerX, true); // Get the result
this.InvokeEx(f => f.stringReadTextBox.AppendText(responseMarkerY + Environment.NewLine));
testHMeasurements.Add(Double.Parse(responseMarkerY));
if (testHMeasurements.Count > ((horzRange * 2) / stepSize))
{
_worker.CancelAsync();
stop = false;
this.InvokeEx(f => f.testBoreRun.Enabled = true);
this.InvokeEx(f => f.button2.Enabled = false);
this.InvokeEx(f => f.stringReadTextBox.AppendText("Horizontal Scanning Is Complete!" + Environment.NewLine));
double maxHamp =testHMeasurements.Max();
int index =testHMeasurements.IndexOf(testHMeasurements.Max());
double maxHPos =testHPositions[index];
testBorePos[0, 0] = maxHPos;
this.InvokeEx(f => f.stringReadTextBox.AppendText("Horizontal Max Amplitude = " + maxHamp + Environment.NewLine));
this.InvokeEx(f => f.stringReadTextBox.AppendText("Horizontal Position of Max Amplitude = " +( maxHPos-180).ToString("F") + Environment.NewLine));
this.InvokeEx(f => f.stringReadTextBox.AppendText("Antenna Under Test Peak Amplitude located at (" + (testBorePos[0, 0] - 180).ToString("F") + " , " + (testBorePos[0, 1] - 45).ToString("F") + ")" + Environment.NewLine));
this.InvokeEx(f => f.SetupControlState(false));
T.SlewToAltAz(testBorePos[0, 0], testBorePos[0, 1]);
dev1.SendBlocking("INIT", true); //Start single measurement
maxAmpTest = new double();
string respOPC2 = "", responseState2 = "", responseMarkerY2 = "";
dev1.QueryBlocking("*OPC?", ref respOPC2, true); //Wait for operation complete
dev1.QueryBlocking("STAT:QUES:MEAS?", ref responseState2, true); //Check State
dev1.QueryBlocking("CALC:MARK:Y?", ref responseMarkerY2, true); // Get the result
maxAmpTest = Double.Parse(responseMarkerY2);
double target = maxAmpTest - 3;
Here is where I am stuck:
// int indexbeam = testHMeasurements.IndexOf(target);
// indexList = testHMeasurements.IndexOf(testHMeasurements.FindAll(s => s.Equals(target)).First());
double closest = testHMeasurements.Aggregate((x, y) => Math.Abs(x - target) < Math.Abs(y - target) ? x : y);
var result = Enumerable.Range(0, testHMeasurements.Count).Where(j => testHMeasurements[j] ==closest).ToList();
// int beamIndex1 = testHMeasurements.IndexOf(testHMeasurements.OrderBy(item => Math.Abs(target - item)).First());
// int beamIndex2 = testHMeasurements.IndexOf(testHMeasurements.OrderBy(item => Math.Abs((beamIndex1 + 1) - item)).First());
double beam1 =( testHPositions[result[0]]) - 180;
double beam2 = (testHPositions[result[1]]) - 180;
beamWidth = Math.Abs(beam1) + Math.Abs(beam2);
this.InvokeEx(f => f.stringReadTextBox.AppendText("Antenna Under Test Amplitude = " + responseMarkerY2 + Environment.NewLine));
this.InvokeEx(f => f.stringReadTextBox.AppendText(" Antenna Under Test Gain = " + (maxAmpTest - refAmp + refGain) + Environment.NewLine));
this.InvokeEx(f => f.stringReadTextBox.AppendText(" Antenna Under Test Beam Width = " +beamWidth.ToString("F") + Environment.NewLine));
testGain = maxAmpTest - refAmp + refGain;
}
}
T.Connected = false;
T.Dispose();
dev1.Dispose();
if (_worker.CancellationPending)
{
Save();
// Cleanup Excel resources
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
});
First, you must find the parabola. Because your data only approximates the parabola, you need a statistical method called Quadratic Regression, or Polynomial Regression to find the parameters a, b and c of the equation
y = ax2 + bx + c
defining the parabola, that best fits the dataset given by the points
(xi, yi)
Use a math library or google for an algorithm.
Once you have the parabola, determine the symmetry axis of it, i.e. find the x-value of where the minimum or maximum (if the parabola is upside down) of the parabola is.
xs = -b / 2a
Now, once you have a given x-value, you can find a point at the opposite side of the parabola by mirroring x at xs
x' = 2xs - x
This is the explanation for a parabola in 2-D. If you have a parabola in 3-D, i.e. a Paraboloid the principle remains the same, but with more complex math. Google for Paraboloid Regression. A parabolic antenna has a curved surface with the cross-sectional shape of a parabola, called a paraboloid in geometrical terms.
Only once you have solved the mathematical problems, you can start programming and finding points in lists.
Turns out this question could actually be solved through programming with no advanced math required. Given a y-value and asked to find two corresponding x values on an asymmetrical/parabola arc you can simply split the arc at the vertex in two pieces then scan each of the two arrays for the matching x-value. It works like a charm - just requires a little critical thinking and a lot less over thinking it (math major stuff :p)
Here's a small piece of the program I am working on. I am trying to manually resize the array by creating another array, copying all of the items from the first array into the second and then having the first array refer to the second.
RoundInfo[] rounds = new RoundInfo[10];
int numRounds = 0;
RoundInfo ri;
RoundInfo[] newRI;
public void AddRound(int height, int speed)
{
if (numRounds >= rounds.Length) // creates a new array of RI objects if numRounds is greater than rounds.Length
{
newRI = new RoundInfo[numRounds + 1];
// Console.WriteLine("numRounds: {0} length: {1}", numRounds, rounds.Length); // me checking if the AddRound correctly increments numRounds, it does.
//Console.WriteLine(newRI.Length);
for (int i = 0; i < newRI.Length; i++)
newRI[i] = rounds[i]; // *THE PROGRAM CRASHES HERE*
rounds = newRI;
ri = new RoundInfo(height, speed);
rounds[numRounds] = ri;
numRounds++;
}
if (numRounds < rounds.Length) // the program goes through this fine
{
ri = new RoundInfo(height, speed);
rounds[numRounds] = ri;
numRounds++;
}
}
I don't see why it crashes if the new array is longer.
because you're entering in first if when numRounds == rounds.Length.
where 10==rounds.Length(which is 10)
theng adding on
if (numRounds >= rounds.Length) // here you're having numRounds as 10
{
newRI = new RoundInfo[numRounds + 1]; //here you're adding + 1 will get newRI = new RoundInfo[11]
for (int i = 0; i < newRI.Length; i++)
newRI[i] = rounds[i]; // *THE PROGRAM CRASHES HERE*
// so in here your program will crash due to indexOutOfBOunds because newRI[11] = rounds[11];
//rounds[11] is not existing
rounds = newRI;
ri = new RoundInfo(height, speed);
rounds[numRounds] = ri;
numRounds++;
}
you may prevent this by not adding +1 on newRI
if (numRounds >= rounds.Length)
{
newRI = new RoundInfo[numRounds]; //remove +1 here
//etc codes
}
I don't know what is your intention in this part
// creates a new array of RI objects if numRounds is greater than rounds.Length
copying an array but exceeds previous array length is impossible. It seems you're trying to do (newArray[oldArray.Length + 1] == oldArray[oldArray.Length])
which you cannot do because it will really go out of bounds.
newArray[11] can't have oldArray[11] because it is not existing
what you may try is the length of oldArray, not the new
for (int i = 0; i < rounds.Length; i++)
newRI[i] = rounds[i];
So here is the problem. I'm working on a combat-simulator for an AI based game. The AI should calculate the best move for him when the enemy makes his best move against every move.
My team has X units with 5 possible moves and my opponent has Y units with 5 possible moves. X and Y > 0
using alpha-beta pruning we want to generate each possible outcome and take the best one out in the end. The problem is the fact that we save each outcome into a situation, this situation stores lists but the lists contain references to the objects stored, this makes them save their moves into the same situation (all 5 moves of 1 unit)
Imagine 2 of our units and one of theirs. We create a situation and add one unit with 1 of the 5 directions to it. Then for our second unit we add one direction, then for the enemy unit. Now we got the end situation we want to save this. Then from the situation we had in OUR second unit (so without the enemy unit) we want to add a different move for the enemy to the situation and save that new situation if it was better. But since C# uses references for lists this situation is the situation with the other enemy move included aswell.
Code is a bit large but I'm really stuck here so I'd hope if anyone has some spare time to help me out with ideas to fix this.
public Situation RecursiveMaxTree(List<SimAnt> undone, int index, bool[,] positions, Situation situation)
{
SimAnt front = undone[index];
int max = situation.Max;
List<SimAnt> bestmoves = new List<SimAnt>();
int frontY = front.position.Y;
int frontX = front.position.X;
if (!front.isEnemy() && undone[index + 1].isEnemy())//cutoff activated----------------------------------------------------------------------------
{
foreach (Direction direction in directions)
{
int newX = GameState.WrapHorizonal(frontX + direction.toVector().X);
int newY = GameState.WrapVertical(frontY + direction.toVector().Y);
if (!positions[newX, newY] && map.isNotWater(newX, newY))
{
//add the updated ant to the new allAnts list
positions[newX, newY] = true;
List<SimAnt> newallAnts = situation.GetList;
Friend newant = new Friend(newX, newY);
newant.direction = direction;
newallAnts.Add(newant);
Situation current = RecursiveMinTree(undone, index + 1, positions, new Situation(newallAnts, max));//geeft min van alle enemy options
positions[newX, newY] = false;
if (current.Max > max)
{
max = current.Max;
bestmoves = current.GetList;
}
}
}
}
else //max-------------------------------------------------------------------------------------------------------------------------------------
{
foreach (Direction direction in directions)
{
int newX = GameState.WrapHorizonal(frontX + direction.toVector().X);
int newY = GameState.WrapVertical(frontY + direction.toVector().Y);
if (!positions[newX, newY] && map.isNotWater(newX, newY))
{
//add the updated ant to the new allAnts list
positions[newX, newY] = true;
List<SimAnt> newallAnts = situation.GetList.Clone();
Friend newant = new Friend(newX, newY);
newant.direction = direction;
newallAnts.Add(newant);
Situation current = RecursiveMaxTree(undone, index + 1, positions, new Situation(newallAnts, max));//geeft min van alle enemy options
positions[newX, newY] = false;
if (current.Max > max)
{
max = current.Max;
bestmoves = current.GetList;
}
}
}
}
return new Situation(bestmoves, max);
}
Situation RecursiveMinTree(List<SimAnt> undone, int index, bool[,] positions, Situation situation)
{
SimAnt front = undone[index];
int max = situation.Max;
int frontY = front.position.Y;
int frontX = front.position.X;
int currentmin = 100;
foreach (Direction direction in directions)
{
int newX = GameState.WrapHorizonal(frontX + direction.toVector().X);
int newY = GameState.WrapVertical(frontY + direction.toVector().Y);
if (!positions[newX, newY] && map.isNotWater(newX, newY))
{
//add the updated ant to the new allAnts list
List<SimAnt> newallAnts = situation.GetList;
Foe newant = new Foe(newX, newY);
newallAnts.Add(newant);
if (index >= undone.Count - 1)
{
return new Situation(situation.GetList, CalculateBattleValue(situation.GetList));
}
else
{
positions[newX, newY] = true;
Situation current = RecursiveMinTree(undone, index + 1, positions, new Situation(newallAnts, max));//geeft min van alle enemy options
positions[newX, newY] = false;
if (current.Max < max)
return current;
else if (current.Max < currentmin)
{
currentmin = current.Max;
}
}
}
}
return new Situation(situation.GetList, currentmin);
}
class Situation
{
public Situation(List<SimAnt> ants, int max)
{
this.max = max;
this.ants = ants;
}
List<SimAnt> ants;
int max;
public List<SimAnt> GetList
{ get { return ants; } }
public int Max
{ get { return max; } }
}
Kind regards, me