c# - C# 中带有 "wrapped edges"的二维数组

标签 c# arrays multidimensional-array subclass

警告:我是 C# 新手。除了回答我的问题之外,如果您在看到我的代码后有任何一般性的提示,我们也欢迎。

假设我在 C# 中定义了一个大小为 10x10 的二维数组:

var arr = new int[10,10];

访问索引超出 0-9 范围的元素是错误的。在某些应用程序中(例如,一些二维数组代表一个世界的游戏),有必要“包裹”数组的边缘。例如

arr[-1, 0]

实际上会引用 arr[9,0] 处的元素。

我一直在使用的一种方法是以下类(class)。我没有子类化 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# 中表达这一点? IE。我想将上面的内容写成:

width.up_to((x) =>
    height.up_to((y) =>
        proc(x, y, state[x, y]);

哪里up_to将是一个整数方法。有类似up_to的东西吗?已经定义了吗?

类似于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 的问题分别得到了一些good answers .

最佳答案

为了方便引用网格,您可以做的一件事是过载 [,] :

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; }
}

如果您发现语法更合适,请使用它。

关于您的mod函数,我能提出的最好建议是让这些变量(a 和 b)有意义。 indexmaxSize应该这样做。


其他内容:

  • 您的state变量应该是私有(private)的。
  • 除非您绝对需要整数,否则请考虑对 state 的类型使用泛型大批。您的Grid类变为Grid<T> .
  • 带支架[,]重载,你可以摆脱你的atset功能。
  • 对于您的世界级,使用简化的网格,要问的问题是这个经典的问题:是还是有?你的世界是网格还是有网格?只有你可以回答这个问题,但我倾向于“HAS”。
  • 考虑一个 Grid 构造函数,它将现成的二维数组作为参数:

示例:

public Grid(int[,] state)
{
    this.state = state;
}
  • mod只需稍作修改即可使其对任何值(多重环绕)有效。

示例:

int mod(int index, int maxSize)
{
    while (index < 0) index += maxSize;
    return index % maxSize;
}

结果:

  • 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

关于c# - C# 中带有 "wrapped edges"的二维数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8162100/

相关文章:

c# - 使用 DI/autofac 避免嵌套服务定位器反模式

c# - 为什么当我们以编程方式更改其文本时,TextBox 的 Text_Changed 事件不会触发?

c++ - 具有int变量乘法的int数组给出错误的结果c++

javascript - 如何检查字符串是否是带有indexof的子字符串[JAVASCRIPT]

c - 尝试按 ASCII 值升序比较二维数组中的字符串

c# - 使用自定义 InputSelect 中的 Blazor 验证消息的模型显示名称

c# - 从 PDF 表单添加到 MSSQL

javascript indexOf() 不断返回-1

Java:在二维数组中搜索单词

java - 二维数组对角线和