Search code examples
javaeclipseimageicon

Programming Tic Tac Toe in Java with ImageIcons - winningCondition


I need help because im a beginner in Java programming. I am programming Tic Tac Toe for University at the moment and i have some problems because i wanted to use some smileys instead of X's & O's. But i don't know how to compare them by Searching for Winners, so i used letters. But you can see the letters together with the Smileys in the playfield and i think this is not the best solution. Maybe some of you have better suggestions and reviews for my program. I copied the images devil.png and sun.png in my TicTacToe src folder.

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

public class Gui implements ActionListener {

    // Variables
    private static int[][] winCombos = new int[][] //Possible win combinations
            {
                {0, 1, 2}, {3, 4, 5}, {6, 7, 8}, //horizontal wins
                {0, 3, 6}, {1, 4, 7}, {2, 5, 8}, //vertical wins
                {0, 4, 8}, {2, 4, 6}             //diagonal wins
            };

    static JButton btn[] = new JButton[9];
    private int count = 0;
    private int xscore = 0;
    private int oscore = 0;
    private String letter = "";
    private boolean win = false;
    private ImageIcon devil; // devil= spieler X
    private ImageIcon sun; // sun = spieler O

    public Gui() {

        // Create Window
        JFrame jf = new JFrame();

        jf.setSize(400, 400);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setLocationRelativeTo(null);
        jf.setResizable(false);
        jf.setTitle("Tic-Tac-Toe Playfield");
        jf.setLayout(new GridLayout(3, 3));
        devil = new ImageIcon(getClass().getResource("devil.png")); //X
        sun = new ImageIcon(getClass().getResource("sun.png")); //O

        // Add Buttons to the Window
        for (int i = 0; i < btn.length; i++) {
            btn[i] = new JButton();
            btn[i].setVisible(true);
            btn[i].setFocusPainted(false);
            btn[i].addActionListener(this);
            jf.add(btn[i]);
        }
        jf.setVisible(true);
    }

    public void actionPerformed(ActionEvent a) 
    {
            count++;

            //Who's turn is it 
            if(count % 2 == 0)
            {
                letter = "O";
                oscore++;
            }
            else
            {
                letter = "X";
                xscore++;
            }

            //Change button to letter
            if(letter == "X")
            {
                JButton pressedButton = (JButton)a.getSource();
                pressedButton.setIcon(devil);
                pressedButton.setEnabled(false);
            }
            else if(letter == "O")
            {
                JButton pressedButton = (JButton)a.getSource();
                pressedButton.setIcon(sun);
                pressedButton.setEnabled(false);
            }

            //Search for Winner
            for(int i=0; i<=7; i++)
            {
               if(btn[winCombos[i][0]].getIcon() !=null &&
                       btn[winCombos[i][0]].getIcon().equals(btn[winCombos[i][1]].getIcon()) && 
                       btn[winCombos[i][1]].getIcon() !=null && 
                               btn[winCombos[i][1]].getIcon().equals(btn[winCombos[i][2]].getIcon())

                       )

                {
                    win = true;
                }
            }


            //Dialog at the end of the game
            if(win)
            {
                JOptionPane.showMessageDialog(null, letter + " wins the game");
                System.exit(0);
            }
            else if(count == 9 && !win)
            {
                JOptionPane.showMessageDialog(null, "There is no winner.");
                System.exit(0);
            }               
    }}

Solution

  • MadProgrammers advice here

    Step back for a moment. You need to do is separate the logic from the presentation, this allows you to consistently model the logic and allow the presentation to present in whatever form it wants to. This is the basic functionality of the "model-view-controller" paradigm. With this, you model your data (the game and it's state) and then allow the view (the UI) to present it in what ever manager it wants to. This means the logic for determining when a player wins a game is determined by the model

    is definitely the right way to go and the how you should consider designing future projects. However I assume that you perhaps are yet to cover MVC and other design patterns in your course.

    The problem you are now getting will be NullPointerException in your loop as on the first click most of the buttons will have no icon assigned, so when you then try to call .equals() on that null object the exception occurs.

    So the simple fix is you will need to check for null icons before you can do the equality check.

    Edit Before you call the equals!

    if(btn[winCombinations[i][0]].getIcon() != null && 
       btn[winCombinations[i][0]].getIcon().equals(....
    

    You will also need to do this for btn[winCombinations[i][1]].getIcon()

    End Edit

    A more concise way might be to use the Objects.equals() method if you are able

    To explain more: When the Exception occurs, the method breaks - so it occurs in your for loop so then the code below that will not get executed. Try adding this below your loop:

    System.out.println("Reached here!");
    

    And you will notice that it is only ever printed once all the buttons have been pressed.

    And to help you check more visually, you could add a try catch around your loop - note that this is not ideal operation - but will help you diagnose the problem more visually.

    try
    {
        // your win check loop
    }
    catch (Exception e)
    {
        e.printStackTrace();
        JOptionPane.showMessageDialog(null, "Oh no!:\n" + e);
    }