5

我有一个循环一直在运行,直到用户单击就绪按钮,然后它在 if 语句中启动循环,但它只在它之前有一个打印语句时才有效。它是否与规则集是静态的有关?Button 无论如何都可以工作,但只有在 print 语句存在时才会进入循环。

package gameoflife;

public class GameOfLife {

    public static final int HEIGHT = 16;
    public static final int LENGTH = 16;
    public static Grid current;

    public static void main(String[] args) {
        Ui gui = new Ui();
        int time = 0;
        while (true) {
            RuleSet.checkReady();
            //System.out.println(RuleSet.checkReady());
            if (RuleSet.checkReady() == true) {
                //System.out.println("ready!");
                if(time == 0){
                    current = gui.getUserSeed();
                }
                while (time < 100) {
                    current.print();
                    Grid next = new Grid(HEIGHT, LENGTH);
                    for (int i = 0; i < HEIGHT; i++) {
                        for (int j = 0; j < LENGTH; j++) {
                            next.changeState(i, j, RuleSet.determineState(current, i, j));
                        }
                    }
                    current = next;
                    time++;
                }
                break;
            }
        }
    }
}

规则类:

公共类规则集{

public Grid grid;
public static boolean readyToStart = false;

/*checkReady()
 * input:   
 * purpose: checks ready flag 
 * output:  none
 */
public static boolean checkReady() {
    return readyToStart;
}

/*isReady()
 * input:   none
 * purpose: sets ready flag to ready
 * output:  none
 */
public static void isReady() {
    readyToStart = true;
}

/*determineState()
 * input:   Grid grid, int y, int x
 * purpose: determines the state of a cell for the next 
 *          generationusing the four rules below
 * output:  true/false
 */
public static boolean determineState(Grid grid, int y, int x) {
    grid = grid;
    int neighbors = grid.getNeighbors(y, x);
    if (grid.getState(y, x)) {
        return (ruleOne(neighbors) && ruleTwo(neighbors)
                && ruleThree(neighbors));
    } else {
        return (ruleFour(neighbors));
    }
}

/*
 * Rule 1:
 * Any live cell with fewer than two live neighbours dies, 
 * as if caused by under-population.
 */
private static boolean ruleOne(int neighbors) {
    return (neighbors >= 2);
}

/*
 * Rule 2:
 * Any live cell with two or three live neighbours 
 * lives on to the next generation.
 */
private static boolean ruleTwo(int neighbors) {
    return (neighbors == 2 || neighbors == 3);
}

/*
 * Rule 3: 
 * Any live cell with more than three live neighbours dies, 
 * as if by overcrowding
 */
private static boolean ruleThree(int neighbors) {
    return (neighbors < 4);
}

/*
 * Rule 4:
 * Any dead cell with exactly three live neighbours becomes a live cell, 
 * as if by reproduction.
 */
private static boolean ruleFour(int neighbors) {
    return (neighbors == 3);
} }

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 *
 * @author peter
 */
public class Ui extends JFrame {

public static JPanel panelGrid;
public static JPanel panelControl;
public static JPanel panelManager;
public static JButton[][] buttons;
public static JButton isReady;
public static JButton nextGen;
public static final int HEIGHT = 16;
public static final int LENGTH = 16;
public Grid temp;

public Ui() {
    setTitle("The Game Of Life");
    setSize(800, 600);
    setLocationRelativeTo(null);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    temp = new Grid(HEIGHT, LENGTH);
    //Creates and sets up the contentPane Container
    Container contentPane = getContentPane();
    contentPane.setLayout(new BorderLayout());
    contentPane.add(initButtonGrid(), BorderLayout.CENTER);
    contentPane.add(initContButton(), BorderLayout.PAGE_END);
    //add(contentPane);
    setVisible(true);
}

/*initButtonGrid()
 * input:   none
 * purpose: to return initialize the button array, and return the 
 *          corresponding JPanel
 * output:  JPanel panelGrid
 */
private JPanel initButtonGrid() {
    buttons = new JButton[HEIGHT][LENGTH];
    panelGrid = new JPanel(new GridLayout(HEIGHT, LENGTH));

    for (int i = 0; i < HEIGHT; i++) {
        for (int j = 0; j < LENGTH; j++) {
            buttons[i][j] = new JButton();
            buttons[i][j].setSize(80, 80);
            buttons[i][j].setBackground(Color.white);
            //Creates an action listener that allows user
            //to setup seed
            buttons[i][j].addActionListener(new ActionListener() {                    
                //Loops through and checks the state of the button/array
                //and then changes state if needed
                public void actionPerformed(ActionEvent e) {
                    for (int i = 0; i < HEIGHT; i++) {
                        for (int j = 0; j < LENGTH; j++) {
                            if (buttons[i][j] == e.getSource()
                                    && !RuleSet.checkReady()) {
                                temp.changeState(i, j, !temp.getState(i, j));
                                if (temp.getState(i, j)) {
                                    buttons[i][j].setBackground(Color.red);
                                } else {
                                    buttons[i][j].setBackground(Color.white);
                                }
                                temp.print();
                            }
                        }
                    }
                }
            });
            panelGrid.add(buttons[i][j]);
        }
    }
    return panelGrid;
}

/*getUserSeed()
 * input:   none
 * purpose: to return the seed the user made with the buttons. I was having
 *          trouble passing the current grid from main() to here in a static
 *          way. Will attempt to update at later point
 * output:  Grid temp
 */
public Grid getUserSeed() {
    return temp;
}

/*initContButton()
 * input:   none
 * purpose: to return initialize the buttons for commands, and return the 
 *          corresponding JPanel
 * output:  JPanel panelControl
 */
private JPanel initContButton() {
    panelControl = new JPanel(new GridLayout(1, 2));
    JButton ready = new JButton("Start Simulation");
    ready.setSize(80, 190);
    ready.addActionListener(new ActionListener() {

        public void actionPerformed(ActionEvent e) {
            RuleSet.isReady();
            System.out.println("Ready Pressed");
        }
    });
    panelControl = new JPanel(new GridLayout(1, 2));
    JButton nextGen = new JButton("Generation");
    nextGen.setSize(80, 190);
    nextGen.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
        }
    });
    panelControl.add(ready);
    panelControl.add(nextGen);
    return panelControl;
} 
}
4

2 回答 2

3

我有一个循环一直在运行,直到用户单击就绪按钮,然后它在 if 语句中启动循环,但它只在它之前有一个打印语句时才有效。

问题背后的原因是,“当用户单击就绪按钮时,事件处理代码正在与循环运行的线程不同的线程中运行”。因此,该行为可能是出乎意料的:因为您假设在进入 if 条件之前已设置了readyToStart 。

添加System.out.println使运行循环的线程等待 io,同时另一个线程正在设置readyToStart 。

您可以通过在其声明中添加 volatile 来使readyToStart 变为volatile,以便两个线程可以对其具有一致的视图。

public class RuleSet {

           public Grid grid;
           public static volatile boolean readyToStart = false;

           /*Rest of code goes here*/
}
于 2013-10-15T16:33:30.877 回答
1

第一:请不要使用 is...() 方法来改变状态。这应该是一个访问器,而不是命名约定的突变器。(您可能想要使用 userIsReady() 或 setReady() 代替)。

我假设您遇到了多线程问题,因为您的 AWT 线程和您的用户线程使用相同的值,但没有确保存在某种同步。

您可以检查更改就绪标志的声明是否有帮助:

public static boolean readyToStart = false; // change this to
public volatile static boolean readyToStart = false;

您可以在此处阅读有关多线程和并发问题的更多信息:

http://docs.oracle.com/javase/tutorial/essential/concurrency/index.html

http://docs.oracle.com/javase/tutorial/uiswing/concurrency/

于 2013-10-15T16:25:08.137 回答