使用java计算康威生命游戏中的下一帧

时间:2015-01-19 11:18:25

标签: java conways-game-of-life

尝试创造Conways生活游戏,但显然形状并不像他们必须的那样。也许有人可以帮我找到问题。

例如滑翔机:

- X - - - - 
- - X X - - 
- X X - - -
- - - - - - 

变成这个

- - X X - - 
- X - - - - 
X X X - - - 
- X X X - - 

但应该是这样的:

- - X - - -
- - - X - -
- X X X - -
- - - - - -

我的代码看起来像这样

public Frame(int x, int y) {

     setWidth(x);
     setHeight(y);

     if (x<1)
         frame = null;
      else if (y<1)
         frame = null;
      else {

       frame = new String [x][y];

         for (int i=0; i<frame.length; i++) {
            for (int j=0; j<frame[i].length; j++) {

               frame [i][j] = DEAD;
            }
         }
      } // else
   } // construktor


 public Integer getNeighbourCount(int x, int y) {

    Frame cell = new Frame(getHeight(), getWidth());
    int counter = 0;

    if(frame[x][y].equals(ALIVE))
    {
        counter = counter - 1;
    }
    for(int i=x-1; i<=x+1;i++){

        if(i<frame.length && i>0){

            for(int j=y-1; j<=y+1;j++){

                if(j<frame[i].length && j>0){

                    if (frame[i][j]==ALIVE) {
                        counter++;

                    }

                }
        }
        }
    }

    return counter;

}



public Frame nextFrame() {

    // Returns next frame


    Frame cell = new Frame(getWidth(), getHeight());
    //cell.frame = new String[getWidth()][getHeight()];

    for(int i = 0; i < frame.length; i++){
        for(int j =0; j <frame[i].length;j++){

            int n = getNeighbourCount(i,j);

                if(cell.frame[i][j]==null) {

                    cell.frame[i][j] = DEAD;
                }
               if (isAlive(i, j) && n < 2 || n > 3) {
                   cell.frame[i][j] = DEAD;
               }
               if (isAlive(i, j) && n == 3 || n == 2){
                   cell.frame[i][j] = ALIVE;
               }
               if(!isAlive(i, j) && n == 3) {          
                   cell.frame[i][j] = ALIVE;
               }
               if(isAlive(i, j) && n > 3){

                   cell.frame[i][j] = DEAD;
               }

               frame[i][j] = cell.frame[i][j];
        }

        }

    cell.toString();
    return cell;
}

    `

完整代码http://pastebin.com/LMwz724H

4 个答案:

答案 0 :(得分:1)

我认为问题在于您在迭代循环时复制新值。这意味着邻居正在使用下一个刻度而不是当前值的值。

您可以等到计算新相框中的所有新值后再修改此问题:cell.frame然后再次遍历该帧并从cell.frame复制到frame

另一种选择(在我看来更好)就是在施工期间不要克隆框架。然后,您可以更改nextFrame方法以创建frame的克隆,并使用克隆在frame中设置新值。

答案 1 :(得分:1)

这是一个有效的解决方案 - 为每个单元格使用enum并使i / j和x / y填充正确(我认为)。它肯定会生成正确的第一次迭代:

static class GameOfLife {

    final int w;
    final int h;
    State[][] frame;

    enum State {

        Dead, Alive;
    }

    public GameOfLife(int w, int h) {
        this.w = w;
        this.h = h;
        frame = new State[h][w];
    }

    public void alive(int x, int y) {
        frame[y][x] = State.Alive;
    }

    public void tick() {
        frame = nextGeneration();
    }

    private int surroundingPopulation(int x, int y) {
        int pop = 0;
        for (int i = y - 1; i <= y + 1; i++) {
            for (int j = x - 1; j <= x + 1; j++) {
                // On frame - vertically.
                if ((i >= 0 && i < h)
                        // On frame horizontally.
                        && (j >= 0 && j < w)
                        // Alive
                        && (frame[i][j] == State.Alive)
                        // Not the center.
                        && (i != y || j != x)) {
                    pop += 1;
                }
            }

        }
        return pop;
    }

    private State[][] nextGeneration() {
        State[][] next = new State[h][w];
        for (int y = 0; y < h; y++) {
            for (int x = 0; x < w; x++) {
                int pop = surroundingPopulation(x, y);
                // Any live cell
                if (frame[y][x] == State.Alive) {
                    if (pop < 2) {
                        // ... with fewer than two live neighbours dies, as if caused by under-population.
                        next[y][x] = State.Dead;
                    } else if (pop > 3) {
                        // ... with more than three live neighbours dies, as if by overcrowding.
                        next[y][x] = State.Dead;
                    } else {
                        // ... with two or three live neighbours lives on to the next generation.
                        next[y][x] = State.Alive;
                    }
                } else {
                    // Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
                    if (pop == 3) {
                        next[y][x] = State.Alive;
                    }
                }
            }
        }
        return next;
    }

    @Override
    public String toString() {
        StringBuilder s = new StringBuilder();
        for (State[] row : frame) {
            for (State c : row) {
                s.append(c == State.Alive ? "X" : " ");
            }
            s.append("\r\n");
        }
        return s.toString();
    }
}

public void test() {
    GameOfLife g = new GameOfLife(6, 6);
    g.alive(1, 0);
    g.alive(2, 1);
    g.alive(3, 1);
    g.alive(1, 2);
    g.alive(2, 2);
    System.out.println("Before:\r\n" + g);
    g.tick();
    System.out.println("After:\r\n" + g);
}

答案 2 :(得分:0)

在迭代网格时,您正在更改DEAD和ALIVE帧。你需要存储应该死亡或变得活着的坐标并在之后执行。

将坐标存储在两个ArrayLists中(dead,alive)。第一个和第二个位置是x和y轴,并根据它们是否应该存活来更改这些坐标。

答案 3 :(得分:0)

这是我前一段时间写过的一个简单测试的片段。正如其他人所提到的那样,不要在读取它们的同时更改活动板上的值。相反,克隆电路板并在读取当前电路板时对副本进行更改。

我碰到几次的另一个问题是迭代y,然后是每个y的x,但是在访问一个点时引用x,y。感觉回到了前面:)

// Rules:
// 1) Any live cell with fewer than two live neighbours dies, as if caused by under-population.
// 2) Any live cell with two or three live neighbours lives on to the next generation.
// 3) Any live cell with more than three live neighbours dies, as if by overcrowding.
// 4) Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
void mutateGrid() {

    // Copy existing grid into the next generation's grid
    boolean[][] mutatedGrid = new boolean[gridXWidth][gridYHeight];
    for (int i = 0; i < gridXWidth; i++) {
        System.arraycopy(grid[i], 0, mutatedGrid[i], 0, gridYHeight);
    }
    // Start mutation rules
    for (int y = 0; y < gridYHeight; y++) {
        for (int x = 0; x < gridXWidth; x++) {
            int liveNeighbours = countLiveNeighbours(x,y);
            if (liveNeighbours < 2 || liveNeighbours > 3) {
                mutatedGrid[x][y] = false;
            }
            else if (liveNeighbours == 3) {
                mutatedGrid[x][y] = true;
            }
        }
    }
    grid = mutatedGrid;
}

int countLiveNeighbours(int x, int y) {
    int count = 0;
    for (int j = y-1; j <= y+1; j++) {
        for (int i = x-1; i <= x+1; i++) {
            if (i < 0 || j < 0 || i >= gridXWidth || j >= gridYHeight){
                continue;
            }
            if (grid[i][j]) {
                count++; 
            }
        }
    }
    count -= grid[x][y]?1:0; // remove self from count
    return count;
}