内容:

最近,我一直在从事几个简单的WPF项目,以更加熟悉C#和XAML。它们主要是对诸如Minesweeper,Centipede和Pong之类的旧游戏或简单游戏的娱乐。我决定通过重新创建SEGA Genesis游戏《致命迷宫》来提高赌注,但在迷宫游戏的开发中遇到了障碍。

该程序通过生成<Cell>列表来工作,该列表是我制作的一个类,它将用作跟踪实体,播放器和迷宫本身位置的基础。我遇到的第一个问题是2D列表的变化无常,因此我决定解决该问题的最简单方法是创建自己的通用类型Grid<T>,该类型由其维度,分别用于X和Y的int和一个List组成。 GridItem<T>GridItem<T>是其自己的通用类。

GridItem<T>包含其位置,该位置由代表其在网格中位置的X和Y坐标给出(不要与Grid的X和Y尺寸相混淆,后者代表Grid的实际大小)和实际位置T类型的项目

问题
如果可以在网格的一个成员中以这种方式在GridItem中包含HasTop / HasNorth布尔值以及TopNeighbor / NorthNeighbor(自然所有类型均为T),那将非常方便。直接与其邻居建立联系,而不必首先确认它甚至有邻居,然后执行查询以获取其邻居。另一个问题是,当我在GridItem中设置一个项目时,我不得不再次通过Linq执行查找,然后进行设置。虽然我可以使用Linq,并且可以使用它,但查看和编写它非常笨拙。

尝试的解决方案
我尝试的第一个解决方案是仅在GridItem中的每个方向放置一个邻居,但是问题是实际网格中的GridItem和存储为邻居的GridItem不会彼此更新。

随之而来的下一个自然解决方案是,在它们的get和set方法中包含一些可以适当更新它们的东西,并且链自然会从那里跳出来。问题是只能以一种方式工作,因为GridItem不知道它是成员的Grid

很好,接下来我要尝试的是将Grid属于GridItem成员的GridItem作为名为Parent的属性。不幸的是,这造成了“我是我自己的爷爷问题”,并且遇到了与先前尝试的解决方案相同的波动和递归问题。

我正在寻找答案

如何使GridItem知道相邻的GridItem,使得它们既可以获取和设置它们又无需创建递归更新或“我是我自己的祖父”

奖金

另外,如果有人可以告诉我如何使T仅可接受为可空类型。例如,我希望它允许诸如Cell之类的东西可以返回为null,但不允许Int或Bool这样的东西不能为null

编辑:
有些人要求提供代码,因此这里是:

public class Grid<T> where T : new()
{
    #region Constructors
    public Grid() { }
    public Grid(List<T> input, int RowLength, int ColumnLength)
    {
        XDimension = RowLength;
        YDimension = ColumnLength;
        int x = 0;
        int y = 0;
        input = input.Take(RowLength * ColumnLength).ToList();
        foreach (T item in input)
        {
            Items.Add(new GridItem<T> { Item = item, Position = new Coordinate { X = (UInt32)x, Y = (UInt32)y } });
            x += 1;
            if (x >= RowLength)
            {
                y += 1;
                x = 0;
            }
        }
        for (int i = 0; i < RowLength * ColumnLength - Items.Count; i++)
        {
            Items.Add(new GridItem<T> { Item = new T(), Position = new Coordinate { X = (UInt32)x, Y = (UInt32)y }, SystemGenerated = true });
            x += 1;
            if (x >= RowLength)
            {
                y += 1;
                x = 0;
            }
        }
    }
    #endregion
    public enum NeigborSelectionEnum { Top, Bottom, Left, Right };
    private List<GridItem<T>> items = new List<GridItem<T>>();
    private int xDimension;
    private int yDimension;
    public List<GridItem<T>> Items
    {
        get
        {
            return items;
        }

        set
        {
            items = value;
        }
    }
    public int XDimension
    {
        get
        {
            return xDimension;
        }

        set
        {
            xDimension = value;
        }
    }
    public int YDimension
    {
        get
        {
            return yDimension;
        }

        set
        {
            yDimension = value;
        }
    }
    public T NeighborOf(NeigborSelectionEnum selectedNeighbor, Coordinate position)
    {
        switch (selectedNeighbor)
        {
            case NeigborSelectionEnum.Top:
                if (position.Y > 0)
                {
                    return Items.FirstOrDefault(n => n.Position.X == position.X && n.Position.Y == position.Y - 1).Item;
                }
                return default(T);
            case NeigborSelectionEnum.Bottom:
                if (position.Y + 1 < YDimension)
                {
                    return Items.FirstOrDefault(n => n.Position.X == position.X && n.Position.Y == position.Y + 1).Item;
                }
                return default(T);
            case NeigborSelectionEnum.Left:
                if (position.X > 0)
                {
                    return Items.FirstOrDefault(n => n.Position.X == position.X - 1 && n.Position.Y == position.Y).Item;
                }
                return default(T);
            case NeigborSelectionEnum.Right:
                if (position.X + 1 < XDimension)
                {
                    return Items.FirstOrDefault(n => n.Position.X == position.X + 1 && n.Position.Y == position.Y).Item;
                }
                return default(T);
            default:
                return default(T);
        }
    }
    public T NeighborOf(NeigborSelectionEnum selectedNeighbor, GridItem<T> item)
    {
        UInt32 x = item.Position.X;
        UInt32 y = item.Position.Y;
        switch (selectedNeighbor)
        {
            case NeigborSelectionEnum.Top:
                if (y > 0)
                {
                    return Items.FirstOrDefault(n => n.Position.X == x && n.Position.Y == y - 1).Item;
                }
                return default(T);
            case NeigborSelectionEnum.Bottom:
                if (y + 1 < YDimension)
                {
                    return Items.FirstOrDefault(n => n.Position.X == x && n.Position.Y == y + 1).Item;
                }
                return default(T);
            case NeigborSelectionEnum.Left:
                if (x > 0)
                {
                    return Items.FirstOrDefault(n => n.Position.X == x - 1 && n.Position.Y == y).Item;
                }
                return default(T);
            case NeigborSelectionEnum.Right:
                if (x + 1 < XDimension)
                {
                    return Items.FirstOrDefault(n => n.Position.X == x + 1 && n.Position.Y == y).Item;
                }
                return default(T);
            default:
                return default(T);
        }
    }
}


这是GridItem

public class GridItem<T> where T : new()
{
    private T item;
    private Coordinate position;
    private bool systemGenerated = false;
    public T Item
    {
        get
        {
            return item;
        }

        set
        {
            item = value;
        }
    }
    public Coordinate Position
    {
        get
        {
            return position;
        }

        set
        {
            position = value;
        }
    }
    public bool SystemGenerated
    {
        get
        {
            return systemGenerated;
        }

        set
        {
            systemGenerated = value;
        }
    }
    public Grid<T> Parent
    {
        get
        {
            return parent;
        }

        set
        {
            parent = value;
        }
    }
}


而目前的代码由于试图在类之外的其他地方进行处理而变得凌乱,因此我无法提供给您。但是我可以给你一个很好的例子是:

List<Cell> MazeMakeStack = new List<Cell>().Add(CellGrid.Items[0, new Random().Next(0,CellGrid.Items.Count-1)]);
do
{
    List<string> availableCells = new List<string>();
    //Checks the Top neighbor of the `CellGrid` who's Item.Id == MazeMakeStack.Last().Id and checks the Boolean IsVistited which is false by default
    if (!IsVisited)
    {
        availableCells.Add("Top")
    }
    //repeats this for left, bottom, and right adding them to availableCells respectively
    if(availableCells.Count=<0)
    {
        //resolves the borders of the cell and then removes it from the stack such that the next item can be handled
        //(My method is randomized depth first search so this is when the tree has no places to go)
    }
    else
    {
        //randomly chooses a member of availableCells
        //uses a switch that tests the randomly chosen member of availableCells and then based on that grabs the corresponding neighbor, adding it MazeMakerStack
    }
}
while(MazeMakeStack,Count()>0)

最佳答案

因为GridItem<T>类不知道GridItem<T>中的任何其他Grid<T>项,所以可以使用委托来实现目标。

这是一个例子:

网格类别:

public class Grid<T>
{
    int width;
    int height;
    public List<GridItem<T>> Cells { get; set; }

    public Grid()
    {
        foreach (GridItem<T> cell in Cells)
        {
            cell.onGetNeighbor += OnGetNeighbor;
        }
    }

    private GridItem<T> OnGetNeighbor(GridItem<T> self, Direction direction)
    {
        GridItem<T> neighbor = null;

        switch (direction)
        {
            case Direction.Top:
                neighbor = Cells.FirstOrDefault(cell =>
                    cell.X == self.X && cell.Y == self.Y - 1);
                break;
            case Direction.Bottom:
                neighbor = Cells.FirstOrDefault(cell =>
                    cell.X == self.X && cell.Y == self.Y + 1);
                break;
            case Direction.Left:
                neighbor = Cells.FirstOrDefault(cell =>
                    cell.X == self.X - 1 && cell.Y == self.Y);
                break;
            case Direction.Right:
                neighbor = Cells.FirstOrDefault(cell =>
                    cell.X == self.X + 1 && cell.Y == self.Y);
                break;
            default:
                break;
        }

        return neighbor;
    }
}


GridItem类:

public class GridItem<T>
{
    public int X { get; set; }
    public int Y { get; set; }

    public Func<GridItem<T>, Direction, GridItem<T>> onGetNeighbor;

    public GridItem<T> GetNeighbor(Direction direction)
    {
        return onGetNeighbor(this, direction);
    }
}


方向枚举:

public enum Direction
{
    Top, Bottom, Left, Right
}


您可以这样使用:

// Insert your grid/grid item code here ..
Grid<int> grid = new Grid<int>();
GridItem<int> item = grid.Cells[1];

// Get top neighbor
GridItem<int> neighbor = item.GetNeighbor(Direction.Top);

// Check if top neighbor exists
bool topNeighborExists = item.GetNeighbor(Direction.Top) != null;

关于c# - 我应该如何使集合的成员意识到自己的“ sibling ”与其位置的关系,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41861659/

10-09 21:02