Reputation: 63
I know this is probably a timing issue but i'm honestly not experienced enough to pin the specific thing down and figure out a fix. Basically, it's a Connect Four game, and I'm just now learning the basics of event listeners and such.
package siena;
import java.awt.*;
import javax.imageio.ImageIO;
import javax.swing.*;
public class ConnectFour {
public static int buttonPushed = -1;
public static void main (String[] args) throws java.lang.Exception {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
JFrame board = new JFrame("Connect Four", gc);
board.setResizable(false);
board.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GridBagLayout gridbag = new GridBagLayout();
board.setLayout(gridbag);
GridBagConstraints c = new GridBagConstraints();
c.gridwidth = 3;
JButton ng = new JButton("New Game");
c.anchor = c.NORTH;
c.fill = c.HORIZONTAL;
c.insets = new Insets(5, 5, 5, 5);
board.add(ng, c);
c.gridx = 1;
JButton eg = new JButton("Close");
c.gridy = 1;
c.gridwidth = 1;
final JButton add[] = new JButton[7];
ButtonClicker clickers[] = new ButtonClicker[9];
for (int i = 0; i < clickers.length; i++) {
clickers[i] = new ButtonClicker(i);
}
ng.addActionListener(clickers[0]);
eg.addActionListener(clickers[8]);
for(int i = 0; i < 7; i++) {
add[i] = new JButton("Drop token");
add[i].addActionListener(clickers[i + 1]);
c.gridx = i;
board.add(add[i], c);
}
JLabel slot[][] = new JLabel[7][6];
int slotStat[][] = new int[7][6];
c.ipadx = 0;
c.ipady = 0;
c.gridx = 0;
c.gridy = 2;
ImageIcon[] img = {new ImageIcon(ImageIO.read(new java.io.File("src/siena/gray.png"))), new ImageIcon(ImageIO.read(new java.io.File("src/siena/red.png"))), new ImageIcon(ImageIO.read(new java.io.File("src/siena/yellow.png")))};
JLabel n = new JLabel(img[0]);
for (int x = 0; x < 7; x++) {
for (int y = 0; y < 6; y++) {
slot[x][y] = new JLabel(n.getIcon());
slotStat[x][y] = 0;
board.add(slot[x][y], c);
c.gridy++;
}
c.gridx++;
c.gridy = 2;
}
c.gridx = 0;
c.gridy = 8;
c.gridwidth = 7;
c.anchor = c.CENTER;
Label info = new Label("It is the RED player's turn.");
info.setAlignment(info.CENTER);
board.add(info, c);
board.pack();
board.setVisible(true);
boolean isRedTurn = true;
int redCheck = 0;
int yellowCheck = 0;
while(buttonPushed != 9){
while(buttonPushed == -1);
switch(buttonPushed) {
case 0:
for (int x = 0; x < 7; x++) {
for (int y = 0; y < 6; y++) {
slotStat[x][y] = 0;
slot[x][y].setIcon(img[0]);
isRedTurn = true;
}
}
buttonPushed = -1;
break;
case 1: case 2: case 3: case 4: case 5: case 6: case 7:
if (slotStat[buttonPushed - 1][0] != 0) {
info.setText("That column is full!");
info.wait(100, 50000);
buttonPushed = -1;
break;
} else {
for (int y = 0; y < 6; y++) {
if (y != 5 && slotStat[buttonPushed - 1][y + 1] == 0) {
//if we're not at the bottom and the slot below this one is empty
if (isRedTurn) slot[buttonPushed - 1][y].setIcon(img[1]);
else slot[buttonPushed - 1][y].setIcon(img[2]);
Thread.sleep(200);
slot[buttonPushed - 1][y].setIcon(img[0]);
} else {
//if we're at the bottom or the slot below this one is full
if (isRedTurn) {
slotStat[buttonPushed][y] = 1;
slot[buttonPushed][y].setIcon(img[1]);
redCheck++;
} else {
slotStat[buttonPushed][y] = 2;
slot[buttonPushed][y].setIcon(img[2]);
yellowCheck++;
}
isRedTurn = !isRedTurn;
}
}
}
buttonPushed = -1;
break;
}
}
}
}
The ButtonPushed class is just something that extends ActionListener so i can find out what button was pressed, it has an "id" int attribute that, on button pushed gets passed to the buttonPushed int in the connect four thing
Upvotes: 1
Views: 117
Reputation: 63
So, to summarize the comments, I was using the kind of structure that would be used in a linear (not event-based) program. While loops don't work when you're waiting for input, and instead of using one big static main method and a slightly modified ActionListener class, I should have used input events to call internal methods to modify internal data, then update the external GUI (in its own class and with its own class methods) based on that internal data.
If anyone needs to see an example, this is my work so far. I still need to edit some of it (namely how the program ends, and I need to add a win detector), but the GUI is fully functional.
ConnectFour class: http://pastebin.com/yeGALQn7
ButtonClicker class: http://pastebin.com/Y2y0SfW9
CFBoard class: http://pastebin.com/g9qqBmry
Oh, and, for the curious reading this, I'm reasonably sure that the reason it only works in debug mode is that the breakpoints stopped the input from conflicting with main() running through the while() loop over and over, so making it fully event-driven meant that those conflicts didn't exist anymore.
Thanks to everyone for the help, especially @HovercraftFullOfEels!
Upvotes: 1