Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If statement only entering if print before [duplicate]

I have a loop that is running until the user clicks a ready button, and then it starts the the loop inside the if-statement, but it only works it there is a print statement before it. Does it have to do with how the Rule Set is static? The Button works no matter what, but it only enters the loop if the print statement is there.

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;
            }
        }
    }
}

Rule Class:

public class RuleSet {

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);
} }

Gui

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;
} 
}
like image 977
Peter Chappy Avatar asked Oct 02 '22 17:10

Peter Chappy


2 Answers

I have a loop that is running until the user clicks a ready button, and then it starts the the loop inside the if-statement, but it only works it there is a print statement before it.

The reason behind your problem is, "when the user clicks the ready button the event handling code is being run in different thread than the thread in which your loop is running". So, the behavior can be unexpected: because you are assuming that readyToStart is being set before you get in to the if condition.

Adding System.out.println makes the thread running the loop to wait for the io and in the meanwhile readyToStart is being set by the other thread.

You can make readyToStart volatile by adding volatile in it's declaration, so that both the threads can have consistant view of it.

public class RuleSet {

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

           /*Rest of code goes here*/
}
like image 110
Vaibhav Raj Avatar answered Oct 13 '22 10:10

Vaibhav Raj


First: Please do not use an is...() method to change state. This should be an accessor, not an mutator by naming convention. (You may want to use userIsReady() or setReady() instead).

I assume that you experience a multi-threading issue, since you have the AWT thread and your user thread working with the same value, but have not ensured that there is some kind of synchronization.

You can check if changeing the declaration of the ready flag helps:

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

You can read more about multithreading and concurrency issues here:

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

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

like image 29
Thomas Avatar answered Oct 13 '22 10:10

Thomas