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.

312 lines
9.7 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. private Patch _lastPatch;
  28. public Render(int width, int height, Grid g, String[] rules) {
  29. addMouseListener(this);
  30. addMouseMotionListener(this);
  31. Render.title = "Goldfish: " + rules[0];
  32. Render.width = width;
  33. Render.height = height;
  34. setScale();
  35. paused = false;
  36. reset = false;
  37. rule = rules[0];
  38. _grid = g;
  39. _image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
  40. _pixels = ((DataBufferInt) _image.getRaster().getDataBuffer()).getData();
  41. _lastTick = 0;
  42. _rules = rules;
  43. _lastPatch = null;
  44. fps_now = 15;
  45. setFrame();
  46. }
  47. public Render(int width, int height, Grid g) {
  48. this(width, height, g, new String[0]);
  49. }
  50. public Render(int width, int height) {
  51. this(width, height, new Grid(width, height));
  52. }
  53. public Render() {
  54. this(256, 256);
  55. }
  56. private void setScale() {
  57. if (height <= 128 || width <= 128) {
  58. Render.scale = 4;
  59. } else if (height <= 256 || width <= 256) {
  60. Render.scale = 2;
  61. } else {
  62. Render.scale = 1;
  63. }
  64. }
  65. private void setFrame() {
  66. JMenuBar menuBar = new JMenuBar();
  67. JMenu menuAlgo = new JMenu("Algorithms");
  68. menuAlgo.setFont(new Font("Arial",1,12));
  69. menuAlgo.setPreferredSize(new Dimension(75,0));
  70. for (String rule : _rules) {
  71. JMenuItem menuAlgoItem = new JMenuItem(rule);
  72. menuAlgo.add(menuAlgoItem);
  73. menuAlgoItem.addActionListener(this);
  74. }
  75. menuBar.add(menuAlgo);
  76. pauseButton = new JButton("Pause");
  77. pauseButton.setActionCommand("pause");
  78. pauseButton.setFont(new Font("Arial", 0, 12));
  79. pauseButton.setPreferredSize(new Dimension(90, 0));
  80. menuBar.add(pauseButton);
  81. pauseButton.addActionListener(this);
  82. JButton resetButton = new JButton("Reset");
  83. resetButton.setActionCommand("reset");
  84. resetButton.setFont(new Font("Arial", 0, 12));
  85. menuBar.add(resetButton);
  86. resetButton.addActionListener(this);
  87. JButton randomButton = new JButton("Random");
  88. randomButton.setActionCommand("random");
  89. randomButton.setFont(new Font("Arial", 0, 12));
  90. menuBar.add(randomButton);
  91. randomButton.addActionListener(this);
  92. JButton clearButton = new JButton("Clear");
  93. clearButton.setActionCommand("clear");
  94. clearButton.setFont(new Font("Arial", 0, 12));
  95. menuBar.add(clearButton);
  96. clearButton.addActionListener(this);
  97. JSlider framesPerSecond = new JSlider(JSlider.HORIZONTAL, 0, 30, 15);
  98. ChangeListener fpschange = new ChangeListener() {
  99. @Override
  100. public void stateChanged(ChangeEvent event) {
  101. JSlider source = (JSlider) event.getSource();
  102. if (!source.getValueIsAdjusting()) {
  103. int fps = (int) source.getValue();
  104. if (fps == 0) {
  105. paused = true;
  106. pauseButton.setText("Unpause");
  107. } else {
  108. paused = false;
  109. fps_now = fps;
  110. pauseButton.setText("Pause");
  111. }
  112. }
  113. }
  114. };
  115. framesPerSecond.addChangeListener(fpschange);
  116. framesPerSecond.setMajorTickSpacing(10);
  117. framesPerSecond.setMinorTickSpacing(1);
  118. framesPerSecond.setPaintTicks(true);
  119. framesPerSecond.setPaintLabels(true);
  120. framesPerSecond.setFont(new Font("Arial", 0, 12));
  121. framesPerSecond.setPreferredSize(new Dimension(100, 0));
  122. menuBar.add(framesPerSecond);
  123. menuBar.setPreferredSize(new Dimension(width * scale, 40));
  124. setPreferredSize(new Dimension(width * scale, height * scale));
  125. _frame = new JFrame();
  126. _frame.setJMenuBar(menuBar);
  127. _frame.setResizable(false);
  128. _frame.setTitle(title);
  129. _frame.add(this);
  130. _frame.pack();
  131. _frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  132. _frame.setLocationRelativeTo(null);
  133. _frame.setVisible(true);
  134. }
  135. private void update() {
  136. int state;
  137. int states = Goldfish.getMaxStates(rule);
  138. for (int i = 0; i < width; i++) {
  139. for (int j = 0; j < height; j++) {
  140. state = _grid.getPatch(i, j).getState();
  141. draw(i, j, (int) ((state / ((double) states - 1)) * 0xffffff));
  142. }
  143. }
  144. }
  145. public void run() {
  146. BufferStrategy bs;
  147. Graphics g;
  148. bs = getBufferStrategy();
  149. if (bs == null) {
  150. createBufferStrategy(1);
  151. return;
  152. }
  153. update();
  154. g = bs.getDrawGraphics();
  155. g.drawImage(_image, 0, 0, getWidth(), getHeight(), null);
  156. g.dispose();
  157. bs.show();
  158. }
  159. public void sleep() {
  160. long since = System.currentTimeMillis() - _lastTick;
  161. if (since < 1000 / fps_now) {
  162. try {
  163. Thread.sleep(1000 / fps_now - since);
  164. } catch (InterruptedException e) {
  165. return;
  166. }
  167. }
  168. _lastTick = System.currentTimeMillis();
  169. }
  170. public void setGrid(Grid g) {
  171. _grid = g;
  172. }
  173. public void draw(int x, int y, int color) {
  174. if (_pixels[x + y * width] != color)
  175. _pixels[x + y * width] = color;
  176. }
  177. public void clear() {
  178. for (int i = 0; i < _grid.getHeight(); i++) {
  179. for (int j = 0; j < _grid.getWidth(); j++) {
  180. _grid.getPatch(i, j).setState(0);
  181. }
  182. }
  183. }
  184. public void randomize() {
  185. for (int i = 0; i < _grid.getHeight(); i++) {
  186. for (int j = 0; j < _grid.getWidth(); j++) {
  187. _grid.getPatch(i, j).setState(random.nextInt(Goldfish.getMaxStates(rule)));
  188. }
  189. }
  190. }
  191. private void mouseDraw(MouseEvent e) {
  192. int states = Goldfish.getMaxStates(rule);
  193. if (e.getX() < 0 || e.getY() < 0 || e.getX() / scale >= width || e.getY() / scale >= height)
  194. return;
  195. Patch p = _grid.getPatch(e.getX()/scale, e.getY()/scale);
  196. if (_lastPatch != p) {
  197. if (p.getState() != 0) {
  198. p.setState(0);
  199. } else {
  200. if (SwingUtilities.isLeftMouseButton(e)) {
  201. p.setState(states - 1);
  202. } else if (SwingUtilities.isRightMouseButton(e)) {
  203. p.setState(1);
  204. }
  205. }
  206. _lastPatch = p;
  207. }
  208. e.consume();
  209. }
  210. @Override
  211. public void mouseDragged(MouseEvent e) {
  212. mouseDraw(e);
  213. }
  214. @Override
  215. public void mouseClicked(MouseEvent e) {
  216. }
  217. @Override
  218. public void mouseEntered(MouseEvent e) {
  219. }
  220. @Override
  221. public void mouseExited(MouseEvent e) {
  222. }
  223. @Override
  224. public void mousePressed(MouseEvent e) {
  225. mouseDraw(e);
  226. }
  227. @Override
  228. public void mouseReleased(MouseEvent e) {
  229. _lastPatch = null;
  230. }
  231. @Override
  232. public void mouseMoved(MouseEvent e) {
  233. }
  234. @Override
  235. public void actionPerformed(ActionEvent event) {
  236. if ("pause".equals(event.getActionCommand())) {
  237. if (paused) {
  238. paused = false;
  239. pauseButton.setText("Pause");
  240. } else {
  241. paused = true;
  242. pauseButton.setText("Unpause");
  243. }
  244. } else if ("reset".equals(event.getActionCommand())) {
  245. clear();
  246. reset = true;
  247. } else if ("random".equals(event.getActionCommand())) {
  248. randomize();
  249. } else if ("clear".equals(event.getActionCommand())) {
  250. clear();
  251. } else {
  252. String oldRule = rule;
  253. rule = event.getActionCommand();
  254. if (oldRule.equals("Brian's Brain") && !rule.equals("Brian's Brain")) {
  255. for (int i = 0; i < _grid.getWidth(); i++) {
  256. for (int j = 0; j < _grid.getHeight(); j++) {
  257. if (_grid.getPatch(i,j).getState() == 2)
  258. _grid.getPatch(i,j).setState(1);
  259. }
  260. }
  261. } else if (!oldRule.equals("Brian's Brain") && rule.equals("Brian's Brain")) {
  262. for (int i = 0; i < _grid.getWidth(); i++) {
  263. for (int j = 0; j < _grid.getHeight(); j++) {
  264. if (_grid.getPatch(i,j).getState() == 1)
  265. _grid.getPatch(i,j).setState(2);
  266. }
  267. }
  268. }
  269. title = "Goldfish: " + rule;
  270. _frame.setTitle(title);
  271. }
  272. }
  273. }