Java 中的生命游戏 GUI - 表达式总是错误的

IAc*_*now 2 java

我尝试实现生命游戏的基本版本并且它起作用了,但是今天我尝试为它制作一个 GUI 并且我遇到了问题。

问题是我有一个if声明来检查游戏规则之一。IDE 告诉我它总是返回 false。

if (!grid[row][col].isAlive() && aliveNeighbours == 3)
Run Code Online (Sandbox Code Playgroud)

我检查了我的方法并进行了各种测试,但可能我太累了,看不到问题所在。

这是完整的课程:

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.*;

public class Main extends JFrame {
    int size = 50;

    Cell[][] grid = new Cell[size][size];

    //Swing components
    JPanel p = new JPanel();
    JPanel top = new JPanel();
    JButton startButton = new JButton("Start");
    JButton randomButton = new JButton("Randomize");
    JPanel center = new JPanel();


    public static void main(String[] args){
         new Main();
    }

    public Main(){
        super("Game of Life GUI");
        setSize(1200,900);
        setResizable(false);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        p.setLayout(new BorderLayout());
        center.setLayout(new GridLayout(size, size));

        setupButtons();
        createFirstGrid();


        top.add(startButton);
        top.add(randomButton);
        p.add(top, BorderLayout.NORTH);
        p.add(center, BorderLayout.CENTER);
        add(p);
        setVisible(true);
    }

    void startLoop(){
        Timer timer = new Timer();
        System.out.println("Started");
        timer.schedule(new TimerTask() {

            @Override
            public void run() {
                step();
            }
        }, 1000, 1000);
    }

    void step() {
        Cell[][] newGrid = grid;
            for (int row = 1; row < grid.length - 1; row++) {
                for (int col = 1; col < grid[row].length - 1; col++) {

                    int aliveNeighbours = getAliveNeighbours(grid, row, col);

                    if (grid[row][col].isAlive() && aliveNeighbours == 2 || aliveNeighbours == 3){
                            newGrid[col][row].setAliveStatus(true);
                    } else if (!grid[row][col].isAlive() && aliveNeighbours == 3){
                        newGrid[col][row].setAliveStatus(true);
                    } else if (aliveNeighbours < 2 || aliveNeighbours > 3) {
                        newGrid[col][row].setAliveStatus(false);
                    }
                }
            }
        grid = newGrid;
    }



    private int getAliveNeighbours(Cell[][] grid, int row, int col){
        int aliveCells = 0;

        for (int x = row - 1; x <= row + 1; x++){
            for (int y = col - 1; y <= col; y++){
                if (x < 0 || x >= grid.length || y<0 || y >= grid.length){
                    continue;
                }
                if (grid[x][y].equals(grid[row][col])){
                    continue;
                }
                if (grid[x][y].isAlive()){
                    aliveCells++;
                }
            }
        }
        System.out.println(aliveCells);
        return aliveCells;
    }

    private void setupButtons() {
        startButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                startLoop();
            }
        });
        randomButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int initialAliveCells = ((size/2) * (size/5)); //totally random, but it makes up a good amount of alive points
                if (initialAliveCells % 2 != 0){ //need a pair number to form couples
                    initialAliveCells--;
                }
                Random randomSeed = new Random();
                ArrayList<Integer> initialIndexes = new ArrayList<Integer>();

                for (int p = 0; p <initialAliveCells; p++){
                    initialIndexes.add(randomSeed.nextInt(size));
                }

                for (int x = 1; x <= initialIndexes.size(); x += 2){
                    grid[initialIndexes.get(x - 1)][initialIndexes.get(x)].setAliveStatus(true);
                }
            }

        });
    }

    private void createFirstGrid(){
            for (int row = 0; row < grid.length; row++) {
                for (int col = 0; col < grid[row].length; col++) {
                    grid[row][col] = new Cell();
                    grid[row][col].setAliveStatus(false);
                    center.add(grid[row][col]);
                }
            }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是 Cell 类

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Cell extends JButton implements ActionListener {
    boolean isAlive;
    Color aliveColor = Color.BLACK;
    Color deadColor = Color.WHITE;

    public Cell(){
        this.addActionListener(this);
        setPreferredSize(new Dimension(5,5));
        setBackground(deadColor);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        setAliveStatus(!isAlive);
        updateColor();
    }

    private void updateColor() {
        if (isAlive){
            setBackground(aliveColor);
        } else {
            setBackground(deadColor);
        }
    }


    public void setAliveStatus(boolean status){
        this.isAlive = status;
        updateColor();
    }

    public boolean isAlive(){
        return isAlive;
    }
}
Run Code Online (Sandbox Code Playgroud)

有问题的方法是 getAliveNeighbours 之一:

private int getAliveNeighbours(Cell[][] grid, int row, int col){
    int aliveCells = 0;

    for (int x = row - 1; x <= row + 1; x++){
        for (int y = col - 1; y <= col; y++){
            if (x < 0 || x >= grid.length || y<0 || y >= grid.length){ //This check shouldn't be needed as i never pass cells in the border
                continue;
            }
            if (grid[x][y].equals(grid[row][col])){ //this is to avoid counting the current cell
                continue;
            }
            if (grid[x][y].isAlive()){  
                aliveCells++;
            }
        }
    }
    System.out.println(aliveCells);
    return aliveCells;
}
Run Code Online (Sandbox Code Playgroud)

它永远不会返回正确的金额,但我不明白为什么。

Joh*_*ica 5

错误信息具有欺骗性。问题其实出在前面的if语句中:

if (grid[row][col].isAlive() && aliveNeighbours == 2 || aliveNeighbours == 3)
Run Code Online (Sandbox Code Playgroud)

&&具有比 更高的优先级||。添加括号以将||条件组合在一起。

if (grid[row][col].isAlive() && (aliveNeighbours == 2 || aliveNeighbours == 3))
Run Code Online (Sandbox Code Playgroud)

没有它们,它被解析为:

if ((grid[row][col].isAlive() && aliveNeighbours == 2) || aliveNeighbours == 3)
Run Code Online (Sandbox Code Playgroud)

以这种方式解释,编译器注意到else if (!grid[row][col].isAlive() && aliveNeighbours == 3)永远不会触发。当aliveNeighbors == 3代码总是输入第一个时if,从不输入else if。这就是它抱怨的原因。但这else if不是问题,而是if上述问题。

经验教训:错误并不总是在标记线上。有时您必须查找才能找到真正的问题。