package org.iota.qupla.dispatcher.entity; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Point; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import javax.swing.BoxLayout; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.MouseInputAdapter; import org.iota.qupla.dispatcher.Dispatcher; import org.iota.qupla.dispatcher.Entity; import org.iota.qupla.dispatcher.Environment; import org.iota.qupla.helper.TritConverter; import org.iota.qupla.helper.TritVector; public class GameOfLifeEntity extends Entity { private static final int GRID_SIZE = 81; private static final int HASH_SIZE = 243; public TritVector currentGrid = new TritVector(GRID_SIZE * GRID_SIZE, TritVector.TRIT_ZERO); public TritVector currentId = new TritVector(HASH_SIZE, TritVector.TRIT_ZERO); public JTextField entry; public JFrame frame; public Environment golGen; public Environment golHash; public Environment golIds; public Environment golSend; public Environment golView; public BufferedImage gridImage; public JPanel gridView; public GameOfLifeEntity() { super(0); final Dispatcher dispatcher = Dispatcher.getInstance(); golGen = dispatcher.getEnvironment("GolGen", null); golHash = dispatcher.getEnvironment("GolHash", null); golIds = dispatcher.getEnvironment("GolIds", null); golSend = dispatcher.getEnvironment("GolSend", null); golView = dispatcher.getEnvironment("GolView", null); join(golView); gridImage = new BufferedImage(GRID_SIZE, GRID_SIZE, BufferedImage.TYPE_3BYTE_BGR); gridView = new JPanel(); gridView.setPreferredSize(new Dimension(200, 200)); gridView.setVisible(true); final MouseInputAdapter mouseAdapter = getMouseInputAdapter(); gridView.addMouseListener(mouseAdapter); gridView.addMouseMotionListener(mouseAdapter); final JLabel label = new JLabel(); label.setText("GoL ID:"); entry = new JTextField(); addChangeListener(); final JPanel idPanel = new JPanel(); idPanel.setLayout(new BoxLayout(idPanel, BoxLayout.X_AXIS)); idPanel.add(label); idPanel.add(entry); frame = new JFrame("Game of Life"); frame.addWindowListener(ViewEntity.windowAdapter); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(idPanel, BorderLayout.PAGE_START); frame.add(gridView, BorderLayout.CENTER); frame.addComponentListener(new ComponentAdapter() { public void componentResized(ComponentEvent evt) { drawGridImage(); } }); frame.setVisible(true); frame.setSize(400, 400); } private void addChangeListener() { entry.getDocument().addDocumentListener(new DocumentListener() { public void changedUpdate(DocumentEvent e) { onEntryChange(); } public void insertUpdate(DocumentEvent e) { onEntryChange(); } public void removeUpdate(DocumentEvent e) { onEntryChange(); } }); } private void drawGridImage() { final Graphics graphics = gridImage.getGraphics(); graphics.setColor(Color.WHITE); graphics.fillRect(0, 0, GRID_SIZE, GRID_SIZE); graphics.setColor(Color.DARK_GRAY); final byte[] trits = currentGrid.trits(); int offset = 0; for (int y = 0; y < GRID_SIZE; y++) { for (int x = 0; x < GRID_SIZE; x++) { if (trits[offset + x] == '1') { graphics.drawRect(x, y, 0, 0); } } offset += GRID_SIZE; } final Dimension size = gridView.getSize(); gridView.getGraphics().drawImage(gridImage, 0, 0, size.width, size.height, null); } private MouseInputAdapter getMouseInputAdapter() { return new MouseInputAdapter() { private char cell; private int getOffset(final MouseEvent mouseEvent) { final Point point = mouseEvent.getPoint(); final Dimension size = gridView.getSize(); final int x = GRID_SIZE * point.x / size.width; final int y = GRID_SIZE * point.y / size.height; return y * GRID_SIZE + x; } @Override public void mouseDragged(final MouseEvent mouseEvent) { if (cell == 0) { return; } final int offset = getOffset(mouseEvent); final byte[] trits = currentGrid.trits(); trits[offset] = (byte) cell; currentGrid = new TritVector(trits); golView.affect(TritVector.concat(currentId, currentGrid), 0); } @Override public void mousePressed(final MouseEvent mouseEvent) { if (mouseEvent.getButton() != 1) { golGen.affect(TritVector.concat(currentId, currentGrid), 0); return; } final int offset = getOffset(mouseEvent); cell = currentGrid.trit(offset) == '1' ? '0' : '1'; mouseDragged(mouseEvent); } @Override public void mouseReleased(final MouseEvent mouseEvent) { if (mouseEvent.getButton() != 1) { return; } cell = 0; golSend.affect(TritVector.concat(currentId, currentGrid), 0); } }; } @Override public TritVector onEffect(final TritVector effect) { //TODO fix this final TritVector inputId = effect.slice(0, HASH_SIZE); if (inputId.equals(currentId)) { currentGrid = effect.slice(HASH_SIZE, GRID_SIZE * GRID_SIZE); drawGridImage(); } // return null, no need to propagate anything return null; } private void onEntryChange() { final String id = entry.getText(); String trytes = ""; for (int i = 0; i < id.length(); i++) { final char c = id.charAt(i); trytes += "9ABCDEFGHIJKLMNOPQRSTUVWXYZ".charAt(c & 0x0f); trytes += "9ABCDEFGHIJKLMNOPQRSTUVWXYZ".charAt((c >> 4) & 0x0f); } // remove previous id if (!currentId.isZero()) { golIds.affect(TritVector.concat(new TritVector(1, TritVector.TRIT_MIN), currentId), 0); } // make new id currentId = TritConverter.trytesToVector(trytes).slicePadded(0, 243); // save new id if (!currentId.isZero()) { golIds.affect(TritVector.concat(new TritVector(1, TritVector.TRIT_ONE), currentId), 0); } } }