A simple Game of Life implementation in Java
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

343 lignes
11 KiB

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