具有“包裹边缘”的二维阵列在 C# 中
警告:我是 C# 新手。除了回答我的问题之外,如果您在看到我的代码后有任何一般性的提示,欢迎您提出。
假设我在 C# 中定义了一个大小为 10x10 的二维数组:
var arr = new int[10,10];
访问索引超出 0-9 范围的元素是错误的。在某些应用程序中(例如,一些二维数组代表一个世界的游戏),有必要“包裹”数组的边缘。例如,
arr[-1, 0]
实际上会引用 arr[9,0] 处的元素。
我一直在使用的一种方法是下面的课程。我没有子类化 System.Array 因为 C# 显然禁止这样做。
用法示例:
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)
类本身:
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...
}
问题:是否有提供此类类的游戏/创意编码框架?
问题:你能想到一个我可以在上面使用的更简单的mod
吗?
为了处理每个元素以及相应的“x”和“y”,我使用以下方法:
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]);
}
问题:我四处寻找在 System.Array 上定义的类似方法,但我没有找到一个。我错过了吗?
问题:在上面的代码中,for(int x = 0; x < width; x++)
是表达“从0到N乘1”的常见习语。有没有一种机制可以在 C# 中表达这一点?即我想将上面的内容写为:
width.up_to((x) =>
height.up_to((y) =>
proc(x, y, state[x, y]);
其中 up_to
是整数方法。是否已经定义了类似 up_to
的内容?
与Scheme 中的map
类似,这里有一个map
方法,它将Func
应用于每个元素及其相应的索引。它返回一个新的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;
}
问题:假设我设置了一个子类class World : Grid
,它添加了额外的实例变量。上述 map
的问题在于,当在 World
的实例上调用时,您会得到一个 Grid
,而不是 World
代码>.我应该如何解决这个问题?这是完全错误的做法吗?也许更好的设计是不子类化Grid
,而是将其保留为World
中的实例变量。
抱歉提交时间太长。 :-)
更新: 我分别询问了有关 upto
的问题,并得到了一些好的答案。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
为了方便对网格的引用,您可以做的一件事是重载
[,]
:如果您发现语法更合适,请使用它。
关于您的 mod 函数,我能提出的最佳建议是使这些变量(a 和 b)有意义。
index
和maxSize
应该这样做。其他内容:
state
变量应该是私有的。state
数组的类型。您的Grid
类将变为Grid
。[,]
重载,您可以摆脱at
和set
函数。示例:
mod
对任何值(多重环绕)有效。示例:
结果:
mod(0,10)
=> 0mod(1,10)
=>; 1mod(-1,10)
=>; 9mod(10,10)
=>; 0mod(-10,10)
=>; 0mod(11,10)
=>; 1mod(-11,10)
=>; 9One thing you can do to facilitate reference to your grid is overload
[,]
: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
andmaxSize
oughta do it.Other stuff:
state
variable should be private.state
array. YourGrid
class becomesGrid<T>
.[,]
overload, you can get rid of yourat
andset
functions.Example:
mod
can be made valid for any value (multiple wrap around) with a slight modification.Example:
Results:
mod(0,10)
=> 0mod(1,10)
=> 1mod(-1,10)
=> 9mod(10,10)
=> 0mod(-10,10)
=> 0mod(11,10)
=> 1mod(-11,10)
=> 9只需使用 modulo
%
函数访问数组即可。对于N
byM
数组,请使用以下内容。它会完全满足您的需要。在您的示例中,使用
arr[-1 % 10, 0 % 10]
而不是arr[-1,0]
。不需要包装函数或额外的代码!Just access the array with the modulo
%
function. For anN
byM
array use the following.it will do exactly what you need. In your example use
arr[-1 % 10, 0 % 10]
instead ofarr[-1,0]
. There is no need for a wrapper function, or additional code!