1

My midterm assignment for my comp sci class is that I have to create a tictactoe game. I have 9 individual JPanel objects that represent the tiles, all with the int value "turn" that determines which graphic gets put into the panel. My problem is that I need to make it so that when you click the button within a panel, it changes the value of turns for all of the CellPanel objects within the frame, not just that instance of it, so that next time you take a panel, it puts a new graphic up, instead of the same graphic as before.

My Mid1 class with the main method:

import java.awt.*;
import javax.swing.*;

public class Mid1 extends JFrame {
  public Mid1() {
    setLayout(new GridLayout(3, 3));

    CellPanel panel1 = new CellPanel();
    add(panel1);
    CellPanel panel2 = new CellPanel();
    add(panel2);
    CellPanel panel3 = new CellPanel();
    add(panel3);
    CellPanel panel4 = new CellPanel();
    add(panel4);
    CellPanel panel5 = new CellPanel();
    add(panel5);
    CellPanel panel6 = new CellPanel();
    add(panel6);
    CellPanel panel7 = new CellPanel();
    add(panel7);
    CellPanel panel8 = new CellPanel();
    add(panel8);
    CellPanel panel9 = new CellPanel();
    add(panel9);
  }

  public static void main(String[] args) {
    Mid1 frame = new Mid1();
    frame.setTitle("mid1");
    frame.setSize(400, 400);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLocationRelativeTo(null); // Center the frame
    frame.setVisible(true);

  }
}

My CellPanel class:

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

class CellPanel extends JPanel implements ActionListener{
  Image cross = new ImageIcon("image/x.gif").getImage();
  Image not = new ImageIcon("image/o.gif").getImage();
  JButton button;
  int turn = 0;
  int draw;

  public CellPanel(){
      BorderLayout layout = new BorderLayout();
      setLayout(layout);
      button = new JButton("Take");
      button.setPreferredSize(new Dimension(0,20));
      button.addActionListener(this);
      this.add(button, layout.SOUTH);
  }

  public void setTurn(int t){
      turn = t;
  }

  public int getTurn(){
      return turn;
  }

  @Override
  protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    if (draw == 1)
        g.drawImage(cross, 0, 0, getWidth(), getHeight(), this);
    if (draw == 2)
        g.drawImage(not, 0, 0, getWidth(), getHeight(), this);

      System.out.println(turn);

    /*int mode = (int)(Math.random() * 3);

    if (mode == 0) {
      g.drawImage(cross, 0, 0, getWidth(), getHeight(), this);
    }
    else if (mode == 1) {
      g.drawImage(not, 0, 0, getWidth(), getHeight(), this);
    }*/
  }

    @Override
    public void actionPerformed(ActionEvent e) {
        switch(turn) {
            case 0:
                draw = 1;
                this.repaint();
                turn = 1;
                break;
            case 1: 
                draw = 2;
                this.repaint();
                turn = 0;
                break;
            default: turn = 0;
                break;
        }
        this.remove(button);
    }
}
Suvasis
  • 1,451
  • 4
  • 24
  • 42
  • Separate your concerns. I would remove the turn field from the pane (panes don't need to know which player is playing next, a pane only needs to know what to display). When a player marks the square, pass a value to the pane so it knows which player just played and can display the appropriate symbol. – The Head Rush Sep 26 '14 at 18:34
  • I'm not sure how I would pass the value, as the buttons and their actionlisteners exist within the panels. Should I make them separate and put them into the Frame itself? I'm not sure how I would work the layout of them in that case. – Grayson Erickson Sep 26 '14 at 18:41

2 Answers2

1

Let each CellPanel know when the game state changes using the observer pattern; several implementations are suggested here. Although CellPanel might usefully extend JPanel to establish a preferred size, it can still implement the Observer observer. Your game's model, which should notify listening cells to redraw themselves, can extend Observable.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
0

There's a few ways to do it.

Assuming you only have one tic tac toe board running, the easiest thing to do is declare turn as static.

static int turn = 0;

Then you can make the get and set static, and you only have to change it for one of the CellPanels for all of them to recognize the turn has changed.

CellPanel.setTurn(1); 
//sets turn for static int turn to 1. All CellPanels share the same turn value and recognize this as such

That being said, I'm not sure what the purpose of your turn item is. Is it denoting Player 1, Player 2? Which turn it physically is? Something else?

Compass
  • 5,867
  • 4
  • 30
  • 42
  • This certainly fixes my first problem, but my problem now is that I need to run a check each time the ActionListener is activated to see if there's a "three in a row" anywhere on the board. Statics won't work here, as each panel (obviously) will have different values for which graphic it has. Any advice? – Grayson Erickson Sep 26 '14 at 18:57
  • @GraysonErickson This should be something the conceptual board that holds all your CellPanels should check. CellPanels should not be checking neighbors to see if they line up (in fact, doing that would be super-complicated). If you need to contact the board from the CellPanel, you can always assign it a JPanel parent so they can call parent.checkForWin(); – Compass Sep 26 '14 at 19:00