Unity 2D Jagged Array , Array index is out of range - c#

I have this 2D Array which is giving me a Array index is out of range, problem. What is the cause of this problem and how can i solve this ?
EDIT: Yep, sorry about that. I will include what i will want to do here:
So im trying to make jagged array which.
So i have a number of platforms, numOfPlatforms
I want to go through them, and each platform has its Size which is randomXSize.
And now, i want mark a point in each platform which is every 0.5, thats why i made
(randomXSize - 0.5)
But i don't know how many times i will need to do that for so i made
randomXSizeSegments = randomXSize * 2;
To calculate how many 0.5 will be for each randomXSize.
So in other words,
If the first platform '0' has a randomXSize of 3
I want the array randomXSizeSegments to be looking like this
randomXSizeSegments[1][0] = 3
randomXSizeSegments[0][1] = 2.5
randomXSizeSegments[0][2] = 2
randomXSizeSegments[0][3] = 1.5
randomXSizeSegments[0][4] = 1
randomXSizeSegments[0][5] = 0.5
randomXSizeSegments[0][6] = 0
And if second platform '1' has a randomXSize of 7
I want the array randomXSizeSegments to be looking like this
randomXSizeSegments[1][0] = 7
randomXSizeSegments[1][1] = 6.5
randomXSizeSegments[1][2] = 6
randomXSizeSegments[1][3] = 5.5
randomXSizeSegments[1][4] = 5
randomXSizeSegments[1][5] = 4.5
randomXSizeSegments[1][6] = 4
randomXSizeSegments[1][7] = 3.5
randomXSizeSegments[1][8] = 3
randomXSizeSegments[1][9] = 2.5
randomXSizeSegments[1][10] = 2
randomXSizeSegments[1][11] = 1.5
randomXSizeSegments[1][12] = 1
randomXSizeSegments[1][13] = 0
void Debugging_One() {
for(int a = 0; a < numOfPlatforms; a = a + 1) {
randomXPosSegments = new int[a][];
randomXSizeSegments = randomXSize * 2;
//Debug.Log(a);
//Debug.Log(randomXSizeSegments);
for(int b = 0; b < randomXSizeSegments; b = b + 1) {
// randomXPosSegments[a][b] = 0;
randomXPosSegments[a] = new int[] {(int)(randomXSize - 0.5)};
//Debug.Log(b);
}
}
}

In the first iteration of your outer for-loop, randomXPosSegments = new int[a][] creates an "empty" array since a = 0. When you then try to access the "0th" (i.e. first) element of that array, it throws that exception since there isn't a position [0] to access.
To create an array with one element, you need to declare it to have a size of 1:
var singleElementArray = new int[1];
singleElementArray[0] = 42;
Debug.WriteLine(singleElementArray[0]); // Prints '42'
If you give it a size of 0. There isn't a "0th" position that exists to assign to:
var singleElementArray = new int[0];
singleElementArray[0] = 42; // Throws IndexOutOfRangeException
I'm not sure how to help you solve this since you haven't explained what you are trying to accomplish and existing code doesn't make sense (e.g. you have an iterator b you never use, you keep on setting randomXPosSegments[a] to a new empty array).
Edit:
A few things first:
To store decimal values like 0.5, randomXPosSegments will need to be an array of double instead of int. We also need to create this outside the loop, or we'll keep creating a new empty array on each iteration. Like wise, you need to initialize randomXPosSegments[a] outside the inner for-loop or you'll just reset it each time.
I created a GetRandomXSize() function, since right now it's value never changes.
Inside the inner for-loop, I'm using randomXSize - (0.5 * b) to get values like 7, 6.5, .... b will start off as 0, so on the first iteration, it will just be randomXSize. Then it'll subtract a 0.5 for each time it's been through the loop.
To get 0 as the last result inside the jagged array, I had to change the condition on the inner for-loop to b <= randomXSizeSegments and make sure I initialize it to be big enough to fit the results (notice the +1 in new double[randomXSizeSegments + 1]).
Here's the code that works for me.
var randomXPosSegments = new double[numOfPlatforms][];
for(int a = 0; a < numOfPlatforms; a = a + 1) {
var randomXSize = GetRandomXSize();
var randomXSizeSegments = randomXSize * 2;
randomXPosSegments[a] = new double[randomXSizeSegments + 1];
for(int b = 0; b <= randomXSizeSegments; b = b + 1) {
randomXPosSegments[a][b] = randomXSize - (0.5 * b);
}
}

Related

I need help finding an easier way of going through an exponentially growing list to find the total count of lanternfish for advent of code

So I'm currently working on a advent of code answer display. This code is a bit chunky. I want to know if anyone by chance knew a simpler way of writing the code?
(Day 6 - year 2021 - Adventofcode)
The data is the following: 3,4,3,1,2
And the following is the expected answer: 26984457539
public static List<string> Star()
{
StreamReader sr = new("./Data/2021/Day06.txt");
string data = sr.ReadToEnd();
sr.Close();
List<int> allLanternCycle = Array.ConvertAll(data.Split(","), int.Parse).ToList();
for (int i = 0; i < 256; i++)
{
for (int j = 0; j < allLanternCycle.Count; j++)
{
if (allLanternCycle[j] == 0)
{
allLanternCycle[j] = 7;
allLanternCycle.Add(9);
}
allLanternCycle[j]--;
}
}
return new List<string>() { "", "true" };
}
Each lanternfish only has 9 possible states, 1 of which "resets" immediately, so you only need to keep track of how many lanternfish are in each of the remaining 8 states at any given time.
That means you only need an array of 8 counters to solve the problem of keeping a count of them all:
var fishPerState = new long[8];
foreach(int state in Array.ConvertAll(data.Split(","), int.Parse))
{
fishPerState[state - 1]++;
}
Now that we have a tracking mechanism, we need a way to advance the program. Every day, each fish changes to a state lower (eg. 8 -> 7), except for fish in state 1, which will "reset and repopulate":
for (int i = 0; i < 256; i++)
{
// move all fish in states 2-8 to one state lower
var temp = new long[8];
Array.Copy(fishPerState, 1, temp, 0, 7);
// reproduce
temp[7] = fishPerState[0];
// reset
temp[5] += fishPerState[0];
// assign new state counts to array variable
fishPerState = temp;
}
Now you don't need to worry about memory constraints, as you only ever use 128 bytes (8 longs * 8 bytes * 2 arrays) of memory regardless of how many lanternfish you count.
If the target count exceeds the capacity of a long (2^63-1), use the BigInteger type for the array elements instead :)

How to create unique pairs of numbers

I'm trying to create some pairs of unique numbers using pretty simple algorithm.
For some unknown reason after compiling Unity goes into an endless "not responding" state. Seems like it's stuck in a do..while loop, but I don't see any reason for that.
//Creating two lists to store random numbers
List<int> xList = new List<int>();
List<int> yList = new List<int>();
int rx, ry;
for(int i = 0; i < 10; i++)
{
// look for numbers until they are unique(while they are in lists)
do
{
rx = rand.Next(0, width);
ry = rand.Next(0, height);
}
while(xList.Contains(rx) || yList.Contains(ry));
//add them to lists
xList.Add(rx);
yList.Add(ry);
Debug.Log(rx + ", " + ry);
// some actions with these numbers
gridArray[rx,ry].isBomb = true;
gridArray[rx,ry].changeSprite(bombSprite);
}
As mentioned the issue is that once all unique numbers have been used once you are stuck in the do - while loop.
Instead you should rather simply
generate the plain index lists for all possible pairs.
I will use the Unit built-in type Vector2Int but you could do the same using your own struct/class
For each bomb to place pick a random entry from the list of pairs
Remove according random picked item from the pairs so it is not available anymore in the next go
Something like
// create the plain pair list
var pairs = new List<Vector2Int>(width * height);
for(var x = 0; x < width; x++)
{
for(var y = 0; y < height; y++)
{
pairs.Add(new Vector2Int(x,y));
}
}
// so now you have all possible permutations in one list
if(pairs.Count < BOMB_AMOUNT_TO_PLACE)
{
Debug.LogError("You are trying more bombs than there are fields in the grid!");
return;
}
// Now place your bombs one by one on a random spot in the grid
for(var i = 0; i < BOMB_AMOUNT_TO_PLACE; i++)
{
// now all you need to do is pick one random index from the possible entries
var randomIndexInPairs = Random.Range(0, pairs.Count);
var randomPair = pairs[randomIndexInPairs];
// and at the same time remove the according entry
pairs.RemoveAt(randomIndexInPairs);
// Now you have completely unique but random index pairs
var rx = randomPair.x;
var ry = randomPair.y;
gridArray[rx, ry].isBomb = true;
gridArray[rx, ry].changeSprite(bombSprite);
}
Depending on your use-case as alternative to generate the pairs list and then remove entries again you could also generate it once and then use
if(pairs.Count < BOMB_AMOUNT_TO_PLACE)
{
Debug.LogError("You are trying more bombs than there are fields in the grid!");
return;
}
var random = new System.Random();
var shuffledPairs = pairs.OrderBy(e => random.Next());
for(var i = 0; i < BOMB_AMOUNT_TO_PLACE; i++)
{
// then you can directly use
var randomPair = shuffledPairs[i];
// Now you have completely unique but random index pairs
var rx = randomPair.x;
var ry = randomPair.y;
gridArray[rx, ry].isBomb = true;
gridArray[rx, ry].changeSprite(bombSprite);
}
Although your algorithm is maybe not the best way to generate ten bombs in a grid, it should work.
The problem is that your while condition is using a OR statement, which means that if you have a bomb in the first line (in any column), it will not be able to add another bomb in that line.
Therefore you will pretty soon end up with an infinite loop because for every bomb you lock the line and column.
If you put an AND condition, you make sure the pair is unique because you lock only that cell.
Provided of course that width x height is more than ten.

How can I implement nested loop with inner loop using index of outer loop index as base for incrementation in R?

How do I implement in R a nested loop that has the inner loop using the outer loop index. Here is the sample of the code I wrote in C#:
int[] days = [1,2,3,4,5,6,7,8,9,10];
int[] amounts = [100, 0, 300, 0 , 0 , 500 , 0 , 600, 0, 1000];
void interpolation(int[]days, int[]amounts){
//start with 1 to avoid amounts[0] is 0 will throw loop out of bound, same for amounts.length()-1
for (int x = 1; x < amounts.length()-1; x++){
if (amounts[x] == 0){
int lastAval = amounts[x-1];
int lastDay = days[x-1];
int nextAval, nextDay;
for (int y = x; y < amounts.length()-1; y++) {
if(amounts[y] != 0) {
nextAval = amounts[y];
nextDay = amounts[y];
break;
}
}
amounts[x] = lastAval + (days[x] - lastDay) * ((nextAval-lastAval)/(nextDay-lastDay));
}
}
}
The purpose of this function is to find and replace any array element that equal to 0 with interpolation. I tried to apply the same function into R and I can't seem to find a way to translate this from C# into R as I unable to find a way to iterate through the R vector and using the index from outer loop and assign it to the inner loop for iterating.
If you want to implement your linear interpolation objective in R, you can try the code below
Using approxfun()
# define the linear interpolation function `interpl`, using `approxfun` given non-zero value pairs
interpl <- approxfun(days[amounts!=0], amounts[amounts!=0])
then run interpl with your input days
amounts <- interpl(days)
or
amounts[amounts == 0] <- interpl(days[amounts == 0])
Using approx()
amount[amounts==0] <- approx(x = days[amounts!=0],
y = amounts[amounts!=0],
xout = days[amounts==0])$y
such that
> amounts
[1] 100.0000 200.0000 300.0000 366.6667 433.3333 500.0000 550.0000 600.0000 800.0000 1000.0000

compare two items in list, and then split into smaller list at index

So i have a list of locations. I need to split the list if the distance between each location is greater than say 30.
I can loop through the list and get the distance between each location, i am just not sure what the best approach is to split the list, i have read answers that break the list into chunks with a set size, but in my case the size could be variable depending on the distance between locations.
This could be really simple and i just cant see it. What i have so far is below, the code is pretty straightforward in comparing the two items, its purely splitting the list i am stuck at. Currently my code would not include all the items from the original list, it would exclude the items before the first GetRange.
var unkownSegments = grouped.Where(x => x.ActivityType == null);
foreach (var group in unkownSegments)
{
var tempLists = new List<List<LocationResult>>();
for (int i = 0; i < group.Items.Count - 1; i++)
{
var point1 = group.Items[i];
var point2 = group.Items[i + 1];
var sCoord = new GeoCoordinate(point1.Lat, point1.Long);
var eCoord = new GeoCoordinate(point2.Lat, point2.Long);
var distance = sCoord.GetDistanceTo(eCoord);
if(distance > 30)
{
var tempList = group.Items.GetRange(i, group.Items.Count - i);
tempLists.Add(tempList);
}
}
}
Thank you for any help or suggestions.
To create a range (using GetRange() method), you need to know where it begins and where it ends. If distance between Item[i] and Item[i+1] is greater then 30, you know the end, because that end is at index i. But you don't know the beginning (of course, you know it for the first range - it's 0), because beginning depends on the end of previous range. So you need to introduce new variable (it's called rangeStart in my example bellow), that will contain such information. It starts with value 0 (that's where first range always begins) and then update it's value whenever you add new range (next range will always start at index i+1).
After the for loop finishes, some points will remain. So need to add them points as the last range. Whole method can then look like this:
var unkownSegments = grouped.Where(x => x.ActivityType == null);
foreach (var group in unkownSegments)
{
var tempLists = new List<List<LocationResult>>();
//This variable keeps track of the beginning of the next range
var rangeStart = 0;
for (int i = 0; i < group.Items.Count - 1; i++)
{
var point1 = group.Items[i];
var point2 = group.Items[i + 1];
var sCoord = new GeoCoordinate(point1.Lat, point1.Long);
var eCoord = new GeoCoordinate(point2.Lat, point2.Long);
var distance = sCoord.GetDistanceTo(eCoord);
if(distance > 30)
{
var tempList = group.Items.GetRange(rangeStart, i - rangeStart + 1);
tempLists.Add(tempList);
rangeStart = i + 1;//Next range will begin on the following item
}
}
if (group.Items.Count - rangeStart > 0)
{
//Add all remainging (not added yet) points as the last range.
var tempList = group.Items.GetRange(rangeStart, group.Items.Count - rangeStart);
tempLists.Add(tempList);
}
}

Sum value to previous value in array

What I'm doing wrong? What I'm trying to do is to add to existing array linesLat values but for next value to insert in linesLat is to take previous from array and summ stepLong. But at the end getting error.
static void Main(string[] args)
{
var stepLong = (10.6237 - 5.9216) / 1000;
var stepLat = (47.7245 - 45.7368) / 1000;
double[] linesLat = { 45.7368 };
double[] linesLong = { 5.9216 };
for (var i = 1; i <= 999; )
{
linesLat[i] = linesLat[i - 1] + stepLat; // throws an error
i++;
}
}
Additional information: Index was outside the bounds of the array.
You should really go back to basics.
Array as a limited size and it will be on the exact size you declare it to be.
In your case you allocated two arrays in the size of 1 (Due to explicit initialization).
double[] linesLat = { 45.7368 }; // Size 1
double[] linesLong = { 5.9216 }; // Size 1
Meaning you can't loop from [0, 999], when you will try to take the value from position 1 (Because C# arrays are zero based; The first element is in the 0 place and not 1) you will get a KABOOM meaning you will get an exception telling you, your index (probably 1) is outside of the legal array bounds.
Solution: You should change your solution to declare a bigger array as #i_a_joref suggested.
var linesLat = new double[1000];
linesLat[0] = 45.7368;
Additionally, your loop can be written more properly:
for (var i = 1; i < linesLat.Length; i++)
{
linesLat[i] = linesLat[i - 1] + stepLat;
}
Possible solution variation for your problem.
If the only goal is to get the sum of the last formula, than array is redundant.
double sumOfFormula = 45.7368;
for (var i = 0; i < 1000; i++) // Will run [0, 999] 1000 iterations
{
sumOfFormula += stepLat;
}
Console.WriteLine("Sum: ", sumOfFormula);
You declared linesLat as an array of size one. If you want to put 999+ elements in it, you need to declare a bigger array.
Your array has a lenght of 1, and you try to iterate up to 999.
You need to instanciate your array with a lengh of 999
double[] linesLat = new double[999];
Your array have size of 1 and in for loop you are trying to access indexes greater then array size.
Just change:
double[] linesLat = { 45.7368 };
to:
double[] linesLat = new double[1000];
linesLat[0] = 45.7368;

Categories

Resources