Reputation: 9527
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.
Upvotes: 2
Views: 2636
Reputation: 16687
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:
state
variable should be private.state
array. Your Grid
class becomes Grid<T>
.[,]
overload, you can get rid of your at
and set
functions.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)
=> 0mod(1,10)
=> 1mod(-1,10)
=> 9mod(10,10)
=> 0mod(-10,10)
=> 0mod(11,10)
=> 1mod(-11,10)
=> 9Upvotes: 6
Reputation: 29244
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!
Upvotes: -1