2d-array with "wrapped edges" in C# - c#

Warning: I'm a C# newb. Besides answering my questions, if you have any tips in general after seeing my code, they are welcome.
Let's say I define a two-dimensional array of size 10x10 in C#:
var arr = new int[10,10];
It is an error to access elements with indices out of the range 0-9. In some applications, (e.g. some games where the 2d-array represents a world) it's necessary to "wrap" the edges of the array. So for example
arr[-1, 0]
would actually refer to the element at arr[9,0].
One approach I've been using is the following class. I didn't subclass System.Array because C# apparently forbids doing so.
Example usage:
var grid = new Grid(10,10);
grid.set(-1, 0, 100); // Set element at (-1,0) to value 100.
grid.at(-1,0); // retrieve element at (-1,0)
The class itself:
class Grid
{
public int[,] state;
public int width { get { return state.GetLength(0); } }
public int height { get { return state.GetLength(1); } }
public Grid(int width_init, int height_init)
{
state = new int[width_init, height_init];
}
int mod(int a, int b)
{
if (a >= 0)
return a % b;
else
return (b + a % b) % b;
}
int wrap_x(int x) { return mod(x, width); }
int wrap_y(int y) { return mod(y, height); }
public int at(int x, int y)
{
return state[wrap_x(x), wrap_y(y)];
}
public void set(int x, int y, int val)
{
state[wrap_x(x), wrap_y(y)] = val;
}
// more stuff here...
}
Question: Is there a game/creative-coding framework out there that provides this sort of class?
Question: Can you think of a simpler mod I can use in the above?
In order to process each element along with the corresponding "x" and "y", I use the following method:
public void each(Action<int, int, int> proc)
{
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
proc(x, y, state[x, y]);
}
Question: I looked around for a similar method defined on System.Array but I didn't find one. Did I miss it?
Question: In the above, for(int x = 0; x < width; x++) is the common idiom expressing "go from zero up to N by 1". Is there a mechanism which expresses this in C#? I.e. I'd like to write the above as:
width.up_to((x) =>
height.up_to((y) =>
proc(x, y, state[x, y]);
where up_to would be a method on integers. Is there something like up_to already defined?
Similar to map from Scheme, here's a map method which applies a Func to each element and its corresponding indices. It returns a new Grid.
public Grid map(Func<int, int, int, int> proc)
{
var grid = new Grid(width, height);
each((x, y, val) => grid.state[x, y] = proc(x, y, val));
return grid;
}
Question: Let's suppose I setup a subclass class World : Grid which adds additional instance variables. The trouble with the above map is that when called on an instance of World, you get a Grid, not a World. How should I fix this? Is this the wrong approach altogether? Perhaps a better design is to not subclass Grid but to have keep it as an instance variable in World.
Sorry for the long submission. :-)
Update: I asked the question about upto separately and got some good answers.

One thing you can do to facilitate reference to your grid is overload [,]:
public int this[int x, int y]
{
get { return state[wrap_x(x), wrap_y(y)]; }
set { state[wrap_x(x), wrap_y(y)] = value; }
}
If you find the syntax more suitable, go for it.
Regarding your mod function, the best suggestion I can make is to make those variables (a and b) meaningful. index and maxSize oughta do it.
Other stuff:
Your state variable should be private.
Unless you absolutely, exclusively need ints, consider using a generic for the type of your state array. Your Grid class becomes Grid<T>.
With the bracket [,] overload, you can get rid of your at and set functions.
As for your World class, with a simplified Grid, the question to ask is this classic: is or has? IS your World a Grid or does it HAVE a Grid? Only you can answer that, but I'm leaning towards HAS.
Consider a Grid constructor which takes a ready-made 2d array as a parameter:
Example:
public Grid(int[,] state)
{
this.state = state;
}
mod can be made valid for any value (multiple wrap around) with a slight modification.
Example:
int mod(int index, int maxSize)
{
while (index < 0) index += maxSize;
return index % maxSize;
}
Results:
mod(0,10) => 0
mod(1,10) => 1
mod(-1,10) => 9
mod(10,10) => 0
mod(-10,10) => 0
mod(11,10) => 1
mod(-11,10) => 9

Just access the array with the modulo % function. For an N by M array use the following.
int x = A[i % N, j % M];
it will do exactly what you need. In your example use arr[-1 % 10, 0 % 10] instead of arr[-1,0]. There is no need for a wrapper function, or additional code!

Related

C# How to paste 2D array[,] onto second 2D array[,] on specified indexes

is there any better (less complex) way to paste the smaller array[,] to the bigger array[,] than looping through them? My code:
private void PasteRoomIntoTheMap(GameObject[,] room, (int, int) positionOnTheMap)
{
(int, int) roomSize = (room.GetLength(0), room.GetLength(1));
int roomsXAxesDimention = 0;
int roomsYAxesDimention = 0;
for (int i = positionOnTheMap.Item1; i <= positionOnTheMap.Item1 + roomSize.Item1; i++)
{
for (int j = positionOnTheMap.Item2; j <= positionOnTheMap.Item2 + roomSize.Item2; j++)
{
Map[i, j] = room[roomsXAxesDimention, roomsYAxesDimention];
roomsYAxesDimention++;
}
roomsXAxesDimention++;
}
}
(I didn't run it yet. There might be some errors but I hope that you will understand this method)
The code that I would love to have:
Map [5...15, 2...5] = room[0...room.GetLength(0), 0...room.GetLength(1)]
Short answer: No
Longer answer:
Multidimensional arrays are really a wrapper around a 1D array, with some special code to handle indices etc. It does however lack some useful features.
You could perhaps improve your example code a bit by copying entire columns or rows using Array.Copy or blockCopy instead of processing item by item. This might help performance if you have very many items that need copying, but is unlikely to make any difference if the sizes are small.
You could probably provide the syntax you desire by creating something like a ArraySlice2D class that reference the original 2D array as well as the region you want to copy. But you probably need to either create your own wrapper to provide index operators, or create extension methods to do it. Perhaps something like
public class My2DArray<T>{
private T[,] array;
public ArraySlice2D<T> this[Range x, Range y]{
get => new ArraySlice2D<T>(array, x, y);
set {
// Copy values from value.RangeX/Y to x/y ranges
}
}
You might also consider writing your own 2D array class that wraps a 1D array. I find that this often makes interoperability easier since most systems can handle 1D arrays, but few handle multidimensional arrays without conversion.
I am not aware of any shortcut for that and there might be to many slightly distinct usecase so that the most apropriate solution would be to implement your own functionality.
It is advisable however to add a size check to your method so you dont end up indexing nonexisting areas of the big array:
private bool ReplaceWithSubArray(int[,] array, int[,] subarray, (int x,int y) indices)
{
if (array.GetLength(0) < subarray.GetLength(0) + indices.x ||
array.GetLength(1) < subarray.GetLength(1) + indices.y)
{
// 'array' to small
return false;
}
for (int x = 0; x <= subarray.GetLength(0); x++)
{
for (int y = 0; y <= subarray.GetLength(1); y++)
{
array[x + indices.x, y + indices.y] = subarray[x, y];
}
}
return true;
}

Best way to choose two random ints to assign values to

I am creating a Dungeons and Dragons Character Creator. There is a randomize feature that is going to create a complete character sheet. There is a part that I have gotten to and I am not quite sure the best way to proceed.
The way I have the racial modifiers set up is with if statements. Here is an example.
if (raceInt == 0 || raceInt == 2 || raceInt == 10)
{
raceStrMod = 2;
}
if (raceInt == 3 || raceInt == 4 || raceInt == 5 || raceInt == 11 || raceInt == 12)
{
raceDexMod = 2;
}
However there are races that have modifiers that let you select two stats to add a modifier to, such as Strength or Dexterity. What would be the best way to select two random ints for just those races?
For example, the half-elf race which would get +2 to Dex and then +1 to two other random stats. So I need to find a way to randomly select two of the remaining ints to make the value = 1.
My race mod ints are initialized as
int raceStrMod = 0;
int raceDexMod = 0;
int raceConMod = 0;
int raceIntMod = 0;
int raceWisMod = 0;
int raceChaMod = 0;
Then the if statements assign a value dependent on which race was randomly selected.
Thank you all for the input! This is how I ended up coding it
if (raceInt == 9)
{
int randomX = rnd.Next(1, 5);
int randomY = rnd.Next(1, 5);
int attempts = 0;
while (randomX == randomY && attempts < 10)
{
randomY = rnd.Next(1, 5);
attempts++;
}
//if they are still not unique after 10 attempts
if (randomX == randomY)
{
if (randomX == 5)
randomY = 1;
else
randomY = randomX + 1;
}
int[] randomNumbers = { randomX, randomY };
foreach (int i in randomNumbers)
{
switch (i)
{
case 1:
raceStrMod = 1;
break;
case 2:
raceDexMod = 1;
break;
case 3:
raceConMod = 1;
break;
case 4:
raceIntMod = 1;
break;
case 5:
raceWisMod = 1;
break;
}
}
}
Has your class introduced you to enum types yet? If not, is there any restriction on your final project with respect to using language features that weren't taught in the class?
Your question is arguably too broad, as there are many different ways to address this sort of thing even in real-world code, and the classroom context introduces potential roadblocks that while might constrain the question, being unknown they make it impossible to know what answer is actually going to work for you.
That said…
Ignoring the classroom aspect and focusing only on the problem itself, I would use enum types and dictionaries for this sort of thing. For example:
enum Attribute
{
Strength,
Dexterity,
Constitution,
Charisma,
Intelligence,
Wisdom,
Count, // must always be last
}
Dictionary<Attribute, int> modifiers = new Dictionary<Attribute, int>();
Then you can pick a random attribute like (assuming you have a random variable referencing a Random object…don't make the classic newbie mistake of creating a new Random object every time you want to pick a new random number):
Attribute attributeToModify = (Attribute)random.Next((int)Attribute.Count);
And you can store that selection like:
modifiers[attributeToModify] = 1;
This can be used to store however many modifiers you like. You can encapsulate that in an object representing the character itself, or you could put it into a separate AttributeModifiers class. One advantage of doing the latter would be that if you have modifiers that come from different sources, you can track that in the character object as a list of AttributeModifier instances, each in turn keeping track of what the actual source of those modifiers are.
This just barely scratches the surface. As I noted, the question itself is fairly broad. But I strongly recommend using the available language features to ensure that your variables represent things in a type-specific way, rather than just using int values for things that aren't really integers, and to use collection classes that more correctly represent the semantics of what your code is intended to do.
Note that this also means you probably should have an enum type for the races. E.g.:
enum Race
{
Dwarf,
Elf,
HalfElf,
Halfling,
HalfOrc,
Human,
// etc.
}
And your chain of if statements is probably better represented as a switch:
Attribute racialMod;
switch (race)
{
case Human:
case Halfling:
// etc.
racialMod = Attribute.Strength;
break;
case Elf:
case HalfElf:
// etc.
racialMod = Attribute.Dexterity;
break;
}
modifiers[racialMod] = 2;
Something like that. The point is to make sure the code reads more like what the original specification would say (if you actually had written one). This will make the code easier to understand, and it will be less likely for you to put bugs in the code (e.g. you accidentally type the wrong magic, unnamed integer).
I am creating a Dungeons and Dragons Character Creator.
That's a fun beginner project; I did the same when I was learning to program.
I need to find a way to randomly select two of the remaining...
You need to find two distinct values, call then x and y. The solution you've arrived at is:
Generate x
Try to generate y ten times
If no attempt succeeded to find a distinct y, hard-code a choice.
That works, and you almost never have to use the hard-coded choice. But I thought you might be interested to know that there is an easier way to generate two distinct numbers. Let's suppose we want two distinct numbers from 0, 1, 2, 3 or 4. (Obviously if you want a different range, say, 1 through 5, you can solve that problem by generating two distinct numbers 0->4 and then adding one to each.)
The improved algorithm is:
Choose x between 0 and 4 as usual.
Choose n between 1 and 4.
y = (x + n) % 5;
Think about it this way. Suppose we make a list like this:
0, 1, 2, 3, 4, 0, 1, 2, 3
We randomly choose x from the first five entries on the list, and then we choose y by stepping forwards between 1 and 4 steps. Since the list does not repeat in one to four steps, we know that we'll get two unique elements. The math does the equivalent of that.
You could similarly have used % in your program:
if (randomX == 5)
randomY = 1;
else
randomY = randomX + 1;
could be written
randomY = randomX % 5 + 1
If you're unfamiliar with %, it is the remainder operator. It is the complement of the / operator. The rule is:
int x = whatever;
int y = whatever;
int r = x % y;
is the same as:
int r = x - (x / y) * y;
That is, it is the remainder when x is divided by y. Keep in mind that the remainder can be negative!
(Disclaimer: I don't love this option, but couldn't think of another way other than reflection which is even nastier)
You could define a class that masks the fact that all of the mods are stored as an array and therefore can be indexed using a random number.
Something like the following:
public class StatMods
{
public int RaceStrMod { get { return this.mods[0]; } set { this.mods[0] = value; } }
public int RaceDexMod { get { return this.mods[1]; } set { this.mods[1] = value; } }
public int RaceConMod { get { return this.mods[2]; } set { this.mods[2] = value; } }
public int RaceIntMod { get { return this.mods[3]; } set { this.mods[3] = value; } }
public int RaceWisMod { get { return this.mods[4]; } set { this.mods[4] = value; } }
public int RaceChaMod { get { return this.mods[5]; } set { this.mods[5] = value; } }
private readonly int[] mods;
private static readonly Random rand = new Random();
public StatMods()
{
this.mods = new int[6];
}
public void ApplyRandomMod(int modification)
{
this.mods[rand.Next(0, 6)] += modification;
}
}

In C#, what does a call to Sort with two parameters in brackets mean?

I recently came across an implementation of Djikstra's Shortest Path algorithm online and found the following call.
given a List of nodes of type int and a Dictionary of distances, of type , what does the following call mean
nodes.Sort((x, y) => distances[x] - distances[y]);
The full code is as follows:
public List<int> shortest_path(int start, int finish)
{
var previous = new Dictionary<int, int>();
var distances = new Dictionary<int, int>();
var nodes = new List<int>();
List<int> path = null;
foreach (var vertex in vertices)
{
if (vertex.Item1 == start)
{
distances[vertex.Item1] = 0;
}
else
{
distances[vertex.Item1] = int.MaxValue / 2;
}
nodes.Add(vertex.Item1);
}
while (nodes.Count != 0)
{
nodes.Sort((x, y) => distances[x] - distances[y]);
var smallest = nodes[0];
nodes.Remove(smallest);
if (smallest == finish)
{
path = new List<int>();
while (previous.ContainsKey(smallest))
{
path.Add(smallest);
smallest = previous[smallest];
}
break;
}
if (distances[smallest] == int.MaxValue)
{
break;
}
foreach (var neighbor in vertices[smallest].Item2)
{
var alt = distances[smallest] + neighbor.Item2;
if (alt < distances[neighbor.Item1])
{
distances[neighbor.Item1] = alt;
previous[neighbor.Item1] = smallest;
}
}
}
return path;
}
I searched for the answer a lot but there doesn't seem to be any clear explanation of what it means.
I do know that in general in LINQ, a call to Array.Select((x,i)=>...) means that x is the actual element in the array and i is the index of element x in the array, but this doesn't seem to be the case above.
Would appreciate any explanation thanks.
In C#, what does a call to Sort with two parameters in brackets mean?
You have this line of code:
nodes.Sort((x, y) => distances[x] - distances[y]);
You are not passing two parameters to the sort method but you are passing one parameter which is a delegate that takes 2 parameters. You are essentially doing the following but using a lambda notation:
var nodes = new List<int>();
nodes.Sort(SortIt);
And here is the SortIt method:
private int SortIt(int x, int y)
{
return distances[x] - distances[y];
}
Keep in mind if you did it using the above approach, distances will have to be a class level field so the SortIt method can access it. With lambda expressions, this is what you have, it will just capture the distances variable and this is called a closure. Read this article if you want to know what closures are.
Sorting is implemented by comparing two items at a time.
The two parameters in parentheses are the two items the callback function should compare.
List.Sort Method takes an optional comparison delegate as a comparer.
https://msdn.microsoft.com/en-us/library/w56d4y5z(v=vs.110).aspx
in your example:
(x, y) => distances[x] - distances[y]) is a delegate that Sort uses as a comparer.
if distances[x] - distances[y] < 0; x is bigger;
if distances[x] - distances[y] > 0; y is bigger;
if distances[x] - distances[y] > 0; both are even;
This method will sort the elements in the entire List using the specified System.Comparison.
Where System.Comparison is a delegate
public delegate int Comparison<in T>(
T x,
T y
)
Think of it like this, you are passing the sort method a way to decide which element in the array is a precedent to the other. The sort function will use the compare function you specified to determine the precedence of each element in the returned sorted list. Therefore this function will get two elements and it will return a value indicating the result of the precendence.
let x be the first argument and y the second argument.
x < y -> the function will return a number less than 0
x = y -> the function will return 0
x > y -> the function will return a number bigger than 0
In conclusion, this function you pass to the Sort method will help the Sort function to sort the array as you wish it should sort it.

Need help for search optimization

I am fairly new to programming and i need some help with optimizing.
Basically a part of my method does:
for(int i = 0; i < Tiles.Length; i++)
{
x = Tiles[i].WorldPosition.x;
y = Tiles[i].WorldPosition.y;
z = Tiles[i].WorldPosition.z;
Tile topsearch = Array.Find(Tiles,
search => search.WorldPosition == Tiles[i].WorldPosition +
new Vector3Int(0,1,0));
if(topsearch.isEmpty)
{
// DoMyThing
}
}
So i am searching for a Tile in a position which is 1 unit above the current Tile.
My problem is that for the whole method it takes 0.1 secs which results in a small hick up..Without Array.Find the method is 0.01 secs.
I tried with a for loop also, but still not great result, because i need 3 more checks for
the bottom, left and right..
Can somebody help me out and point me a way of acquiring some fast results?
Maybe i should go with something like threading?
You could create a 3-dimensional array so that you can look up a tile at a specific location by just looking what's in Tiles[x, y + 1, z].
You can then iterate through your data in 2 loops: one to build up Tiles and one to do the checks you are doing in your code above, which would then just be:
for(int i = 0; i < Tiles.Length; i++)
{
Tile toFind = Tiles[Tile[i].x, Tile[i].y + 1, Tile[i].z];
if (toFind != null) ...
}
You would have to dimension the array so that you have 1 extra row in the y so that Tiles[x, y + 1, z] doesn't cause an index-out-of-range exception.
Adding to Roy's solution, if the space is not continuous, as it might be, you could put a hashcode of WorldPosition (the x, y and z coordinates) to some good use here.
I mean you could override WorldPosition's GetHashCode with your own implementation like that:
public class WorldPosition
{
public int X;
public int Y;
public int Z;
public override int GetHashCode()
{
int result = X.GetHashCode();
result = (result * 397) ^ Y.GetHashCode();
result = (result * 397) ^ Z.GetHashCode();
return result;
}
}
See Why is '397' used for ReSharper GetHashCode override? for explanation.
Then you can put your tiles in a Dictionary<WorldPosition, Tile>.
This would allow for quickly looking up for dict[new WorldPosition(x, y, z + 1)] etc. Dictionaries use hashcode for keys, so it would be fast.
First, like #Roy suggested, try storing the values in an array so you can access them with x,y,z coordinates,
Another thing you could do is change the search to
Tile topsearch = Array.Find(Tiles,
search => search.WorldPosition.x == Tiles[i].WorldPosition.x &&
search.WorldPosition.y == (Tiles[i].WorldPosition.y + 1) &&
search.WorldPosition.z == Tiles[i].WorldPosition.z)
This might be faster as well, depending on how many fields your WorldPosition has

C# Look up dictionary

I'm currently trying to create a program that estimates location based on signal strength. The signal strength value is an int and then i need a lookup dictionary with ranges.
So I would have something like:
Signal Strenth Position
0-9 1
10-19 2
20-29 3
and then I would want to look up what position a signal strength relates to, for example 15 would relate to position 2.
I know I can just have a load of if statements but is there a good way to do this using some sort of lookup dictionary?
If you have arbitrary but consecutive ranges you can use an array of the upper bounds and perform a binary search to get the position:
// Definition of ranges
int[] ranges = new int[] { 9, 19, 29 };
// Lookup
int position = Array.BinarySearch(ranges, 15);
if (position < 0)
position = ~position;
// Definition of range names
string[] names = new string[] { "home", "street", "city", "far away" };
Console.WriteLine("Position is: {0}", names[position]);
Array.BinarySearch returns the index of the item in the array if it exists (array must be sorted obviously) or the bitwise inverted index where the item should be inserted to keep the array sorted.
What about :
int position = signalStrength / 10 + 1;
Kindness,
Dan
When you want to use Dictionary, you need at least some special key type to deal with the ranges. KeyType can be abstract and two derived types KeyTypeRange(int int) and KEyTypeSearch( int). Some special comparison logic must be implemented to compare an KeyTypeSearch with an KeyTypeRange.
SortedDictionary<KeyType,int> lookup = new Dictionary<int,int>();
lookup.Add( new KeyTypeRange(1,10),1);
lookup.Add( new KeyTypeRange(11,20),2);
lookup.Add( new KeyTypeRange(21,30),3);
lookup.TryGetValue( new KeyTypeSearch(15) );
It shows a possible solution to use different esearch keys and key values in dictionaries. But this seems to be Overkill for this problem. This problem is solved best by the BinarySearch solution.
Good is a function of purpose. All of the above solutions work well presuming that any given range is a small number of integers. Otherwise you may want to use whatever the real world math function is to determine your group. For instance, for the example given, your answer function would be x % 10 + 1; That'll run much faster than a dictionary.
You could do a Dictionary, where the first int is the signal strength and the second int is the position. You would need to add an entry for every value in the range (so, one for signal strength 0, position 1, signal strength 1, position 1, etc.), but it would be a very quick, single line lookup.
Something like:
Dictionary<int, int> values;
values = new Dictionary<int, int>();
values[0] = 1;
values[1] = 1;
...
values[29] = 3;
and then, to access it:
Console.WriteLine(values[27].ToString());
For future expansion i would do 2 dictionaries.
Just in case those rates change
so a
dictionary<string,dictionary<int,int>>
or just use custom classes
the string would be static strings like low med, high, then you can change the ranges in your foreach initilixing the initial values
One solution would be to use a simple list, where each position in the list represents a different position that you're scanning for. In code, it might look something like this (assuming that all position numbers are sequential):
** Note: I have not actually run this code to make sure it works as-is... you might also need to implement an IEqualityComparer on Range in order for the IndexOf operation to return the proper position:
public class Controller
{
List m_positions = new List();
public void LoadPositions()
{
m_positions.Add(new Range(0, 9));
m_positions.Add(new Range(10, 19));
m_positions.Add(new Range(20, 29));
}
public int GetPosition (int signal)
{
Range range = m_positions.Single(a => IsBetween(signal, a.Min, a.Max));
return m_positions.IndexOf(range);
}
private static bool IsBetween (int target, int min, int max)
{
return min = target;
}
}
It's probably pretty self-explanatory, but to avoid any confusion, here's what the Range class might look like:
public class Range
{
public Range(int min, int max)
{
this.Min = min;
this.Max = max;
}
public int Min
{
get;
private set;
}
public int Max
{
get;
private set;
}
}
if there is a direct correlation between signal range and the position then use what #agileguy suggested.
If you have positions distributed non linearly across the signal strength then one way would be:
class SignalStrengthPositionMapper
{
private static readonly int[] signalStrength = { Int32.MinValue, 0, 5, 11, 15, 20, 27, 35 };
public static int GetPosition(int strength)
{
return StrengthSearch(0, signalStrength.Length, strength);
}
// modified binary search
private static int StrengthSearch(int start, int end, int strength)
{
int mid = 0;
while (start <= end)
{
mid = (start + end) / 2;
if (strength >= signalStrength[mid]) // lower bound check
{
start = mid + 1;
if (strength < signalStrength[start]) // upper bound check
return mid;
}
else if (strength < signalStrength[mid]) // upper bound check
{
end = mid - 1;
if (strength >= signalStrength[end]) // lower bound check
return mid;
}
}
return 0;
}
}
Try using generics:
Dictionary<int,int> lookup = new Dictionary<int,int>();
lookup.Add(0,1);
lookup.Add(1,1);
lookup.Add(2,1);
lookup.Add(3,1);
...
lookup.Add(9,1);
lookup.Add(10,2);
lookup.Add(11,2);
etc
Then, lookup[22] would return value of 3. I suggest using a set of loops to create your 'ranges'. With this method, you're guaranteed O(1) access time.

Categories

Resources