Skip to content
Advertisement

How to have the program regenerate a “new game” where previous grid letters get swapped with new grid letters

In this program I’m trying to input a functionality to start game, where if I click start game (MainMenu) a new jpanel opens up (MainGame), creating another jpanel that creates jbuttons in a grid. If i go back, and click start game again, a new grid should generate instead of the previous one, effectively starting a “new game”. the problem is that if i go back and click on new game again, the program creates 2 grids.

I’ve tried removing the instance of the grid panel with = null but it doesn’t work

Main function:

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

public class Game extends JFrame {
    MainMenu mainMenu;
    Settings settings;
    MainGame mainGame;
    CardLayout cl;
    JPanel container;

    public Game(){
        setSize(900,900); //have all as seperate classes
        setDefaultCloseOperation(3); //cl call container
        container  = new JPanel(); //container call menu1 and menu2
        cl = new CardLayout();
        mainMenu = new MainMenu();
        settings = new Settings();
        mainGame = new MainGame();
        mainMenu.setSettings(settings);
        settings.setMainMenu(mainMenu);
        settings.setMainGame(mainGame);
        mainMenu.setMainGame(mainGame);
        mainGame.setMainMenu(mainMenu);
        mainGame.setSettings(settings);
        container.setLayout(cl); //this stays here i think



        //add setter for main game here
        container.add(mainMenu,"1");
        container.add(settings,"2");
        container.add(mainGame,"3");
        mainMenu.setContainer(container);
        mainMenu.setCl(cl);
        settings.setContainer(container);
        settings.setCl(cl);
        mainGame.setContainer(container);
        mainGame.setCl(cl);
        cl.show(container, "1");
        add(container,BorderLayout.CENTER);

    }

    public static void main(String[] args) {
        Game game = new Game();
        game.setVisible(true);
    }
}

main game class:

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


public class MainGame extends JPanel {
    MainMenu mainMenu;
    Settings settings;
    CardLayout cl;
    JPanel container;
    String rows;
    String columns;

    public void setMainMenu(MainMenu mainMenu) {
        this.mainMenu = mainMenu;
    }

    public void setSettings(Settings settings) {
        this.settings = settings;
    }

    public void setCl(CardLayout cl) {
        this.cl = cl;
    }

    public void setContainer(JPanel container) {
        this.container = container;
    }

    public void setRows(String rows) {
        this.rows = rows;
    }

    public void setColumns(String columns) {
        this.columns = columns;
    }
    public MainGame(){
        JPanel north = new JPanel();
        north.setLayout(new FlowLayout());
        ReturnAction returnAl = new ReturnAction();
        JButton Return2 = new JButton("Return");
        Return2.addActionListener(returnAl);
        north.add(Return2);
        add(north);
    }
    class ReturnAction implements ActionListener {
        @Override

        public void actionPerformed(ActionEvent e) {
            cl.show(container,"1");
        }
    }
}

Main menu class (this one contains the game generation part):

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

public class MainMenu extends JPanel {
JPanel grid = new JPanel();
MainGame mainGame;
Settings settings;
CardLayout cl;
JPanel container;
String rows;
String columns;
boolean checkexists = false;
int rownumber;
int columnnumber;


public void setMainGame(MainGame mainGame) {
    this.mainGame = mainGame;
}

public void setCl(CardLayout cl) {
    this.cl = cl;
}

public void setContainer(JPanel container) {
    this.container = container;
}

public void setSettings(Settings settings) {
    this.settings = settings;
}

public void setRows(String rows) {
    this.rows = rows;
}

public void setColumns(String columns) {
    this.columns = columns;
}

public MainMenu() {
    setLayout(new GridLayout(3, 1));
    JButton Newgame = new JButton("New Game");
    JButton Cont = new JButton("Continue");
    JButton Sett = new JButton("Settings");
    add(Newgame);
    add(Cont);
    SwitchMenu1 switchMenu1 = new SwitchMenu1();
    SwitchMenu2 switchMenu2 = new SwitchMenu2();
    GenerateGame generateGame = new GenerateGame();
    Newgame.addActionListener(switchMenu2);
    Newgame.addActionListener(generateGame);
    Sett.addActionListener(switchMenu1);
    add(Sett);

}

class SwitchMenu1 implements ActionListener {
    @Override

    public void actionPerformed(ActionEvent e) {
        cl.show(container, "2");

    }
}

class SwitchMenu2 implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        cl.show(container, "3");
    }
}

class GenerateGame implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        if (checkexists == true){
            grid = null;
            grid = new JPanel();
        }
        try {
            rownumber = Integer.parseInt(rows);
        } catch (NumberFormatException be) {
            rownumber = 10;
        }
        try {
            columnnumber = Integer.parseInt(columns);
        } catch (NumberFormatException be) {
            columnnumber = 10;
        }
        Random rand = new Random();
        int randomnumber;
        String Letters = "AAIIOOUUEEABCDEFGHIJKLMNOPQRSTUVWXYZ";
        grid.setLayout(new GridLayout(rownumber, columnnumber));
        JButton[][] gridbutton = new JButton[rownumber][columnnumber];
        MainbuttonAL mainbuttonAL = new MainbuttonAL();
        for (int i = 0; i < rownumber; i++) {
            for (int j = 0; j < columnnumber; j++) {
                if (checkexists == true){
                    gridbutton[i][j] = null;
                }
                randomnumber = rand.nextInt(Letters.length());
                gridbutton[i][j] = new JButton("" + Letters.charAt(randomnumber));
                gridbutton[i][j].addActionListener(mainbuttonAL);
                grid.add(gridbutton[i][j]);
            }
        }
        mainGame.add(grid);
        checkexists = true;
    }
}

class MainbuttonAL implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {

    }
}
}

settings class:

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

public class MainMenu extends JPanel {
    JPanel grid = new JPanel();
    MainGame mainGame;
    Settings settings;
    CardLayout cl;
    JPanel container;
    String rows;
    String columns;
    boolean checkexists = false;
    int rownumber;
    int columnnumber;


    public void setMainGame(MainGame mainGame) {
        this.mainGame = mainGame;
    }

    public void setCl(CardLayout cl) {
        this.cl = cl;
    }

    public void setContainer(JPanel container) {
        this.container = container;
    }

    public void setSettings(Settings settings) {
        this.settings = settings;
    }

    public void setRows(String rows) {
        this.rows = rows;
    }

    public void setColumns(String columns) {
        this.columns = columns;
    }

    public MainMenu() {
        setLayout(new GridLayout(3, 1));
        JButton Newgame = new JButton("New Game");
        JButton Cont = new JButton("Continue");
        JButton Sett = new JButton("Settings");
        add(Newgame);
        add(Cont);
        SwitchMenu1 switchMenu1 = new SwitchMenu1();
        SwitchMenu2 switchMenu2 = new SwitchMenu2();
        GenerateGame generateGame = new GenerateGame();
        Newgame.addActionListener(switchMenu2);
        Newgame.addActionListener(generateGame);
        Sett.addActionListener(switchMenu1);
        add(Sett);

    }

    class SwitchMenu1 implements ActionListener {
        @Override

        public void actionPerformed(ActionEvent e) {
            cl.show(container, "2");

        }
    }

    class SwitchMenu2 implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            cl.show(container, "3");
        }
    }

    class GenerateGame implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (checkexists == true){
                grid = null;
                grid = new JPanel();
            }
            try {
                rownumber = Integer.parseInt(rows);
            } catch (NumberFormatException be) {
                rownumber = 10;
            }
            try {
                columnnumber = Integer.parseInt(columns);
            } catch (NumberFormatException be) {
                columnnumber = 10;
            }
            Random rand = new Random();
            int randomnumber;
            String Letters = "AAIIOOUUEEABCDEFGHIJKLMNOPQRSTUVWXYZ";
            grid.setLayout(new GridLayout(rownumber, columnnumber));
            JButton[][] gridbutton = new JButton[rownumber][columnnumber];
            MainbuttonAL mainbuttonAL = new MainbuttonAL();
            for (int i = 0; i < rownumber; i++) {
                for (int j = 0; j < columnnumber; j++) {
                    if (checkexists == true){
                        gridbutton[i][j] = null;
                    }
                    randomnumber = rand.nextInt(Letters.length());
                    gridbutton[i][j] = new JButton("" + Letters.charAt(randomnumber));
                    gridbutton[i][j].addActionListener(mainbuttonAL);
                    grid.add(gridbutton[i][j]);
                }
            }
            mainGame.add(grid);
            checkexists = true;
        }
    }

    class MainbuttonAL implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {

        }
    }
}

what method can i employ to regenerate a grid?

Advertisement

Answer

In general, you should be working on the concept of decoupling your views and your data, this means that you could have a “game model” which could be applied to a view and the view would then modify itself based on model properties, this is commonly known as “model – view – controller”.

The problem is, however, you never remove grid from it’s parent container when you create a new game

if (checkexists == true){
    grid = null;
    grid = new JPanel();
}

Instead, before you re-intialise the grid, you should remove from it’s parent container

if (grid != null) {
    mainGame.remove(grid);
    grid = null;
    grid = new JPanel();
}

or you could just remove the components from the grid panel itself

grid.removeAll();

A different approach…

At all stages you should be trying to decouple you objects and workflows from each other, so that it’s easier to change any one part without having adverse effects on the other parts of the system or workflow.

Looking at you code, for example, the navigation decisions are tightly coupled to each panel/view, but in reality, they shouldn’t know or care about how the navigation works (or the fact that there are other views), they should just do there job.

You can decouple this workflow through the use of delegation (backed by an observer). This basically means that the individual view doesn’t care “how” the navigation works, only that when it makes a request for some action to be taken, it happens.

You should take the time to read through…

But how does this help you? Well, it will help you all the time!

Lets start with the “game” itself. The first thing we need is some kind of container to hold the data base logic for the game, so based on your current code, it might look something like…

public interface GameModel {
    public int getRows();
    public int getColumns();
}

I know, amazing isn’t it, but this interface would grow to hold the logic required to run your game.

Now, we can apply this to the GamePanel

public class GamePane extends JPanel {
    
    public interface Obsever {
        public void back(GamePane source);
    }

    private GameModel model;
    private Obsever obsever;
    
    private JPanel contentPane;
    
    private ActionListener buttonActionListener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            didTap(e.getActionCommand());
        }
    };
    
    public GamePane(Obsever obsever) {
        this.obsever = obsever;
        
        setLayout(new BorderLayout());
        
        contentPane = new JPanel();
        add(new JScrollPane(contentPane));
        
        JButton backButton = new JButton("<< Back");
        backButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                obsever.back(GamePane.this);
            }
        });
        
        JPanel bannerPane = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.weightx = 1;
        gbc.anchor = GridBagConstraints.LINE_END;
        
        bannerPane.add(backButton, gbc);
        
        add(bannerPane, BorderLayout.NORTH);
    }

    @Override
    public Dimension getPreferredSize() {
        // Bunch of things we could do here, but this basically
        // acts as a stand in for CardLayout, otherwise the primary
        // view will be to small
        return new Dimension(800, 800);
    }

    public void setModel(GameModel model) {
        if (this.model == model) {
            // Do nothing, nothings changed
            return;
        }
        this.model = model;
        buildUI();
    }

    protected void buildUI() {
        contentPane.removeAll();
        if (model == null) {
            return;
        }
        String Letters = "AAIIOOUUEEABCDEFGHIJKLMNOPQRSTUVWXYZ";
        Random rnd = new Random();
        JButton[][] gridbutton = new JButton[model.getRows()][model.getColumns()];
        contentPane.setLayout(new GridLayout(model.getRows(), model.getColumns()));
        //Game.MainMenu.MainbuttonAL mainbuttonAL = new Game.MainMenu.MainbuttonAL();
        for (int i = 0; i < model.getRows(); i++) {
            for (int j = 0; j < model.getColumns(); j++) {
                int randomnumber = rnd.nextInt(Letters.length());
                gridbutton[i][j] = new JButton("" + Letters.charAt(randomnumber));
                //gridbutton[i][j].addActionListener(mainbuttonAL);
                contentPane.add(gridbutton[i][j]);
            }
        }
    }
    
    protected void didTap(String action) {
        
    }

}

Now, the nice “juicy” part is in the buildUI which is called by setModel when the model changes. This just re-builds the UI based on the GameModel properties.

As for the navigation concept, you can see part of it in the GamePane via its Observer interface. I started by creating a seperate class to handle the navigation workflows.

This means that the “how” or “implementation detail” is decoupled or hidden from the other parts of the system. Instead, it makes use of simple observer/delegation workflow.

Each view provides an Observer (for the what of a better name) which describes the navigation actions it needs performed. For example, both the SettingsPane and GamePane simply have back. They don’t care what came before them, that’s up to the navigation controller to decide.

public class NavigationPane extends JPanel {

    enum View {
        MAIN_MENU, GAME, SETTINGS
    }

    private CardLayout cardLayout;
    private GameModel model;
    private GamePane gamePane;
    
    // Just for testing...
    private Random rnd = new Random();

    public NavigationPane() {
        cardLayout = new CardLayout();
        setLayout(cardLayout);

        add(new MainMenu(new MainMenu.Observer() {
            @Override
            public void newGame(MainMenu source) {
                gamePane.setModel(createModel());
                navigateTo(View.GAME);
            }

            @Override
            public void continueGame(MainMenu source) {
                // Because it's possible to push continue
                // without starting a game
                // It might be possible have a "menu" model
                // which can be used to change the enabled state of
                // the continue button based on the state of the
                // game
                gamePane.setModel(getOrCreateGameModel());
                navigateTo(View.GAME);
            }

            @Override
            public void settingsGame(MainMenu source) {
                navigateTo(View.SETTINGS);
            }
        }), View.MAIN_MENU);
        
        gamePane = new GamePane(new GamePane.Obsever() {
            @Override
            public void back(GamePane source) {
                navigateTo(View.MAIN_MENU);
            }
        });
        add(gamePane, View.GAME);
        
        add(new SettingsPane(new SettingsPane.Obsever() {
            @Override
            public void back(SettingsPane source) {
                navigateTo(View.MAIN_MENU);
            }
        }), View.SETTINGS);

        navigateTo(View.MAIN_MENU);
    }
    
    protected GameModel createModel() {
        model = new DefaultGameModel(rnd.nextInt(9) + 2, rnd.nextInt(9) + 2);
        return model;
    }
    
    protected GameModel getOrCreateGameModel() {
        if (model == null) {
            model = createModel();
        }
        return model;
    }

    protected void add(Component component, View view) {
        add(component, view.name());
    }

    protected void navigateTo(View view) {
        cardLayout.show(this, view.name());
    }

}

Runnable example…

So, that’s a lot of out-of-context code. The below is basically an example of one possible approach you could take to further reduce some of the clutter and coupling which is growing in your code base at this time.

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new NavigationPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class NavigationPane extends JPanel {

        enum View {
            MAIN_MENU, GAME, SETTINGS
        }

        private CardLayout cardLayout;
        private GameModel model;
        private GamePane gamePane;

        // Just for testing...
        private Random rnd = new Random();

        public NavigationPane() {
            cardLayout = new CardLayout();
            setLayout(cardLayout);

            add(new MainMenu(new MainMenu.Observer() {
                @Override
                public void newGame(MainMenu source) {
                    gamePane.setModel(createModel());
                    navigateTo(View.GAME);
                }

                @Override
                public void continueGame(MainMenu source) {
                    // Because it's possible to push continue
                    // without starting a game
                    // It might be possible have a "menu" model
                    // which can be used to change the enabled state of
                    // the continue button based on the state of the
                    // game
                    gamePane.setModel(getOrCreateGameModel());
                    navigateTo(View.GAME);
                }

                @Override
                public void settingsGame(MainMenu source) {
                    navigateTo(View.SETTINGS);
                }
            }), View.MAIN_MENU);

            gamePane = new GamePane(new GamePane.Obsever() {
                @Override
                public void back(GamePane source) {
                    navigateTo(View.MAIN_MENU);
                }
            });
            add(gamePane, View.GAME);

            add(new SettingsPane(new SettingsPane.Obsever() {
                @Override
                public void back(SettingsPane source) {
                    navigateTo(View.MAIN_MENU);
                }
            }), View.SETTINGS);

            navigateTo(View.MAIN_MENU);
        }

        protected GameModel createModel() {
            model = new DefaultGameModel(rnd.nextInt(9) + 2, rnd.nextInt(9) + 2);
            return model;
        }

        protected GameModel getOrCreateGameModel() {
            if (model == null) {
                model = createModel();
            }
            return model;
        }

        protected void add(Component component, View view) {
            add(component, view.name());
        }

        protected void navigateTo(View view) {
            cardLayout.show(this, view.name());
        }

    }

    public class MainMenu extends JPanel {

        public interface Observer {
            public void newGame(MainMenu source);
            public void continueGame(MainMenu source);
            public void settingsGame(MainMenu source);
        }

        private Observer observer;

        public MainMenu(Observer observer) {
            this.observer = observer;
            setLayout(new GridBagLayout());

            JButton newGameButton = new JButton("New Game");
            JButton continueButton = new JButton("Continue");
            JButton settingsButton = new JButton("Settings");

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.gridwidth = GridBagConstraints.REMAINDER;

            add(newGameButton, gbc);
            add(continueButton, gbc);
            add(settingsButton, gbc);

            newGameButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    observer.newGame(MainMenu.this);
                }
            });

            continueButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    observer.continueGame(MainMenu.this);
                }
            });

            settingsButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    observer.settingsGame(MainMenu.this);
                }
            });
        }

    }

    public class SettingsPane extends JPanel {

        public interface Obsever {
            public void back(SettingsPane source);
        }

        public SettingsPane(Obsever obsever) {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            add(new JLabel("All your setting belong to us"), gbc);

            JButton backButton = new JButton("<< Back");
            backButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    obsever.back(SettingsPane.this);
                }
            });

            add(backButton, gbc);
        }

    }

    public interface GameModel {
        public int getRows();
        public int getColumns();
    }

    public class DefaultGameModel implements GameModel {

        private int rows;
        private int columns;

        public DefaultGameModel(int rows, int columns) {
            this.rows = rows;
            this.columns = columns;
        }

        @Override
        public int getRows() {
            return rows;
        }

        @Override
        public int getColumns() {
            return columns;
        }

    }

    public class GamePane extends JPanel {

        public interface Obsever {
            public void back(GamePane source);
        }

        private GameModel model;
        private Obsever obsever;

        private JPanel contentPane;

        private ActionListener buttonActionListener = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                didTap(e.getActionCommand());
            }
        };

        public GamePane(Obsever obsever) {
            this.obsever = obsever;

            setLayout(new BorderLayout());

            contentPane = new JPanel();
            add(new JScrollPane(contentPane));

            JButton backButton = new JButton("<< Back");
            backButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    obsever.back(GamePane.this);
                }
            });

            JPanel bannerPane = new JPanel(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.weightx = 1;
            gbc.anchor = GridBagConstraints.LINE_END;

            bannerPane.add(backButton, gbc);

            add(bannerPane, BorderLayout.NORTH);
        }

        @Override
        public Dimension getPreferredSize() {
            // Bunch of things we could do here, but this basically
            // acts as a stand in for CardLayout, otherwise the primary
            // view will be to small
            return new Dimension(800, 800);
        }

        public void setModel(GameModel model) {
            if (this.model == model) {
                // Do nothing, nothings changed
                return;
            }
            this.model = model;
            buildUI();
        }

        protected void buildUI() {
            contentPane.removeAll();
            if (model == null) {
                return;
            }
            String Letters = "AAIIOOUUEEABCDEFGHIJKLMNOPQRSTUVWXYZ";
            Random rnd = new Random();
            JButton[][] gridbutton = new JButton[model.getRows()][model.getColumns()];
            contentPane.setLayout(new GridLayout(model.getRows(), model.getColumns()));
            //Game.MainMenu.MainbuttonAL mainbuttonAL = new Game.MainMenu.MainbuttonAL();
            for (int i = 0; i < model.getRows(); i++) {
                for (int j = 0; j < model.getColumns(); j++) {
                    int randomnumber = rnd.nextInt(Letters.length());
                    gridbutton[i][j] = new JButton("" + Letters.charAt(randomnumber));
                    //gridbutton[i][j].addActionListener(mainbuttonAL);
                    contentPane.add(gridbutton[i][j]);
                }
            }
        }

        protected void didTap(String action) {

        }

    }
}
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement