⚠️ Warning: This is a draft ⚠️
This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.
If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.
{{works with|Java|6+}}
This swing based implementation will take user input, and can be interacted with using the mouse.
import java.awt.*; import java.awt.event.*; import java.net.URI; import java.util.ArrayList; import java.util.ConcurrentModificationException; import javax.swing.*; /** * Conway's game of life is a cellular automaton devised by the * mathematician John Conway. */ public class ConwaysGameOfLife extends JFrame implements ActionListener { private static final Dimension DEFAULT_WINDOW_SIZE = new Dimension(800, 600); private static final Dimension MINIMUM_WINDOW_SIZE = new Dimension(400, 400); private static final int BLOCK_SIZE = 10; private JMenuBar mb_menu; private JMenu m_file, m_game, m_help; private JMenuItem mi_file_options, mi_file_exit; private JMenuItem mi_game_autofill, mi_game_play, mi_game_stop, mi_game_reset; private JMenuItem mi_help_about, mi_help_source; private int i_movesPerSecond = 3; private GameBoard gb_gameBoard; private Thread game; public static void main(String[] args) { // Setup the swing specifics JFrame game = new ConwaysGameOfLife(); game.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); game.setTitle("Conway's Game of Life"); game.setIconImage(new ImageIcon(ConwaysGameOfLife.class.getResource("/images/logo.png")).getImage()); game.setSize(DEFAULT_WINDOW_SIZE); game.setMinimumSize(MINIMUM_WINDOW_SIZE); game.setLocation((Toolkit.getDefaultToolkit().getScreenSize().width - game.getWidth())/2, (Toolkit.getDefaultToolkit().getScreenSize().height - game.getHeight())/2); game.setVisible(true); } public ConwaysGameOfLife() { // Setup menu mb_menu = new JMenuBar(); setJMenuBar(mb_menu); m_file = new JMenu("File"); mb_menu.add(m_file); m_game = new JMenu("Game"); mb_menu.add(m_game); m_help = new JMenu("Help"); mb_menu.add(m_help); mi_file_options = new JMenuItem("Options"); mi_file_options.addActionListener(this); mi_file_exit = new JMenuItem("Exit"); mi_file_exit.addActionListener(this); m_file.add(mi_file_options); m_file.add(new JSeparator()); m_file.add(mi_file_exit); mi_game_autofill = new JMenuItem("Autofill"); mi_game_autofill.addActionListener(this); mi_game_play = new JMenuItem("Play"); mi_game_play.addActionListener(this); mi_game_stop = new JMenuItem("Stop"); mi_game_stop.setEnabled(false); mi_game_stop.addActionListener(this); mi_game_reset = new JMenuItem("Reset"); mi_game_reset.addActionListener(this); m_game.add(mi_game_autofill); m_game.add(new JSeparator()); m_game.add(mi_game_play); m_game.add(mi_game_stop); m_game.add(mi_game_reset); mi_help_about = new JMenuItem("About"); mi_help_about.addActionListener(this); mi_help_source = new JMenuItem("Source"); mi_help_source.addActionListener(this); m_help.add(mi_help_about); m_help.add(mi_help_source); // Setup game board gb_gameBoard = new GameBoard(); add(gb_gameBoard); } public void setGameBeingPlayed(boolean isBeingPlayed) { if (isBeingPlayed) { mi_game_play.setEnabled(false); mi_game_stop.setEnabled(true); game = new Thread(gb_gameBoard); game.start(); } else { mi_game_play.setEnabled(true); mi_game_stop.setEnabled(false); game.interrupt(); } } @Override public void actionPerformed(ActionEvent ae) { if (ae.getSource().equals(mi_file_exit)) { // Exit the game System.exit(0); } else if (ae.getSource().equals(mi_file_options)) { // Put up an options panel to change the number of moves per second final JFrame f_options = new JFrame(); f_options.setTitle("Options"); f_options.setSize(300,60); f_options.setLocation((Toolkit.getDefaultToolkit().getScreenSize().width - f_options.getWidth())/2, (Toolkit.getDefaultToolkit().getScreenSize().height - f_options.getHeight())/2); f_options.setResizable(false); JPanel p_options = new JPanel(); p_options.setOpaque(false); f_options.add(p_options); p_options.add(new JLabel("Number of moves per second:")); Integer[] secondOptions = {1,2,3,4,5,10,15,20}; final JComboBox cb_seconds = new JComboBox(secondOptions); p_options.add(cb_seconds); cb_seconds.setSelectedItem(i_movesPerSecond); cb_seconds.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent ae) { i_movesPerSecond = (Integer)cb_seconds.getSelectedItem(); f_options.dispose(); } }); f_options.setVisible(true); } else if (ae.getSource().equals(mi_game_autofill)) { final JFrame f_autoFill = new JFrame(); f_autoFill.setTitle("Autofill"); f_autoFill.setSize(360, 60); f_autoFill.setLocation((Toolkit.getDefaultToolkit().getScreenSize().width - f_autoFill.getWidth())/2, (Toolkit.getDefaultToolkit().getScreenSize().height - f_autoFill.getHeight())/2); f_autoFill.setResizable(false); JPanel p_autoFill = new JPanel(); p_autoFill.setOpaque(false); f_autoFill.add(p_autoFill); p_autoFill.add(new JLabel("What percentage should be filled? ")); Object[] percentageOptions = {"Select",5,10,15,20,25,30,40,50,60,70,80,90,95}; final JComboBox cb_percent = new JComboBox(percentageOptions); p_autoFill.add(cb_percent); cb_percent.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (cb_percent.getSelectedIndex() > 0) { gb_gameBoard.resetBoard(); gb_gameBoard.randomlyFillBoard((Integer)cb_percent.getSelectedItem()); f_autoFill.dispose(); } } }); f_autoFill.setVisible(true); } else if (ae.getSource().equals(mi_game_reset)) { gb_gameBoard.resetBoard(); gb_gameBoard.repaint(); } else if (ae.getSource().equals(mi_game_play)) { setGameBeingPlayed(true); } else if (ae.getSource().equals(mi_game_stop)) { setGameBeingPlayed(false); } else if (ae.getSource().equals(mi_help_source)) { Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; try { desktop.browse(new URI("https://github.com/Burke9077/Conway-s-Game-of-Life")); } catch (Exception ex) { JOptionPane.showMessageDialog(null, "Source is available on GitHub at:\nhttps://github.com/Burke9077/Conway-s-Game-of-Life", "Source", JOptionPane.INFORMATION_MESSAGE); } } else if (ae.getSource().equals(mi_help_about)) { JOptionPane.showMessageDialog(null, "Conway's game of life was a cellular animation devised by the mathematician John Conway.\nThis Java, swing based implementation was created by Matthew Burke.\n\nhttp://burke9077.com\nBurke9077@gmail.com\n@burke9077\n\nCreative Commons Attribution 4.0 International"); } } private class GameBoard extends JPanel implements ComponentListener, MouseListener, MouseMotionListener, Runnable { private Dimension d_gameBoardSize = null; private ArrayList<Point> point = new ArrayList<Point>(0); public GameBoard() { // Add resizing listener addComponentListener(this); addMouseListener(this); addMouseMotionListener(this); } private void updateArraySize() { ArrayList<Point> removeList = new ArrayList<Point>(0); for (Point current : point) { if ((current.x > d_gameBoardSize.width-1) || (current.y > d_gameBoardSize.height-1)) { removeList.add(current); } } point.removeAll(removeList); repaint(); } public void addPoint(int x, int y) { if (!point.contains(new Point(x,y))) { point.add(new Point(x,y)); } repaint(); } public void addPoint(MouseEvent me) { int x = me.getPoint().x/BLOCK_SIZE-1; int y = me.getPoint().y/BLOCK_SIZE-1; if ((x >= 0) && (x < d_gameBoardSize.width) && (y >= 0) && (y < d_gameBoardSize.height)) { addPoint(x,y); } } public void removePoint(int x, int y) { point.remove(new Point(x,y)); } public void resetBoard() { point.clear(); } public void randomlyFillBoard(int percent) { for (int i=0; i<d_gameBoardSize.width; i++) { for (int j=0; j<d_gameBoardSize.height; j++) { if (Math.random()*100 < percent) { addPoint(i,j); } } } } @Override public void paintComponent(Graphics g) { super.paintComponent(g); try { for (Point newPoint : point) { // Draw new point g.setColor(Color.blue); g.fillRect(BLOCK_SIZE + (BLOCK_SIZE*newPoint.x), BLOCK_SIZE + (BLOCK_SIZE*newPoint.y), BLOCK_SIZE, BLOCK_SIZE); } } catch (ConcurrentModificationException cme) {} // Setup grid g.setColor(Color.BLACK); for (int i=0; i<=d_gameBoardSize.width; i++) { g.drawLine(((i*BLOCK_SIZE)+BLOCK_SIZE), BLOCK_SIZE, (i*BLOCK_SIZE)+BLOCK_SIZE, BLOCK_SIZE + (BLOCK_SIZE*d_gameBoardSize.height)); } for (int i=0; i<=d_gameBoardSize.height; i++) { g.drawLine(BLOCK_SIZE, ((i*BLOCK_SIZE)+BLOCK_SIZE), BLOCK_SIZE*(d_gameBoardSize.width+1), ((i*BLOCK_SIZE)+BLOCK_SIZE)); } } @Override public void componentResized(ComponentEvent e) { // Setup the game board size with proper boundries d_gameBoardSize = new Dimension(getWidth()/BLOCK_SIZE-2, getHeight()/BLOCK_SIZE-2); updateArraySize(); } @Override public void componentMoved(ComponentEvent e) {} @Override public void componentShown(ComponentEvent e) {} @Override public void componentHidden(ComponentEvent e) {} @Override public void mouseClicked(MouseEvent e) {} @Override public void mousePressed(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) { // Mouse was released (user clicked) addPoint(e); } @Override public void mouseEntered(MouseEvent e) {} @Override public void mouseExited(MouseEvent e) {} @Override public void mouseDragged(MouseEvent e) { // Mouse is being dragged, user wants multiple selections addPoint(e); } @Override public void mouseMoved(MouseEvent e) {} @Override public void run() { boolean[][] gameBoard = new boolean[d_gameBoardSize.width+2][d_gameBoardSize.height+2]; for (Point current : point) { gameBoard[current.x+1][current.y+1] = true; } ArrayList<Point> survivingCells = new ArrayList<Point>(0); // Iterate through the array, follow game of life rules for (int i=1; i<gameBoard.length-1; i++) { for (int j=1; j<gameBoard[0].length-1; j++) { int surrounding = 0; if (gameBoard[i-1][j-1]) { surrounding++; } if (gameBoard[i-1][j]) { surrounding++; } if (gameBoard[i-1][j+1]) { surrounding++; } if (gameBoard[i][j-1]) { surrounding++; } if (gameBoard[i][j+1]) { surrounding++; } if (gameBoard[i+1][j-1]) { surrounding++; } if (gameBoard[i+1][j]) { surrounding++; } if (gameBoard[i+1][j+1]) { surrounding++; } if (gameBoard[i][j]) { // Cell is alive, Can the cell live? (2-3) if ((surrounding == 2) || (surrounding == 3)) { survivingCells.add(new Point(i-1,j-1)); } } else { // Cell is dead, will the cell be given birth? (3) if (surrounding == 3) { survivingCells.add(new Point(i-1,j-1)); } } } } resetBoard(); point.addAll(survivingCells); repaint(); try { Thread.sleep(1000/i_movesPerSecond); run(); } catch (InterruptedException ex) {} } } }