我正在研究Conway的生命游戏,我自己实现它,并且遵守以下规则:
给定具有m×n个单元的板,每个单元具有初始状态live(1)或dead(0)。每个单元格使用以下四条规则(取自上述维基百科文章)与其八个邻居(水平,垂直,对角线)进行交互:
- 任何活着的邻居少于两个的活细胞都会死亡,好像是由于人口不足造成的。
- 任何有两三个活邻居的活细胞都会留在下一代。
- 任何有三个以上活着的邻居的活细胞都会死亡,好像人口过多...
- 任何有三个活着的邻居的死细胞都会成为活细胞,好像通过繁殖一样。
实施(https://discuss.leetcode.com/topic/29054/easiest-java-solution-with-explanation):
public void gameOfLife(int[][] board) {
if (board == null || board.length == 0) return;
int m = board.length, n = board[0].length;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
int lives = liveNeighbors(board, m, n, i, j);
// In the beginning, every 2nd bit is 0;
// So we only need to care about when will the 2nd bit become 1.
if (board[i][j] == 1 && lives >= 2 && lives <= 3) {
board[i][j] = 3; // Make the 2nd bit 1: 01 ---> 11
}
if (board[i][j] == 0 && lives == 3) {
board[i][j] = 2; // Make the 2nd bit 1: 00 ---> 10
}
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
board[i][j] >>= 1; // Get the 2nd state.
}
}
}
public int liveNeighbors(int[][] board, int m, int n, int i, int j) {
int lives = 0;
for (int x = Math.max(i - 1, 0); x <= Math.min(i + 1, m - 1); x++) {
for (int y = Math.max(j - 1, 0); y <= Math.min(j + 1, n - 1); y++) {
lives += board[x][y] & 1;
}
}
lives -= board[i][j] & 1;
return lives;
}
和司机:
public static void main(String args[]) {
GameOfLife gl = new GameOfLife();
int[][] board = {
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 1, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 1, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0}
};
gl.gameOfLife(board);
}
我的问题是,x
中的y
和liveNeighbors()
代表什么?不明白为什么需要Math.min()
和Math.max()
。而且,lives
是否代表了董事会中初始化生活的数量?
答案 0 :(得分:4)
给定代码使用min
和max
函数将搜索限制为数组中的有效条目。如果未执行此操作,则在尝试将-1
,m
或n
用作数组索引时,代码将返回ArrayOutOfBoundsException。 (循环不“知道”在地图的右边缘给出一个正方形,它不应该在右边进一步搜索活着的邻居;这些函数编码这个事实。)x
和{{1只是循环控制变量,用于迭代目标方块周围的有效方块。
对于y
变量,这是占位符,用于记录下面循环找到的活动邻居数量。您可能已经猜到了这是lives
函数的返回值。
我们举个例子。我们将调用liveNeighbors
,其中liveNeighbors(board,9,9,0,2)
是驱动程序中给出的板。您的电路板尺寸为9x9,因此我们传递的是board
和m
,对于我们的示例,我们正在研究n
,0
处的正方形,这是第三行中的第一个条目(右侧有2
)。好的,我们开始吧。
1
,所以i=0
(这显示了x = Math.max(i - 1, 0) = Math.max(-1, 0) = 0
功能的原因:如果我们刚才说max
,我们最终会得到int x=i-1
超出数组的界限。接下来我们评估x&lt; = Math.min(i + 1,m - 1)= Math.min(1,8)= 1.如果我们正在调查最后一列中的一个单元格,这个条件会强制执行数组的右边缘。
我将保留涉及x = -1
和y
的类似逻辑。
循环简化为:
j
内部循环将运行六次,使用以下for (int x = 0; x <= 1; x++) {
for (int y = 1; y <= 3; y++) {
lives += board[x][y] & 1;
}
}
对:(x,y)
。说服自己,这些是我们正在调查的广场的邻居,以及广场本身。
这六个方块中的五个将返回(0,1),(0,2),(0,3),(1,1),(1,2),(1,3)
,0
处的一个返回1,因此在此循环结束时,(1,2)
将等于1.最后要做的事情是是lives
,如果我们正在调查的方格中有一个1,则会将lives -= board[i][j] & 1;
减少1。在我们的例子中它没有(lives
= 0)所以我们减去0,留下1,我们返回。 board[i][j]
我可能已经liveNeighbors(board,9,9,0,2) = 1
和x
向后退了一次或两次,但希望这足以让你了解正在发生的事情。