package puzzledice; import gui.AreaEditPanel; import gui.WindowMain; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.HashSet; import java.util.Queue; import java.util.LinkedList; import com.mxgraph.model.mxCell; import com.mxgraph.view.mxGraph; public class AreaBlock { private List<AreaBlock> _doors; private String _name; private Object _graphCell; private Object _puzzleGraphCell = null; // For keeping track of our edges in the puzzle graph. private List<AreaBlock> _puzzleEdges; private boolean _isStartArea = false; public void setStartArea(boolean value) { if (!_isStartArea && value) { _isStartArea = value; createPuzzleCell(); } _isStartArea = value; } public boolean isStartArea() { return _isStartArea; } // Used to properly display the puzzle textual descriptions // If this door has a non-empty list, then this area must be a destination area behind a locked door. private List<DoorUnlockBlock> _lockedDoors; // Used for correctly building the puzzle graphs. // If we're the source of a locked door private List<DoorUnlockBlock> _sourceLockedDoors; public AreaBlock(String name) { _name = name; _doors = new ArrayList<AreaBlock>(); _lockedDoors = new ArrayList<DoorUnlockBlock>(); _sourceLockedDoors = new ArrayList<DoorUnlockBlock>(); _puzzleEdges = new ArrayList<AreaBlock>(); } public void addDoor(AreaBlock doorToAdd) { _doors.add(doorToAdd); } public boolean hasDoor(AreaBlock door) { return _doors.contains(door); } public void removeDoor(AreaBlock doorToRemove) { _doors.remove(doorToRemove); } public void addPuzzleEdge(AreaBlock edgeToAdd) { mxGraph puzzleGraph = WindowMain.getPuzzleGraph(); createPuzzleCell(); puzzleGraph.getModel().beginUpdate(); try { // Have our given destination add a puzzle graph cell if it doesn't have one already edgeToAdd.createPuzzleCell(); puzzleGraph.insertEdge(puzzleGraph.getDefaultParent(), null, null, _puzzleGraphCell, edgeToAdd.getPuzzleGraphCell()); _puzzleEdges.add(edgeToAdd); } finally { puzzleGraph.getModel().endUpdate(); } } public void removePuzzleEdges() { mxGraph puzzleGraph = WindowMain.getPuzzleGraph(); if (_puzzleGraphCell != null) { puzzleGraph.getModel().beginUpdate(); try { for (AreaBlock edge : _puzzleEdges) { puzzleGraph.removeCells(puzzleGraph.getEdgesBetween(_puzzleGraphCell, edge.getPuzzleGraphCell(), false)); } } finally { puzzleGraph.getModel().endUpdate(); } } _puzzleEdges.clear(); } public AreaBlock[] getPuzzleEdges() { return _puzzleEdges.toArray(new AreaBlock[_puzzleEdges.size()]); } // For finding cycles in the area puzzle graph public boolean nodeReachable(AreaBlock target) { // Do a simple bfs Set<AreaBlock> closedBlocks = new HashSet<AreaBlock>(); Queue<AreaBlock> agenda = new LinkedList<AreaBlock>(); agenda.add(this); while (agenda.size() > 0) { AreaBlock block = agenda.remove(); if (block == target) return true; closedBlocks.add(block); for (AreaBlock neighbor : block.getPuzzleEdges()) { if (!closedBlocks.contains(neighbor)) agenda.add(neighbor); } } return false; } public boolean canReachBlockBackwards(Object target) { Set<Object> closedBlocks = new HashSet<Object>(); Queue<Object> agenda = new LinkedList<Object>(); agenda.add(this); while (agenda.size() > 0) { Object block = agenda.remove(); System.out.println(block); if (block.equals(target)) return true; closedBlocks.add(block); if (block instanceof PuzzleBlock) { PuzzleBlock pBlock = (PuzzleBlock)block; for (PuzzleBlock neighbor : pBlock.getPuzzleInputs()) { if (!closedBlocks.contains(neighbor)) agenda.add(neighbor); } for (AreaBlock neighbor : pBlock.getAreaInputs()) { if (!closedBlocks.contains(neighbor)) agenda.add(neighbor); } } else if (block instanceof AreaBlock) { AreaBlock aBlock = (AreaBlock)block; for (DoorUnlockBlock neighbor : aBlock.getLockedDoorList()) { if (!closedBlocks.contains(neighbor)) agenda.add(neighbor); } for (AreaBlock neighbor : aBlock.getInputAreas()) { if (!closedBlocks.contains(neighbor)) agenda.add(neighbor); } } } return false; } public AreaBlock[] getDoorList() { return _doors.toArray(new AreaBlock[_doors.size()]); } public void setName(String newName) { _name = newName; } public String getName() { return _name; } public void createPuzzleCell() { mxGraph puzzleGraph = WindowMain.getPuzzleGraph(); puzzleGraph.getModel().beginUpdate(); try { // First, create a graph cell if we don't have one already if (_puzzleGraphCell == null) { setPuzzleGraphCell(puzzleGraph.insertVertex(puzzleGraph.getDefaultParent(), null, this, 0, 0, 0, 0, null)); mxCell edge = (mxCell)puzzleGraph.insertEdge(puzzleGraph.getDefaultParent(), null, null, WindowMain.getHierarchyRoot(), _puzzleGraphCell); edge.setVisible(_isStartArea); puzzleGraph.updateCellSize(_puzzleGraphCell); } else { puzzleGraph.updateCellSize(_puzzleGraphCell); for (Object cell : puzzleGraph.getEdgesBetween(WindowMain.getHierarchyRoot(), _puzzleGraphCell, false)) { ((mxCell)cell).setVisible(_isStartArea); } } } finally { puzzleGraph.getModel().endUpdate(); } } public void setGraphCell(Object graphCell) { _graphCell = graphCell; } public void setPuzzleGraphCell(Object graphCell) { _puzzleGraphCell = graphCell; } public Object getGraphCell() { return _graphCell; } public Object getPuzzleGraphCell() { return _puzzleGraphCell; } // function that deletes our puzzle cell if it no longer has any edges public void maybeDeletePuzzleCell() { if (_puzzleGraphCell == null) return; mxCell cell = (mxCell)_puzzleGraphCell; if(cell.getEdgeCount() <= 1 && !_isStartArea) { mxGraph puzzleGraph = WindowMain.getPuzzleGraph(); puzzleGraph.removeCells(new Object[]{_puzzleGraphCell}); _puzzleGraphCell = null; } } @Override public String toString() { if (!_isStartArea) return _name; else return _name + "\n(Start Area)"; } public void addDoorLock(DoorUnlockBlock lock) { _lockedDoors.add(lock); } public void removeDoorLock(DoorUnlockBlock lockToRemove) { _lockedDoors.remove(lockToRemove); } public DoorUnlockBlock[] getLockedDoorList() { return _lockedDoors.toArray(new DoorUnlockBlock[_lockedDoors.size()]); } public void addSourceLock(DoorUnlockBlock lock) { _sourceLockedDoors.add(lock); } public void removeSourceLock(DoorUnlockBlock lock) { _sourceLockedDoors.remove(lock); } public DoorUnlockBlock[] getSourceLockList() { return _sourceLockedDoors.toArray(new DoorUnlockBlock[_sourceLockedDoors.size()]); } public AreaBlock[] getInputAreas() { // Find all areas that have an edge pointing to this area List<AreaBlock> inputAreas = new ArrayList<AreaBlock>(); for (AreaBlock area : AreaEditPanel.getAreaList()) { for (AreaBlock maybeMe : area.getPuzzleEdges()) { if (maybeMe == this) { inputAreas.add(area); break; } } } return inputAreas.toArray(new AreaBlock[inputAreas.size()]); } public String getTextualDescription() { String retVal = ""; for (DoorUnlockBlock d : _lockedDoors) retVal += d.getTextualDescription(); for (AreaBlock a : getInputAreas()) retVal += a.getTextualDescription(); return retVal; } public String toXML() { String xml = "<area name=\"" + _name + "\" startArea=\"" + _isStartArea + "\""; if (_lockedDoors.size() == 0 && _doors.size() == 0) xml += "/>\n"; else { xml += ">\n"; for (AreaBlock area : _doors) { xml += "<door name=\"" + area.getName() + "\"/>\n"; } for (DoorUnlockBlock lock : _lockedDoors) { xml += "<lockedDoor name=\"" + lock.getName() + "\"/>\n"; } for (AreaBlock inputArea : getInputAreas()) { xml += "<inputArea name=\"" + inputArea.getName() + "\"/>\n"; } xml += "</area>"; } return xml; } }