A simple Game of Life implementation in Java
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

276 lines
8.3 KiB

  1. package edu.stuy.goldfish;
  2. import java.util.Random;
  3. import java.awt.*;
  4. import java.awt.event.*;
  5. import java.awt.image.*;
  6. import javax.swing.*;
  7. import javax.swing.event.*;
  8. public class Render extends Canvas implements Runnable, MouseListener,
  9. MouseMotionListener, ActionListener {
  10. private static final long serialVersionUID = 1L;
  11. public static String title;
  12. public static int width;
  13. public static int height;
  14. public static int scale;
  15. public int fps_now;
  16. public boolean paused;
  17. public String rule;
  18. public boolean reset;
  19. private Grid _grid;
  20. private int[] _pixels;
  21. private BufferedImage _image;
  22. private long _lastTick;
  23. private String[] _rules;
  24. private JFrame _frame;
  25. private JButton pauseButton;
  26. private Random random = new Random();
  27. public Render(int width, int height, Grid g, String[] rules) {
  28. addMouseListener(this);
  29. addMouseMotionListener(this);
  30. Render.title = "Goldfish: " + rules[0];
  31. Render.width = width;
  32. Render.height = height;
  33. setScale();
  34. paused = false;
  35. reset = false;
  36. rule = rules[0];
  37. _grid = g;
  38. _image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
  39. _pixels = ((DataBufferInt) _image.getRaster().getDataBuffer()).getData();
  40. _lastTick = 0;
  41. _rules = rules;
  42. fps_now = 15;
  43. setFrame();
  44. }
  45. public Render(int width, int height, Grid g) {
  46. this(width, height, g, new String[0]);
  47. }
  48. public Render(int width, int height) {
  49. this(width, height, new Grid(width, height));
  50. }
  51. public Render() {
  52. this(256, 256);
  53. }
  54. private void setScale() {
  55. if (height <= 128 || width <= 128) {
  56. Render.scale = 4;
  57. } else if (height <= 256 || width <= 256) {
  58. Render.scale = 2;
  59. } else {
  60. Render.scale = 1;
  61. }
  62. }
  63. private void setFrame() {
  64. JMenuBar menuBar = new JMenuBar();
  65. JMenu menuAlgo = new JMenu("Algorithms");
  66. for (String rule : _rules) {
  67. JMenuItem menuAlgoItem = new JMenuItem(rule);
  68. menuAlgo.add(menuAlgoItem);
  69. menuAlgoItem.addActionListener(this);
  70. }
  71. menuBar.add(menuAlgo);
  72. pauseButton = new JButton("Pause");
  73. pauseButton.setActionCommand("pause");
  74. pauseButton.setPreferredSize(new Dimension(90,0));
  75. menuBar.add(pauseButton);
  76. pauseButton.addActionListener(this);
  77. JButton resetButton = new JButton("Reset");
  78. resetButton.setActionCommand("reset");
  79. menuBar.add(resetButton);
  80. resetButton.addActionListener(this);
  81. JButton randomButton = new JButton("Random");
  82. randomButton.setActionCommand("random");
  83. menuBar.add(randomButton);
  84. randomButton.addActionListener(this);
  85. JButton clearButton = new JButton("Clear");
  86. clearButton.setActionCommand("clear");
  87. menuBar.add(clearButton);
  88. clearButton.addActionListener(this);
  89. JSlider framesPerSecond = new JSlider(JSlider.HORIZONTAL, 0, 30, 15);
  90. ChangeListener fpschange = new ChangeListener() {
  91. @Override
  92. public void stateChanged(ChangeEvent event) {
  93. JSlider source = (JSlider) event.getSource();
  94. if (!source.getValueIsAdjusting()) {
  95. int fps = (int) source.getValue();
  96. if (fps == 0) {
  97. paused = true;
  98. pauseButton.setText("Unpause");
  99. } else {
  100. paused = false;
  101. fps_now = fps;
  102. pauseButton.setText("Pause");
  103. }
  104. }
  105. }
  106. };
  107. framesPerSecond.addChangeListener(fpschange);
  108. framesPerSecond.setMajorTickSpacing(10);
  109. framesPerSecond.setMinorTickSpacing(1);
  110. framesPerSecond.setPaintTicks(true);
  111. framesPerSecond.setPaintLabels(true);
  112. framesPerSecond.setPreferredSize(new Dimension(100,40));
  113. menuBar.add(framesPerSecond);
  114. setPreferredSize(new Dimension(width * scale, height * scale));
  115. _frame = new JFrame();
  116. _frame.setJMenuBar(menuBar);
  117. _frame.setResizable(false);
  118. _frame.setTitle(title);
  119. _frame.add(this);
  120. _frame.pack();
  121. _frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  122. _frame.setLocationRelativeTo(null);
  123. _frame.setVisible(true);
  124. }
  125. private void update() {
  126. int state;
  127. int states = Goldfish.getMaxStates(rule);
  128. for (int i = 0; i < width; i++) {
  129. for (int j = 0; j < height; j++) {
  130. state = _grid.getPatch(i, j).getState();
  131. if (_pixels[i + j * width] == state) {
  132. } else {
  133. draw(i, j, (int) ((state / ((double) states - 1)) * 0xffffff));
  134. }
  135. }
  136. }
  137. }
  138. public void run() {
  139. BufferStrategy bs;
  140. Graphics g;
  141. bs = getBufferStrategy();
  142. if (bs == null) {
  143. createBufferStrategy(1);
  144. return;
  145. }
  146. update();
  147. g = bs.getDrawGraphics();
  148. g.drawImage(_image, 0, 0, getWidth(), getHeight(), null);
  149. g.dispose();
  150. bs.show();
  151. }
  152. public void sleep() {
  153. long since = System.currentTimeMillis() - _lastTick;
  154. if (since < 1000 / fps_now) {
  155. try {
  156. Thread.sleep(1000 / fps_now - since);
  157. } catch (InterruptedException e) {
  158. return;
  159. }
  160. }
  161. _lastTick = System.currentTimeMillis();
  162. }
  163. public void setGrid(Grid g) {
  164. _grid = g;
  165. }
  166. public void draw(int x, int y, int color) {
  167. _pixels[x + y * width] = color;
  168. }
  169. public void clear() {
  170. for (int i = 0; i < _grid.getHeight(); i++) {
  171. for (int j = 0; j < _grid.getWidth(); j++) {
  172. _grid.getPatch(i, j).setState(0);
  173. }
  174. }
  175. }
  176. public void randomize() {
  177. for (int i = 0; i < _grid.getHeight(); i++) {
  178. for (int j = 0; j < _grid.getWidth(); j++) {
  179. _grid.getPatch(i, j).setState(random.nextInt(Goldfish.getMaxStates(rule)));
  180. }
  181. }
  182. }
  183. @Override
  184. public void mouseDragged(MouseEvent e) {
  185. int states = Goldfish.getMaxStates(rule) - 1;
  186. if (e.getX() < 0 || e.getY() < 0 || e.getX() / scale > width || e.getY() / scale > height)
  187. return;
  188. _grid.getPatch(e.getX() / scale, e.getY() / scale).setState(states);
  189. e.consume();
  190. }
  191. @Override
  192. public void mouseClicked(MouseEvent e) {
  193. int states = Goldfish.getMaxStates(rule) - 1;
  194. _grid.getPatch(e.getX() / scale, e.getY() / scale).setState(states);
  195. e.consume();
  196. }
  197. @Override
  198. public void mouseEntered(MouseEvent e) {
  199. }
  200. @Override
  201. public void mouseExited(MouseEvent e) {
  202. }
  203. @Override
  204. public void mousePressed(MouseEvent e) {
  205. int states = Goldfish.getMaxStates(rule) - 1;
  206. _grid.getPatch(e.getX() / scale, e.getY() / scale).setState(states);
  207. e.consume();
  208. }
  209. @Override
  210. public void mouseReleased(MouseEvent e) {
  211. }
  212. @Override
  213. public void mouseMoved(MouseEvent e) {
  214. }
  215. @Override
  216. public void actionPerformed(ActionEvent event) {
  217. if ("pause".equals(event.getActionCommand())) {
  218. if (paused) {
  219. paused = false;
  220. pauseButton.setText("Pause");
  221. } else {
  222. paused = true;
  223. pauseButton.setText("Unpause");
  224. }
  225. } else if ("reset".equals(event.getActionCommand())) {
  226. clear();
  227. reset = true;
  228. } else if ("random".equals(event.getActionCommand())) {
  229. randomize();
  230. } else if ("clear".equals(event.getActionCommand())) {
  231. clear();
  232. } else {
  233. rule = event.getActionCommand();
  234. title = "Goldfish: " + rule;
  235. _frame.setTitle(title);
  236. }
  237. }
  238. }