Java:如何实现康威的生命游戏?

时间:2016-11-29 20:45:56

标签: java algorithm bit

我正在研究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中的yliveNeighbors()代表什么?不明白为什么需要Math.min()Math.max()。而且,lives是否代表了董事会中初始化生活的数量?

1 个答案:

答案 0 :(得分:4)

给定代码使用minmax函数将搜索限制为数组中的有效条目。如果未执行此操作,则在尝试将-1mn用作数组索引时,代码将返回ArrayOutOfBoundsException。 (循环不“知道”在地图的右边缘给出一个正方形,它不应该在右边进一步搜索活着的邻居;这些函数编码这个事实。)x和{{1只是循环控制变量,用于迭代目标方块周围的有效方块。

对于y变量,这是占位符,用于记录下面循环找到的活动邻居数量。您可能已经猜到了这是lives函数的返回值。

我们举个例子。我们将调用liveNeighbors,其中liveNeighbors(board,9,9,0,2)是驱动程序中给出的板。您的电路板尺寸为9x9,因此我们传递的是boardm,对于我们的示例,我们正在研究n0处的正方形,这是第三行中的第一个条目(右侧有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 = -1y的类似逻辑。

循环简化为:

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) = 1x向后退了一次或两次,但希望这足以让你了解正在发生的事情。