Commits

zetro  committed 1403491

Better use of RAM, added ctrl+drag to copy and implemented some parts of the MCell file format.

  • Participants
  • Parent commits 2541e05

Comments (0)

Files changed (12)

File src/org/bitbucket/zetro/squaredino/backend/BriansBrain.java

 			return OFF;
 		}
 		System.err.println("Warning: Invalid cell " + cell);
-		return null;
+		return OFF;
 	}
 
 	@Override

File src/org/bitbucket/zetro/squaredino/backend/HPP.java

 import java.util.List;
 
 /**
- * Implementation of HPP. <br> Example:
+ * Implementation of HPP. <br/> Example:
  * <code>14P$P12.P$P12.P$P8.A3.P$P12.P$P12.P$P3.M8.P$P12.P$P12.P$14P!</code>
  */
 public class HPP extends CellularAutomaton {

File src/org/bitbucket/zetro/squaredino/backend/experimental/HashAutomaton.java

 				expanded = expand(expanded);
 			}
 
-			System.out.print("Step size: " + (1 << stepSize) + ", population: " + expanded.size());
+			//System.out.print("Step size: " + (1 << stepSize) + ", population: " + expanded.size());
 			n = nextGeneration(expanded, stepSize);		// level == node.level + 1
-			System.out.println(", new population: " + n.size());
+			//System.out.println(", new population: " + n.size());
 		}
 		// Compact node, usally undoes the second expand
 		HashNode c = compact(n);				// level <= node.level + 1
 		return c;
 	}
 
-	@SuppressWarnings("unchecked")
 	private HashNode nextGeneration(HashNode node, int linearLevel) {
 		if (node.next != null) {
 			return node.next;

File src/org/bitbucket/zetro/squaredino/backend/experimental/HashQuadTree.java

 		HashQuadTree<T> hashTree = new HashQuadTree<T>();
 		hashTree.pos = tree.getPosition();
 
-		QuadTree<T>.Node node = tree.getRoot();
+		QuadTree.Node<T> node = tree.getRoot();
 		if (!node.isLeaf()) {
 			HashNode newRoot = buildNode(hashTree, node, tree.getLevel());
 			hashTree.root = newRoot;
 		return hashTree;
 	}
 
-	private static <T> HashNode buildNode(HashQuadTree<T> hashTree, QuadTree<T>.Node node, int level) {
+	private static <T> HashNode buildNode(HashQuadTree<T> hashTree, QuadTree.Node<T> node, int level) {
 		if (node == null) {
 			return hashTree.getSpaceNode(level);
 		} else if (!node.isLeaf()) {
 			return HashNode.create(hashTree.cache, nw, ne, sw, se);
 		} else if (node instanceof QuadTree.ContentNode) {
 			assert level == 0;
-			@SuppressWarnings("unchecked")
-			T content = (T) ((QuadTree.ContentNode) node).content;
+			T content = ((QuadTree.ContentNode<T>) node).content;
 			hashTree.numberOfElements++;
 			return HashContentNode.create(hashTree.cache, content);
 		} else {

File src/org/bitbucket/zetro/squaredino/backend/experimental/QuadBoard.java

 		System.out.print("Building hashtree... ");
 
 		hashTree = HashQuadTree.create(tree);
-		tree.clear();
+		tree = null;
 		buildAutomaton();
 
 		System.out.println("done.");
 	private void rebuildQuadTree() {
 		System.out.print("Rebuilding quadtree... ");
 
-		tree.clear();
+		tree = new QuadTree<Cell>();
 		for (Map.Entry<Point, Cell> en : hashTree) {
 			Point p = en.getKey();
 			Cell cell = en.getValue();
 	public void step() {
 		if (hashTree == null) {
 			buildHashTree();
+		} else if (tree != null) {
+			throw new AssertionError();
 		}
 
 		HashNode cur = hashTree.getRoot();

File src/org/bitbucket/zetro/squaredino/backend/experimental/QuadTree.java

  * @param <T> stored data type
  */
 public class QuadTree<T> implements Iterable<Map.Entry<Point, T>> {
-	class Node {
-		public Node nw, ne, sw, se;
+	static class Node<T> {
+		public Node<T> nw, ne, sw, se;
 
-		Node() {
+		private Node() {
 			this(null, null, null, null);
 		}
 
-		Node(Node nw, Node ne, Node sw, Node se) {
+		private Node(Node<T> nw, Node<T> ne, Node<T> sw, Node<T> se) {
 			this.nw = nw;
 			this.ne = ne;
 			this.sw = sw;
 		}
 	}
 
-	class ContentNode extends Node {
+	static class ContentNode<T> extends Node<T> {
 		public final T content;
 
-		ContentNode(Node parent, T content) {
+		private ContentNode(T content) {
 			super();
 
 			this.content = content;
 			return "ContentNode{" + "content=" + content + '}';
 		}
 	}
-	private Node root;
+	private Node<T> root;
 	private Point pos;
 	private int treeSize;
 	private int levels;
 	 * QuadTree constructor.
 	 */
 	public QuadTree() {
-		root = new Node();
+		root = new Node<T>();
 		pos = new Point(0, 0);
 		treeSize = 2;
 		levels = 1;
 	}
 
 	private void expand(boolean right, boolean down) {
-		Node old = root;
-		root = new Node();
+		Node<T> old = root;
+		root = new Node<T>();
 
 		int x = pos.x, y = pos.y;
 		if (!right) {
 	public void add(Point p, T value) {
 		checkSize(p);
 
-		Node n = root;
+		Node<T> n = root;
 		int macro = treeSize;
 		int x = pos.x, y = pos.y;
 		while (macro >= 1) {
 
 			if (macro == 2) {
 				numberOfElements++;
-				Node content = new ContentNode(n, value);
+				Node<T> content = new ContentNode<T>(value);
 				setNode(n, content, right, down);
 				return;
 			} else {
-				Node child = getNode(n, right, down);
+				Node<T> child = getNode(n, right, down);
 				if (child == null) {
-					child = new Node();
+					child = new Node<T>();
 					setNode(n, child, right, down);
 				}
 
 	 * @param p the point index
 	 */
 	public void remove(Point p) {
-		Stack<Node> parentNodes = new Stack<Node>();
+		Stack<Node<T>> parentNodes = new Stack<Node<T>>();
 		Stack<Boolean> parentRight = new Stack<Boolean>();
 		Stack<Boolean> parentDown = new Stack<Boolean>();
 
-		Node n = root;
+		Node<T> n = root;
 		int macro = treeSize;
 		int x = pos.x, y = pos.y;
 
 				parentNodes.add(n);
 				parentRight.add(right);
 				parentDown.add(down);
-				Node child = getNode(n, right, down);
+				Node<T> child = getNode(n, right, down);
 				if (child == null) {
-					child = new Node();
+					child = new Node<T>();
 					setNode(n, child, right, down);
 				}
 
 	 * <code>p</code>
 	 */
 	public T get(Point p) {
-		Node n = root;
+		Node<T> n = root;
 		int macro = treeSize;
 		int x = pos.x, y = pos.y;
 
 			}
 
 			if (macro == 2) {
-				Node content = getNode(n, right, down);
+				Node<T> content = getNode(n, right, down);
 				if (content != null) {
-					return ((ContentNode) content).content;
+					return ((ContentNode<T>) content).content;
 				}
 				return null;
 			} else {
-				Node child = getNode(n, right, down);
+				Node<T> child = getNode(n, right, down);
 				if (child == null) {
 					return null;
 				}
 		throw new AssertionError();
 	}
 
-	private void setNode(Node node, Node value, boolean right, boolean down) {
+	private void setNode(Node<T> node, Node<T> value, boolean right, boolean down) {
 		if (!right && !down) {
 			node.nw = value;
 		} else if (right && !down) {
 		}
 	}
 
-	private Node getNode(Node node, boolean right, boolean down) {
+	private Node<T> getNode(Node<T> node, boolean right, boolean down) {
 		if (!right && !down) {
 			return node.nw;
 		} else if (right && !down) {
 	 * call.
 	 */
 	public void clear() {
-		root = new Node();
+		root = new Node<T>();
 		pos = new Point(0, 0);
 		treeSize = 2;
 		levels = 1;
 	}
 
-	Node getRoot() {
+	Node<T> getRoot() {
 		return root;
 	}
 

File src/org/bitbucket/zetro/squaredino/backend/experimental/QuadTreeIterator.java

  */
 public class QuadTreeIterator<T> implements Iterator<Entry<Point, T>> {
 	private final Selection selection;
-	private Stack<QuadTree<T>.Node> stack;
+	private Stack<QuadTree.Node<T>> stack;
 	private Stack<Point> positions;
 	private Stack<Integer> sizes;
 	private Entry<Point, T> next;
 	 * @param position node position
 	 * @param levels the maximum depth in the node
 	 */
-	QuadTreeIterator(Selection selection, QuadTree<T>.Node node, Point position, int levels, int ignoreLevel) {
+	QuadTreeIterator(Selection selection, QuadTree.Node<T> node, Point position, int levels, int ignoreLevel) {
 		this.selection = selection;
 		this.ignoreLevel = ignoreLevel;
 
-		stack = new Stack<QuadTree<T>.Node>();
+		stack = new Stack<QuadTree.Node<T>>();
 		positions = new Stack<Point>();
 		sizes = new Stack<Integer>();
 
 		add(node, position, 1 << levels);
 	}
 
-	private void add(QuadTree<T>.Node node, Point pos, int size) {
+	private void add(QuadTree.Node<T> node, Point pos, int size) {
 		if (node != null) {
 			if (selection != null) {
 				if (pos.x + size - 1 < selection.getTopLeft().x) {
 		}
 
 		while (!stack.isEmpty()) {
-			final QuadTree<T>.Node node = stack.pop();
+			final QuadTree.Node<T> node = stack.pop();
 			final Point pos = positions.pop();
 			final int size = sizes.pop();
 
 					}
 
 					@Override
-					@SuppressWarnings("unchecked")
 					public T getValue() {
 						if (node instanceof QuadTree.ContentNode) {
-							return (T) ((QuadTree.ContentNode) node).content;
+							return ((QuadTree.ContentNode<T>) node).content;
 						}
 						return null;
 					}

File src/org/bitbucket/zetro/squaredino/gui/BoardPanel.java

 
 import java.awt.Color;
 import java.awt.Graphics;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseWheelEvent;
 		
 		paddx = paddy = (int) (4*zoom); 
 		
+		addKeyListener(new KeyAdapter() {
+			@Override
+			public void keyPressed(KeyEvent e) {
+				copySelection = e.isControlDown();
+				moveDead = !e.isAltDown();
+				repaint();
+			}
+
+			@Override
+			public void keyReleased(KeyEvent e) {
+				copySelection = e.isControlDown();
+				moveDead = !e.isAltDown();
+				repaint();
+			}
+		});
 		addMouseMotionListener(new MouseAdapter() {
 			public void mouseDragged(MouseEvent e) {
 				Point p = calPos(e.getX() - tempaddx, e.getY() - tempaddy);
 							topLeft.y + (int) (getHeight() / zoom) + 1));
 			
 			if(selection != null && movesSelection) {
-				g.setColor(Color.WHITE); 
-				g.fillRect(paddx + tempaddx + (int) ((p.x + selected.getTopLeft().x) * zoom), 
-						paddy + tempaddy + (int) ((p.y + selected.getTopLeft().y) * zoom), 
-						(int) ((selected.getWidth()+1)*zoom), (int) ((selected.getHeight()+1)*zoom)
-				);
+				if (moveDead) {
+					g.setColor(Color.WHITE); 
+					g.fillRect(paddx + tempaddx + (int) ((p.x + selected.getTopLeft().x) * zoom), 
+							paddy + tempaddy + (int) ((p.y + selected.getTopLeft().y) * zoom), 
+							(int) ((selected.getWidth()+1)*zoom), (int) ((selected.getHeight()+1)*zoom)
+					);
+				}
 				g.setColor(Color.BLACK);
 				Iterator<Map.Entry<Point, Cell>> cells2 = selection.getLivingCells(view, ignoreLevel); 
 				while(cells2.hasNext()) {
 					Map.Entry<Point, Cell> entry = cells2.next();
 					Point p2 = entry.getKey(); 
-					g.setColor(cellColors[entry.getValue().state % cellColors.length]);
+					int state = entry.getValue() != null ? entry.getValue().state : 1;
+					g.setColor(cellColors[state % cellColors.length]);
 					g.fillRect(paddx + tempaddx + (int) ((p.x + p2.x) * zoom), 
 								paddy + tempaddy + (int) ((p.y + p2.y) * zoom), 
 								size, size

File src/org/bitbucket/zetro/squaredino/gui/ControlBar.java

 				ImportDialog importDialog = new ImportDialog(owner, currentDirectory); 
 				currentDirectory = importDialog.getCurrentDirectory();
 				BoardData boardData = importDialog.getBoardData();
+				importDialog.clear();
 				if (boardData != null) {
 					Board board = boardData.getBoard();
 					if (board != null) {
 		b.setContentAreaFilled(false); 
 		b.setFocusPainted(false); 
 		b.setAlignmentX(JComponent.CENTER_ALIGNMENT); 
+		b.setFocusable(false);
 		
 		Box box = Box.createVerticalBox(); 
 		box.add(b); 

File src/org/bitbucket/zetro/squaredino/gui/ImportDialog.java

 	private JLabel width = new JLabel("Width/Height: "); 
 	
 	private BoardPanel bp;
-	private BoardData importData, boardData;
+	private BoardData importData;
 	
 	public ImportDialog(JFrame owner, File currentDirectory) {
 		super(owner, true);
 		loadBoard(new StringReader(s.toString()));
 	}
 	private void loadBoard(Reader reader) throws IOException {
-		this.boardData = SquareIO.load(reader);
+		BoardData boardData = SquareIO.load(reader);
 
 		updateInfo(boardData);
 		if (boardData.getBoard() != null) {
 			width.setText("Width/Height: " + sw + "/" + sh);
 		}
 	}
+
+	/**
+	 * Clears all imported board data.
+	 */
+	public void clear() {
+		importData = null;
+		bp.getBoard().clear(); // Note: bg.getBoard() != importData
+	}
+	
 	public BoardData getBoardData() {
 		return importData;
 	}

File src/org/bitbucket/zetro/squaredino/gui/SquareDinoWindow.java

 import java.awt.BorderLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
 
 import javax.swing.AbstractAction;
 import javax.swing.Action;
 		control = new ControlBar(this, bp, gp); 
 		add(control, BorderLayout.PAGE_START); 
 		
+		addWindowFocusListener(new WindowAdapter() {
+			@Override
+			public void windowGainedFocus(WindowEvent e) {
+				bp.requestFocusInWindow();
+			}
+		});
+		
 		add(new AbstractAction() {
 			@Override
 			public void actionPerformed(ActionEvent e) {

File src/org/bitbucket/zetro/squaredino/io/SquareIO.java

 import java.util.Scanner;
 import java.util.SortedMap;
 import java.util.TreeMap;
-import org.bitbucket.zetro.squaredino.backend.AbstractAutomaton;
 import org.bitbucket.zetro.squaredino.backend.Board;
 import org.bitbucket.zetro.squaredino.backend.BoardFactory;
 import org.bitbucket.zetro.squaredino.backend.Cell;
 			}
 			if (state == 0) {
 				data.append("b");
-			} else if (state == -1) {
+			} else if (state == 1) {
 				data.append("o");
 			} else {
 				int multiplier = (state - 1) / 24;
 		String author = null;
 		ArrayList<String> comments = new ArrayList<String>();
 		int width = Board.INFINITE, height = Board.INFINITE;
+		String rule = null;
 
 		int startX = 0;
 		int startY = 0;
 				char type = line.charAt(1);
 				String nline = line.length() >= 2 ? line.substring(2).trim() : "";
 
-				if (type == 'C' || type == 'c') {	// Comment
+				if (type == 'C' || type == 'c') {	// Comment (RLE)
 					System.out.println("Comment: " + nline);
 					comments.add(nline);
-				} else if (type == 'N') {			// Name
+				} else if (type == 'D') {			// Description (MCell)
+					System.out.println("Description: " + nline);
+					name = nline;
+				} else if (type == 'N') {			// Name (RLE)
 					System.out.println("Name: " + nline);
 					name = nline;
-				} else if (type == 'O') {			// Author
+				} else if (type == 'O') {			// Author (RLE)
 					System.out.println("Author: " + nline);
 					author = nline;
+				} else if (type == 'L') {			// Data line (MCell)
+					System.out.println("Data line: " + nline);
+					if (board == null) {
+						board = BoardFactory.createBoard(width, height);
+						if (rule != null) {
+							board.setRule(rule);
+						}
+					}
+					Point p = parseDataLine(board, nline, startX, xPos, yPos);
+					xPos = p.x;
+					yPos = p.y;
+				} else if (line.startsWith("#RULE")) {	// Rule  (MCell)
+					String r = line.substring(line.indexOf("RULE") + 4).trim();
+					if (rule == null) {
+						rule = r;
+					} else {
+						rule += r;
+					}
+					System.out.println("Rule: " + r);
+				} else if (line.startsWith("#GAME")) {	// Game  (MCell)
+					String r = line.substring(line.indexOf("GAME") + 4).trim();
+					if (rule == null) {
+						rule = r + ":";
+					} else {
+						rule = rule + ":" + r;
+					}
+					System.out.println("Game: " + r);
 				} else {							// Unknown
 					System.err.println("Warning: Unknown #-type '" + type + "' with content \"" + nline + "\"");
 				}
 
 					System.out.println("Header: " + line);
 					String[] s = line.split("\\s*,\\s*");
-					String rule = AbstractAutomaton.STANDARD_RULE;
 					for (String string : s) {
 						if (!string.contains("=")) {
 							System.err.println("Error: Invalid header property \"" + string + "\"");
 					}
 
 					board = BoardFactory.createBoard(width, height);
-					board.setRule(rule);
+					if (rule != null) {
+						board.setRule(rule);
+					}
 
 					xPos = startX;
 					yPos = startY;
 				} else {
-					//System.out.println("Cell Line: " + line);
-					int runCount = 1;
-					char[] cs = line.toCharArray();
-					StringBuilder buf = new StringBuilder();
-					for (int ii = 0; ii < cs.length; ii++) {
-						char c = cs[ii];
-						if (c >= '0' && c <= '9') {
-							buf.append(c);
-							continue;
-						} else if (buf.length() > 0) {
-							runCount = Integer.parseInt(buf.toString());
-							buf.setLength(0);
-						} else if (c >= 'p' && c <= 'z' && ii + 1 < cs.length) {
-							char c2 = cs[ii + 1];
-							if (c2 >= 'A' && c2 <= 'Z') {
-								int state = (c - 'p' + 1) * 24 + (c2 - 'A' + 1);
-
-								Cell cell = Cell.createCell(state);
-								for (int i = 0; i < runCount; i++) {
-									board.addCell(cell, xPos, yPos);
-									xPos++;
-								}
-								runCount = 1;
-								ii++;
-								continue;
-							}
-						}
-						if (c >= 'A' && c <= 'Z') {
-							int state = c - 'A' + 1;
-
-							Cell cell = Cell.createCell(state);
-							for (int i = 0; i < runCount; i++) {
-								board.addCell(cell, xPos, yPos);
-								xPos++;
-							}
-							runCount = 1;
-							continue;
-						} else if (c == 'b' || c == '.') { // dead cell
-							xPos += runCount;
-							runCount = 1;
-						} else if (c == 'o') { // alive cell
-							Cell cell = Cell.createCell(1);
-							for (int i = 0; i < runCount; i++) {
-								board.addCell(cell, xPos, yPos);
-								xPos++;
-							}
-							runCount = 1;
-						} else if (c == '$') { // end of line
-							xPos = startX;
-							yPos += runCount;
-							runCount = 1;
-						} else if (c == '!') { // quit
-							break line;
-						} else {
-							System.err.println("Warning: Unknown type '" + c + "' in \"" + line + "\"");
-						}
+					Point p = parseDataLine(board, line, startX, xPos, yPos);
+					if (p == null) {
+						break line;
 					}
+					xPos = p.x;
+					yPos = p.y;
 				}
 			}
 		}
 
 		return new BoardData(board, name, author, comments, width, height);
 	}
+
+	private static Point parseDataLine(Board board, String line, int startX, int x, int y) {
+		//System.out.println("Cell Line: " + line);
+		int xPos = x, yPos = y;
+		int runCount = 1;
+
+		char[] cs = line.toCharArray();
+		StringBuilder buf = new StringBuilder();
+		for (int ii = 0; ii < cs.length; ii++) {
+			char c = cs[ii];
+			if (c >= '0' && c <= '9') {
+				buf.append(c);
+				continue;
+			} else if (buf.length() > 0) {
+				runCount = Integer.parseInt(buf.toString());
+				buf.setLength(0);
+			} else if (c >= 'p' && c <= 'z' && ii + 1 < cs.length) {
+				char c2 = cs[ii + 1];
+				if (c2 >= 'A' && c2 <= 'Z') {
+					int state = (c - 'p' + 1) * 24 + (c2 - 'A' + 1);
+
+					Cell cell = Cell.createCell(state);
+					for (int i = 0; i < runCount; i++) {
+						board.addCell(cell, xPos, yPos);
+						xPos++;
+					}
+					runCount = 1;
+					ii++;
+					continue;
+				}
+			}
+			if (c >= 'A' && c <= 'Z') {
+				int state = c - 'A' + 1;
+
+				Cell cell = Cell.createCell(state);
+				for (int i = 0; i < runCount; i++) {
+					board.addCell(cell, xPos, yPos);
+					xPos++;
+				}
+				runCount = 1;
+				continue;
+			} else if (c == 'b' || c == '.') { // dead cell
+				xPos += runCount;
+				runCount = 1;
+			} else if (c == 'o') { // alive cell
+				Cell cell = Cell.createCell(1);
+				for (int i = 0; i < runCount; i++) {
+					board.addCell(cell, xPos, yPos);
+					xPos++;
+				}
+				runCount = 1;
+			} else if (c == '$') { // end of line
+				xPos = startX;
+				yPos += runCount;
+				runCount = 1;
+			} else if (c == '!') { // quit
+				return null;
+			} else {
+				System.err.println("Warning: Unknown type '" + c + "' in \"" + line + "\"");
+			}
+		}
+
+		return new Point(xPos, yPos);
+	}
 }