我有一个2维数组,用于存储棋盘的字段..
private field[,] board = new field[boardsize,boardsize];
..现在当我初始化它们时,我想引用每个字段的邻居,这些字段部分尚未启动。
目前使用这样的解决办法:
for(int x = 0; x < boardsize ; x++)
{
for(int y = 0; y < boardsize ; y++)
{
board[x,y] = new field();
}
}
for(int x = 0; x < boardsize ; x++)
{
for(int y = 0; y < boardsize ; y++)
{
board[x,y].setNeighbours(x, y, board);
}
}
这种方法很好,但我很感兴趣,如果可以在初始化之前或之时设置邻居。
setNeighbour - 方法:
setNeighbour(int x, int y, field[,])
{
if(field[x-1,y] != null)
this.neighbour[0] = field[x-1,y];
if(field[x-1,y+1] != null)
this.neighbour[0] = field[x-1,y+1];
if(field[x,y+1] != null)
this.neighbour[0] = field[x,y+1];
if(field[x+1,y+1] != null)
this.neighbour[0] = field[x+1,y+1];
if(field[x+1,y] != null)
this.neighbour[0] = field[x+1,y];
if(field[x+1,y-1] != null)
this.neighbour[0] = field[x+1,y-1];
if(field[x,y-1] != null)
this.neighbour[0] = field[x,y-1];
if(field[x-1,y-1] != null)
this.neighbour[0] = field[x-1,y-1];
}
答案 0 :(得分:2)
你可以这样做:
private field[,] board = new field[boardsize,boardsize];
for(int x = 0; x < boardsize ; x++)
{
for(int y = 0; y < boardsize ; y++)
{
if(board[x,y] == null)
board[x,y] = new field();
board[x,y].setNeighbours(x, y, board);
}
}
并以相同的方式检查setNeighbours()
方法中邻居的初始化:
private void setNeighbours(int x, int y, field[,] board)
{
//Initialize neighbour if not already initialized
if(board[x+1,y] == null)
board[x+1,y] = new field();
//DO SOMETHING...
}
答案 1 :(得分:1)
我不相信它可以引用邻居,因为它们尚未创建。但是,您可以将该板作为参数添加到字段的构造函数中,并在以后需要时使用属性查找邻居。
答案 2 :(得分:0)
这是一个经典的问题......可悲的是,C#没有延续......他们可以通过使用Thread
来模拟(非常缓慢)...是的,它有点矫枉过正了只是一个编程练习:
public sealed class WaitForReady<T> : IDisposable
{
public readonly ManualResetEvent mre = new ManualResetEvent(false);
public T Value
{
get
{
mre.WaitOne();
return this.value;
}
set
{
this.value = value;
mre.Set();
}
}
private T value;
#region IDisposable Members
public void Dispose()
{
mre.Dispose();
}
#endregion
}
public class Field
{
public Field[] Neighbours;
public Field(WaitForReady<Field> me, WaitForReady<Field>[] neighbours)
{
me.Value = this;
Neighbours = new Field[neighbours.Length];
for (int i = 0; i < neighbours.Length; i++)
{
Neighbours[i] = neighbours[i] != null ? neighbours[i].Value : null;
}
}
}
public static void Main(string[] args)
{
int boardsize = 8;
Field[,] board = new Field[boardsize, boardsize];
WaitForReady<Field>[,] boardTemp = null;
try
{
boardTemp = new WaitForReady<Field>[boardsize, boardsize];
var threads = new Thread[boardsize * boardsize];
for (int i = 0; i < boardsize; i++)
{
for (int j = 0; j < boardsize; j++)
{
boardTemp[i, j] = new WaitForReady<Field>();
}
}
int k = 0;
for (int i = 0; i < boardsize; i++)
{
for (int j = 0; j < boardsize; j++)
{
var neighbours = new WaitForReady<Field>[8];
neighbours[0] = i > 0 && j > 0 ? boardTemp[i - 1, j - 1] : null;
neighbours[1] = i > 0 ? boardTemp[i - 1, j] : null;
neighbours[2] = i > 0 && j + 1 < boardsize ? boardTemp[i - 1, j + 1] : null;
neighbours[3] = j > 0 ? boardTemp[i, j - 1] : null;
neighbours[4] = j + 1 < boardsize ? boardTemp[i, j + 1] : null;
neighbours[5] = i + 1 < boardsize && j > 0 ? boardTemp[i + 1, j - 1] : null;
neighbours[6] = i + 1 < boardsize ? boardTemp[i + 1, j] : null;
neighbours[7] = i + 1 < boardsize && j + 1 < boardsize ? boardTemp[i + 1, j + 1] : null;
int i1 = i, j1 = j;
threads[k] = new Thread(() => board[i1, j1] = new Field(boardTemp[i1, j1], neighbours));
threads[k].Start();
k++;
}
}
// Wait for all the threads
for (int i = 0; i < threads.Length; i++)
{
threads[i].Join();
}
}
finally
{
// Dispose the WaitForReady
if (boardTemp != null)
{
for (int i = 0; i < boardsize; i++)
{
for (int j = 0; j < boardsize; j++)
{
if (boardTemp[i, j] != null)
{
boardTemp[i, j].Dispose();
}
}
}
}
}
}
这里的“技巧”是在64个单独的线程中创建Field
。首次初始化时,Field
向所有人宣布“自己”(通过设置其对应的WaitForReady<>
对象),然后它会询问其邻居的this
引用。它通过它作为参数接收的WaitForReady<>
个对象来完成此操作。 WaitForReady<>
是一个“特殊”容器,可以包含单个值(Value
)。如果未设置Value
,则要求它将使线程等待,直到有人通过set
设置值。
对于小尺寸,可以使用递归来构建所有内容以模拟延续。对于64的电路板,通常是可能的。这更快。
public class Field
{
public Field[] Neighbours;
public Field(int i, int j, int boardsize, Func<Field>[,] getters)
{
Console.WriteLine("Building [{0},{1}]", i, j);
getters[i, j] = () => this;
Neighbours = new Field[8];
Neighbours[0] = i > 0 && j > 0 ? getters[i - 1, j - 1]() : null;
Neighbours[1] = i > 0 ? getters[i - 1, j]() : null;
Neighbours[2] = i > 0 && j + 1 < boardsize ? getters[i - 1, j + 1]() : null;
Neighbours[3] = j > 0 ? getters[i, j - 1]() : null;
Neighbours[4] = j + 1 < boardsize ? getters[i, j + 1]() : null;
Neighbours[5] = i + 1 < boardsize && j > 0 ? getters[i + 1, j - 1]() : null;
Neighbours[6] = i + 1 < boardsize ? getters[i + 1, j]() : null;
Neighbours[7] = i + 1 < boardsize && j + 1 < boardsize ? getters[i + 1, j + 1]() : null;
Console.WriteLine("Builded [{0},{1}]", i, j);
}
}
public static void Main(string[] args)
{
int boardsize = 8;
Field[,] board = new Field[boardsize, boardsize];
Func<Field>[,] getters = new Func<Field>[boardsize, boardsize];
for (int i = 0; i < boardsize; i++)
{
for (int j = 0; j < boardsize; j++)
{
int i1 = i, j1 = j;
getters[i, j] = () => board[i1, j1] = new Field(i1, j1, boardsize, getters);
}
}
for (int i = 0; i < boardsize; i++)
{
for (int j = 0; j < boardsize; j++)
{
getters[i, j]();
}
}
}
答案 3 :(得分:0)
另一种方法是让Fields处理其他字段的创建。 编写所有代码要做的工作要多得多,但应该提高处理器效率。
原来你不能在构造函数中做到这一点,因为你会进入一个无限循环的字段试图互相创建(因为他们还找不到对方)。
我喜欢做积极内联的事情,即使它只在Release模式下产生微小的差别,实际上在调试模式下减慢了代码的速度。在我的机器上,执行10k的时间约为0.1秒。有兴趣知道这是否比@ xanatos的答案更快。当然还有更多的代码:P
using System.Runtime.CompilerServices;
namespace Algorithms
{
public class Board
{
public Field[,] fields = new Field[8, 8];
}
public class Field
{
// Neighbor positions
// 701 +1-1 +10 +1+1
// 6 2 0-1 00 0+1
// 543 -1-1 -10, -1+1
private Field[] neighbors = new Field[8];
public void FindNeighbors(Board board, int rank, int file)
{
if (rank > 0)
{
// Not on bottom
createNeighbor(board, rank - 1, file, 4);
if (file > 0)
{
// Not in bottom-left corner, so adding it
//createNeighbor(board, rank - 1, file, 4);
createNeighbor(board, rank - 1, file - 1, 5);
createNeighbor(board, rank, file - 1, 6);
if (rank < 7)
{
// Not on top corner, so adding above and left-above
createNeighbor(board, rank + 1, file - 1, 7);
createNeighbor(board, rank + 1, file, 0);
if (file < 7)
{
// Not in any corder, adding remainder
createNeighbor(board, rank, file + 1, 2);
createNeighbor(board, rank - 1, file + 1, 3);
createNeighbor(board, rank + 1, file + 1, 1);
}
else
{
// On the right, the only fields that haven't been added yet are on the right
}
}
else
{
// on top
if (file < 7)
{
// Not on the left, so add those fields.
createNeighbor(board, rank, file + 1, 2);
createNeighbor(board, rank - 1, file + 1, 3);
}
else
{
// On the top-left, so nothing else to add.
}
}
}
else
{
createNeighbor(board, rank, file + 1, 2);
createNeighbor(board, rank - 1, file + 1, 3);
if (rank < 7)
{
createNeighbor(board, rank + 1, file, 0);
createNeighbor(board, rank + 1, file + 1, 1);
}
else
{
// Top-left corner, nothing to add
}
}
}
else
{
// Bottom
createNeighbor(board, rank + 1, file, 0);
if (file > 0)
{
// Not on left
createNeighbor(board, rank, file - 1, 6);
createNeighbor(board, rank + 1, file - 1, 7);
if (file < 7)
{
// Not on the right
createNeighbor(board, rank + 1, file + 1, 1);
createNeighbor(board, rank, file + 1, 2);
}
}
else
{
// Bottom-left corner
createNeighbor(board, rank + 1, file + 1, 1);
createNeighbor(board, rank, file + 1, 2);
}
}
}
// Neighbor positions
// 701 +1-1 +10 +1+1
// 6 2 0-1 00 0+1
// 543 -1-1 -10, -1+1
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void createNeighbor(Board board, int rank, int file, int neighbor)
{
var field = board.fields[rank, file];
if (field == null)
{
field = new Field();
board.fields[rank, file] = field;
// Start looking for neighbors after their object is initialized.
field.FindNeighbors(board, rank, file);
}
// Always copy a link to the field, even if it already existed
neighbors[neighbor] = field;
}
}
}