monoteen

Conway's Game of Life

Nov 4th, 2014
305
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 13.48 KB | None | 0 0
  1. import java.awt.*;
  2. import java.awt.event.*;
  3. import java.net.URI;
  4. import java.util.ArrayList;
  5. import java.util.ConcurrentModificationException;
  6. import javax.swing.*;
  7.  
  8. /**
  9.  * Conway's game of life is a cellular automaton devised by the
  10.  * mathematician John Conway.
  11.  */
  12. public class ConwaysGameOfLife extends JFrame implements ActionListener {
  13.     private static final Dimension DEFAULT_WINDOW_SIZE = new Dimension(800, 600);
  14.     private static final Dimension MINIMUM_WINDOW_SIZE = new Dimension(400, 400);
  15.     private static final int BLOCK_SIZE = 10;
  16.  
  17.     private JMenuBar mb_menu;
  18.     private JMenu m_file, m_game, m_help;
  19.     private JMenuItem mi_file_options, mi_file_exit;
  20.     private JMenuItem mi_game_autofill, mi_game_play, mi_game_stop, mi_game_reset;
  21.     private JMenuItem mi_help_about, mi_help_source;
  22.     private int i_movesPerSecond = 3;
  23.     private GameBoard gb_gameBoard;
  24.     private Thread game;
  25.  
  26.     public static void main(String[] args) {
  27.         // Setup the swing specifics
  28.         JFrame game = new ConwaysGameOfLife();
  29.         game.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  30.         game.setTitle("Conway's Game of Life");
  31.         game.setIconImage(new ImageIcon(ConwaysGameOfLife.class.getResource("/images/logo.png")).getImage());
  32.         game.setSize(DEFAULT_WINDOW_SIZE);
  33.         game.setMinimumSize(MINIMUM_WINDOW_SIZE);
  34.         game.setLocation((Toolkit.getDefaultToolkit().getScreenSize().width - game.getWidth())/2,
  35.                 (Toolkit.getDefaultToolkit().getScreenSize().height - game.getHeight())/2);
  36.         game.setVisible(true);
  37.     }
  38.  
  39.     public ConwaysGameOfLife() {
  40.         // Setup menu
  41.         mb_menu = new JMenuBar();
  42.         setJMenuBar(mb_menu);
  43.         m_file = new JMenu("File");
  44.         mb_menu.add(m_file);
  45.         m_game = new JMenu("Game");
  46.         mb_menu.add(m_game);
  47.         m_help = new JMenu("Help");
  48.         mb_menu.add(m_help);
  49.         mi_file_options = new JMenuItem("Options");
  50.         mi_file_options.addActionListener(this);
  51.         mi_file_exit = new JMenuItem("Exit");
  52.         mi_file_exit.addActionListener(this);
  53.         m_file.add(mi_file_options);
  54.         m_file.add(new JSeparator());
  55.         m_file.add(mi_file_exit);
  56.         mi_game_autofill = new JMenuItem("Autofill");
  57.         mi_game_autofill.addActionListener(this);
  58.         mi_game_play = new JMenuItem("Play");
  59.         mi_game_play.addActionListener(this);
  60.         mi_game_stop = new JMenuItem("Stop");
  61.         mi_game_stop.setEnabled(false);
  62.         mi_game_stop.addActionListener(this);
  63.         mi_game_reset = new JMenuItem("Reset");
  64.         mi_game_reset.addActionListener(this);
  65.         m_game.add(mi_game_autofill);
  66.         m_game.add(new JSeparator());
  67.         m_game.add(mi_game_play);
  68.         m_game.add(mi_game_stop);
  69.         m_game.add(mi_game_reset);
  70.         mi_help_about = new JMenuItem("About");
  71.         mi_help_about.addActionListener(this);
  72.         mi_help_source = new JMenuItem("Source");
  73.         mi_help_source.addActionListener(this);
  74.         m_help.add(mi_help_about);
  75.         m_help.add(mi_help_source);
  76.         // Setup game board
  77.         gb_gameBoard = new GameBoard();
  78.         add(gb_gameBoard);
  79.     }
  80.  
  81.     public void setGameBeingPlayed(boolean isBeingPlayed) {
  82.         if (isBeingPlayed) {
  83.             mi_game_play.setEnabled(false);
  84.             mi_game_stop.setEnabled(true);
  85.             game = new Thread(gb_gameBoard);
  86.             game.start();
  87.         } else {
  88.             mi_game_play.setEnabled(true);
  89.             mi_game_stop.setEnabled(false);
  90.             game.interrupt();
  91.         }
  92.     }
  93.  
  94.     @Override
  95.     public void actionPerformed(ActionEvent ae) {
  96.         if (ae.getSource().equals(mi_file_exit)) {
  97.             // Exit the game
  98.             System.exit(0);
  99.         } else if (ae.getSource().equals(mi_file_options)) {
  100.             // Put up an options panel to change the number of moves per second
  101.             final JFrame f_options = new JFrame();
  102.             f_options.setTitle("Options");
  103.             f_options.setSize(300,60);
  104.             f_options.setLocation((Toolkit.getDefaultToolkit().getScreenSize().width - f_options.getWidth())/2,
  105.                 (Toolkit.getDefaultToolkit().getScreenSize().height - f_options.getHeight())/2);
  106.             f_options.setResizable(false);
  107.             JPanel p_options = new JPanel();
  108.             p_options.setOpaque(false);
  109.             f_options.add(p_options);
  110.             p_options.add(new JLabel("Number of moves per second:"));
  111.             Integer[] secondOptions = {1,2,3,4,5,10,15,20};
  112.             final JComboBox cb_seconds = new JComboBox(secondOptions);
  113.             p_options.add(cb_seconds);
  114.             cb_seconds.setSelectedItem(i_movesPerSecond);
  115.             cb_seconds.addActionListener(new ActionListener(){
  116.                 @Override
  117.                 public void actionPerformed(ActionEvent ae) {
  118.                     i_movesPerSecond = (Integer)cb_seconds.getSelectedItem();
  119.                     f_options.dispose();
  120.                 }
  121.             });
  122.             f_options.setVisible(true);
  123.         } else if (ae.getSource().equals(mi_game_autofill)) {
  124.             final JFrame f_autoFill = new JFrame();
  125.             f_autoFill.setTitle("Autofill");
  126.             f_autoFill.setSize(360, 60);
  127.             f_autoFill.setLocation((Toolkit.getDefaultToolkit().getScreenSize().width - f_autoFill.getWidth())/2,
  128.                 (Toolkit.getDefaultToolkit().getScreenSize().height - f_autoFill.getHeight())/2);
  129.             f_autoFill.setResizable(false);
  130.             JPanel p_autoFill = new JPanel();
  131.             p_autoFill.setOpaque(false);
  132.             f_autoFill.add(p_autoFill);
  133.             p_autoFill.add(new JLabel("What percentage should be filled? "));
  134.             Object[] percentageOptions = {"Select",5,10,15,20,25,30,40,50,60,70,80,90,95};
  135.             final JComboBox cb_percent = new JComboBox(percentageOptions);
  136.             p_autoFill.add(cb_percent);
  137.             cb_percent.addActionListener(new ActionListener() {
  138.                 @Override
  139.                 public void actionPerformed(ActionEvent e) {
  140.                     if (cb_percent.getSelectedIndex() > 0) {
  141.                         gb_gameBoard.resetBoard();
  142.                         gb_gameBoard.randomlyFillBoard((Integer)cb_percent.getSelectedItem());
  143.                         f_autoFill.dispose();
  144.                     }
  145.                 }
  146.             });
  147.             f_autoFill.setVisible(true);
  148.         } else if (ae.getSource().equals(mi_game_reset)) {
  149.             gb_gameBoard.resetBoard();
  150.             gb_gameBoard.repaint();
  151.         } else if (ae.getSource().equals(mi_game_play)) {
  152.             setGameBeingPlayed(true);
  153.         } else if (ae.getSource().equals(mi_game_stop)) {
  154.             setGameBeingPlayed(false);
  155.         } else if (ae.getSource().equals(mi_help_source)) {
  156.             Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null;
  157.             try {
  158.                 desktop.browse(new URI("https://github.com/Burke9077/Conway-s-Game-of-Life"));
  159.             } catch (Exception ex) {
  160.                 JOptionPane.showMessageDialog(null, "Source is available on GitHub at:\nhttps://github.com/Burke9077/Conway-s-Game-of-Life", "Source", JOptionPane.INFORMATION_MESSAGE);
  161.             }
  162.         } else if (ae.getSource().equals(mi_help_about)) {
  163.             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\n[email protected]\n@burke9077\n\nCreative Commons Attribution 4.0 International");
  164.         }
  165.     }
  166.  
  167.     private class GameBoard extends JPanel implements ComponentListener, MouseListener, MouseMotionListener, Runnable {
  168.         private Dimension d_gameBoardSize = null;
  169.         private ArrayList<Point> point = new ArrayList<Point>(0);
  170.  
  171.         public GameBoard() {
  172.             // Add resizing listener
  173.             addComponentListener(this);
  174.             addMouseListener(this);
  175.             addMouseMotionListener(this);
  176.         }
  177.  
  178.         private void updateArraySize() {
  179.             ArrayList<Point> removeList = new ArrayList<Point>(0);
  180.             for (Point current : point) {
  181.                 if ((current.x > d_gameBoardSize.width-1) || (current.y > d_gameBoardSize.height-1)) {
  182.                     removeList.add(current);
  183.                 }
  184.             }
  185.             point.removeAll(removeList);
  186.             repaint();
  187.         }
  188.  
  189.         public void addPoint(int x, int y) {
  190.             if (!point.contains(new Point(x,y))) {
  191.                 point.add(new Point(x,y));
  192.             }
  193.             repaint();
  194.         }
  195.  
  196.         public void addPoint(MouseEvent me) {
  197.             int x = me.getPoint().x/10-1;
  198.             int y = me.getPoint().y/10-1;
  199.             if ((x >= 0) && (x < d_gameBoardSize.width) && (y >= 0) && (y < d_gameBoardSize.height)) {
  200.                 addPoint(x,y);
  201.             }
  202.         }
  203.  
  204.         public void removePoint(int x, int y) {
  205.             point.remove(new Point(x,y));
  206.         }
  207.  
  208.         public void resetBoard() {
  209.             point.clear();
  210.         }
  211.  
  212.         public void randomlyFillBoard(int percent) {
  213.             for (int i=0; i<d_gameBoardSize.width; i++) {
  214.                 for (int j=0; j<d_gameBoardSize.height; j++) {
  215.                     if (Math.random()*100 < percent) {
  216.                         addPoint(i,j);
  217.                     }
  218.                 }
  219.             }
  220.         }
  221.  
  222.         @Override
  223.         public void paintComponent(Graphics g) {
  224.             super.paintComponent(g);
  225.             try {
  226.                 for (Point newPoint : point) {
  227.                     // Draw new point
  228.                     g.setColor(Color.blue);
  229.                     g.fillRect(BLOCK_SIZE + (BLOCK_SIZE*newPoint.x), BLOCK_SIZE + (BLOCK_SIZE*newPoint.y), BLOCK_SIZE, BLOCK_SIZE);
  230.                 }
  231.             } catch (ConcurrentModificationException cme) {}
  232.             // Setup grid
  233.             g.setColor(Color.BLACK);
  234.             for (int i=0; i<=d_gameBoardSize.width; i++) {
  235.                 g.drawLine(((i*BLOCK_SIZE)+BLOCK_SIZE), BLOCK_SIZE, (i*BLOCK_SIZE)+BLOCK_SIZE, BLOCK_SIZE + (BLOCK_SIZE*d_gameBoardSize.height));
  236.             }
  237.             for (int i=0; i<=d_gameBoardSize.height; i++) {
  238.                 g.drawLine(BLOCK_SIZE, ((i*BLOCK_SIZE)+BLOCK_SIZE), BLOCK_SIZE*(d_gameBoardSize.width+1), ((i*BLOCK_SIZE)+BLOCK_SIZE));
  239.             }
  240.         }
  241.  
  242.         @Override
  243.         public void componentResized(ComponentEvent e) {
  244.             // Setup the game board size with proper boundries
  245.             d_gameBoardSize = new Dimension(getWidth()/BLOCK_SIZE-2, getHeight()/BLOCK_SIZE-2);
  246.             updateArraySize();
  247.         }
  248.         @Override
  249.         public void componentMoved(ComponentEvent e) {}
  250.         @Override
  251.         public void componentShown(ComponentEvent e) {}
  252.         @Override
  253.         public void componentHidden(ComponentEvent e) {}
  254.         @Override
  255.         public void mouseClicked(MouseEvent e) {}
  256.         @Override
  257.         public void mousePressed(MouseEvent e) {}
  258.         @Override
  259.         public void mouseReleased(MouseEvent e) {
  260.             // Mouse was released (user clicked)
  261.             addPoint(e);
  262.         }
  263.         @Override
  264.         public void mouseEntered(MouseEvent e) {}
  265.  
  266.         @Override
  267.         public void mouseExited(MouseEvent e) {}
  268.  
  269.         @Override
  270.         public void mouseDragged(MouseEvent e) {
  271.             // Mouse is being dragged, user wants multiple selections
  272.             addPoint(e);
  273.         }
  274.         @Override
  275.         public void mouseMoved(MouseEvent e) {}
  276.  
  277.         @Override
  278.         public void run() {
  279.             boolean[][] gameBoard = new boolean[d_gameBoardSize.width+2][d_gameBoardSize.height+2];
  280.             for (Point current : point) {
  281.                 gameBoard[current.x+1][current.y+1] = true;
  282.             }
  283.             ArrayList<Point> survivingCells = new ArrayList<Point>(0);
  284.             // Iterate through the array, follow game of life rules
  285.             for (int i=1; i<gameBoard.length-1; i++) {
  286.                 for (int j=1; j<gameBoard[0].length-1; j++) {
  287.                     int surrounding = 0;
  288.                     if (gameBoard[i-1][j-1]) { surrounding++; }
  289.                     if (gameBoard[i-1][j])   { surrounding++; }
  290.                     if (gameBoard[i-1][j+1]) { surrounding++; }
  291.                     if (gameBoard[i][j-1])   { surrounding++; }
  292.                     if (gameBoard[i][j+1])   { surrounding++; }
  293.                     if (gameBoard[i+1][j-1]) { surrounding++; }
  294.                     if (gameBoard[i+1][j])   { surrounding++; }
  295.                     if (gameBoard[i+1][j+1]) { surrounding++; }
  296.                     if (gameBoard[i][j]) {
  297.                         // Cell is alive, Can the cell live? (2-3)
  298.                         if ((surrounding == 2) || (surrounding == 3)) {
  299.                             survivingCells.add(new Point(i-1,j-1));
  300.                         }
  301.                     } else {
  302.                         // Cell is dead, will the cell be given birth? (3)
  303.                         if (surrounding == 3) {
  304.                             survivingCells.add(new Point(i-1,j-1));
  305.                         }
  306.                     }
  307.                 }
  308.             }
  309.             resetBoard();
  310.             point.addAll(survivingCells);
  311.             repaint();
  312.             try {
  313.                 Thread.sleep(1000/i_movesPerSecond);
  314.                 run();
  315.             } catch (InterruptedException ex) {}
  316.         }
  317.     }
  318. }
Advertisement
Add Comment
Please, Sign In to add comment