上下文
最近我一直在研究几个简单的WPF项目,以便更熟悉C#和XAML。它们主要是复制旧的或简单的游戏,如扫雷,蜈蚣和乒乓。我决定通过重新创造SEGA Genesis游戏 Fatal Labyrinth 来提高赌注,但是我已经在迷宫的一代中遇到了障碍。
该程序的工作原理是生成<Cell>
列表,这是我制作的类,它将作为跟踪实体,玩家和迷宫本身位置的基础。我遇到的第一个问题是2D列表的浮躁,所以我决定修复它的最简单方法是创建我自己的泛型类型Grid<T>
,它由Dimensions组成,分别是X和Y的int,以及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
s不要互相更新。
从那里流出的下一个自然解决方案是在他们的get和set方法中包含适当更新它们的东西,并且链条会自然地从那里涟漪。问题是只能以一种方式工作,因为GridItem
不知道它所属的Grid
。
很好,接下来我尝试的是将Grid
作为GridItem
成员的GridItem
作为名为Parent的属性。不幸的是,这是我自己的爷爷问题&#34;以及在先前尝试的解决方案中遇到相同的纹波和递归问题。
我正在寻找
如何让GridItem
知道相邻的GridItem
,以便它可以在不创建递归更新的情况下获取和设置它们,并且&#34;我是我自己的爷爷&#34;
加成
此外,如果有人能告诉我如何使T
仅作为可空类型接受。例如,我希望它允许我的Cell
之类的东西可以返回为null,但不能返回Int或Bool,它们不能为空
修改 有些人要求代码,所以这里是:
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)
答案 0 :(得分: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;
}
}
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;