Ver código fonte

Pseudocode fürs berechnen der layouts ist fertig

Kolja Strohm 6 anos atrás
pai
commit
c73a76530f

+ 0 - 28
src/animation/AlgorithmStage.java

@@ -1,28 +0,0 @@
-package animation;
-
-import javax.swing.JTree;
-
-import bk.BlockCalc;
-
-/**
- * Represents a specific stage of the algorithm.
- * Example calculating the blocks, see {@link BlockCalc}.
- * Each of those stages also has an associated {@link PseudoCodeNode}, i.e., a line of pseudocode.
- * 
- * @author kolja
- *
- */
-public interface AlgorithmStage {
-    /**
-     * Indicates whether the whole stage is finished.
-     * @author kolja
-     *
-     */
-
-    /**
-     * Creates a {@link PseudoCodeNode}, i.e., a line of pseudocode that resembles this Stage.
-     * @param tree The {@link JTree} where the node should be inserted.
-     * @return The node.
-     */
-    public PseudoCodeNode createPseudocodeTree( JTree tree );
-}

+ 1 - 2
src/animation/AnimatedAlgorithm.java

@@ -10,7 +10,7 @@ import javax.swing.SwingUtilities;
 import animation.PseudoCodeProcessor.CodeStatus;
 import graph.LayeredGraphNode;
 
-public abstract class AnimatedAlgorithm extends Thread implements AlgorithmStage {
+public abstract class AnimatedAlgorithm extends Thread {
 
     protected AnimationController ac;
     protected LayeredGraphNode graph;
@@ -85,7 +85,6 @@ public abstract class AnimatedAlgorithm extends Thread implements AlgorithmStage
         }
     }
 
-    @Override
     public abstract PseudoCodeNode createPseudocodeTree( JTree tree );
     
     public PseudoCodeProcessor getProcessor() {

+ 4 - 2
src/animation/PseudoCodeNode.java

@@ -6,6 +6,8 @@ import javax.swing.tree.DefaultMutableTreeNode;
 import javax.swing.tree.MutableTreeNode;
 import javax.swing.tree.TreePath;
 
+import lib.TextLayoutHelper;
+
 /**
  * represents a line of pseudocode
  * @author kolja
@@ -30,9 +32,9 @@ public class PseudoCodeNode extends DefaultMutableTreeNode {
     private boolean selected;
     private boolean breakPoint;
     
-    public PseudoCodeNode( String description, JTree tree, CodeLine line )
+    public PseudoCodeNode( String description, String[] vars, JTree tree, CodeLine line )
     {
-        super( description );
+        super( TextLayoutHelper.setupPseudoCode( description, vars ) );
         synchronized( PseudoCodeNode.class )
         {
         	nodeId = nextNodeId++;

+ 94 - 37
src/bk/BKNodePlacement.java

@@ -48,18 +48,14 @@ public class BKNodePlacement extends AnimatedAlgorithm {
     {
         return state;
     }
-    
-    public void setAlgorithmState( State s )
-    {
-        state = s;
-    }
 
+    @SuppressWarnings("serial")
     @Override
     public PseudoCodeNode createPseudocodeTree( JTree tree )
     {
     	String[] vars = { "layout", "graph" };
-    	PseudoCodeNode mainFunction = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode("function bkNodePlacement( graph )", vars ), tree, new FunctionDefinition( new String[]{"graph"} ) );
-    	root = new PseudoCodeNode( TextLayoutHelper.setupPseudoCodeStage("-- BK Node Placement Algorithm --" ), tree, new CodeLine() {
+    	PseudoCodeNode mainFunction = new PseudoCodeNode( "function bkNodePlacement( graph )", vars, tree, new FunctionDefinition( new String[]{"graph"} ) );
+    	root = new PseudoCodeNode( "-- BK Node Placement Algorithm --", vars, tree, new CodeLine() {
 
 			@Override
 			public ControlFlow runForward(Memory m) {
@@ -82,53 +78,114 @@ public class BKNodePlacement extends AnimatedAlgorithm {
         } );
         root.setSelected( true );
     	
-        PseudoCodeNode conflictDetectionFunction = new ConflictDetection( this ).createPseudocodeTree( tree );
-        PseudoCodeNode calcLayout = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "function calcLayout( layout, graph )", vars ), tree, new FunctionDefinition( vars ) );
-        PseudoCodeNode combine = new Combine().createPseudocodeTree( tree );
+        PseudoCodeNode conflictDetectionFunction = ConflictDetection.mark_conflicts( tree );
+        PseudoCodeNode calcLayout = new PseudoCodeNode( "function calcLayout( layout, graph )", vars, tree, new FunctionDefinition( vars ) );
+        PseudoCodeNode combine = Combine.combine( tree );
         root.add( mainFunction );
-        mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "call detectConflicts( graph )", vars ), tree, new FunctionCall( conflictDetectionFunction, new String[]{ "graph" } ) ) );
-        mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "layout = DOWN_RIGHT", vars ), tree, new DeclareVariable<String>( "layout" ) {
+        mainFunction.add( new PseudoCodeNode( "call detectConflicts( graph )", vars, tree, new FunctionCall( conflictDetectionFunction, new String[]{ "graph" } ) ) );
+        mainFunction.add( new PseudoCodeNode( "layout = 'DOWN_RIGHT'", vars, tree, new DeclareVariable<String>( "layout" ) {
             @Override
             protected String value(ReadOnlyMemory m) {
                 return "DOWN_RIGHT";
             }
-        }) );
-        mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "call calcLayout( layout, graph )", vars ), tree, new FunctionCall( calcLayout, new String[]{ "layout", "graph" } ) ) );
-        mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "layout = DOWN_LEFT", vars ), tree, new SetVariable<String>( "layout" ) {
+        }) {
+            @Override
+            public String getDebugOutput( Memory m ) {
+                state = State.LAYOUT1;
+                return super.getDebugOutput( m );
+            }
+        } );
+        mainFunction.add( new PseudoCodeNode( "call calcLayout( layout, graph )", vars, tree, new FunctionCall( calcLayout, new String[]{ "layout", "graph" } ) ) );
+        mainFunction.add( new PseudoCodeNode( "layout = 'DOWN_LEFT'", vars, tree, new SetVariable<String>( "layout" ) {
             @Override
             protected String value(ReadOnlyMemory m) {
                 return "DOWN_LEFT";
             }
-        }) );
-        mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "call calcLayout( layout, graph )", vars ), tree, new FunctionCall( calcLayout, new String[]{ "layout", "graph" } ) ) );
-        mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "layout = UP_RIGHT", vars ), tree, new SetVariable<String>( "layout" ) {
+        }) {
+            @Override
+            public String getDebugOutput( Memory m ) {
+                state = State.LAYOUT2;
+                return super.getDebugOutput( m );
+            }
+        });
+        mainFunction.add( new PseudoCodeNode( "call calcLayout( layout, graph )", vars, tree, new FunctionCall( calcLayout, new String[]{ "layout", "graph" } ) ) );
+        mainFunction.add( new PseudoCodeNode( "layout = 'UP_RIGHT'", vars, tree, new SetVariable<String>( "layout" ) {
             @Override
             protected String value(ReadOnlyMemory m) {
                 return "UP_RIGHT";
             }
-        }) );
-        mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "call calcLayout( layout, graph )", vars ), tree, new FunctionCall( calcLayout, new String[]{ "layout", "graph" } ) ) );
-        mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "layout = UP_LEFT", vars ), tree, new SetVariable<String>( "layout" ) {
+        }) {
+            @Override
+            public String getDebugOutput( Memory m ) {
+                state = State.LAYOUT3;
+                return super.getDebugOutput( m );
+            }
+        } );
+        mainFunction.add( new PseudoCodeNode( "call calcLayout( layout, graph )", vars, tree, new FunctionCall( calcLayout, new String[]{ "layout", "graph" } ) ) );
+        mainFunction.add( new PseudoCodeNode( "layout = 'UP_LEFT'", vars, tree, new SetVariable<String>( "layout" ) {
             @Override
             protected String value(ReadOnlyMemory m) {
                 return "UP_LEFT";
             }
-        }) );
-        mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "call calcLayout( layout, graph )", vars ), tree, new FunctionCall( calcLayout, new String[]{ "layout", "graph" } ) ) );
-        mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "call combine( graph )", vars ), tree, new FunctionCall( combine, new String[]{ "graph" } ) ) );
-        root.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCodeStage( "-- mark type 1 conflicts --" ), tree, new Comment() ) );
-        root.add( conflictDetectionFunction );
-        PseudoCodeNode blockCalc = new BlockCalc( this ).createPseudocodeTree( tree );
-        PseudoCodeNode horizontalCompaction = new Compaction().createPseudocodeTree( tree );
-        calcLayout.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "call calculateBlockGraph( layout, graph )", vars ), tree, new FunctionCall( blockCalc, vars ) ) );
-        calcLayout.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "call horizontalCompaction( layout, graph )", vars ), tree, new FunctionCall( horizontalCompaction, vars ) ) );
-        root.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCodeStage( "-- Compute an extremal layout --" ), tree, new Comment() ) );
-        root.add( calcLayout );
-        root.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCodeStage( "-- vertical alignment --" ), tree, new Comment() ) );
-        root.add( blockCalc );
-        root.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCodeStage( "-- horizontal compaction --" ), tree, new Comment() ) );
-        root.add( horizontalCompaction );
-        root.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCodeStage( "-- balancing --" ), tree, new Comment() ) );
+        }) {
+            @Override
+            public String getDebugOutput( Memory m ) {
+                state = State.LAYOUT4;
+                return super.getDebugOutput( m );
+            }
+        } );
+        mainFunction.add( new PseudoCodeNode( "call calcLayout( layout, graph )", vars, tree, new FunctionCall( calcLayout, new String[]{ "layout", "graph" } ) ) );
+        mainFunction.add( new PseudoCodeNode( "call combine( graph )", vars, tree, new FunctionCall( combine, new String[]{ "graph" } ) ) {
+            @Override
+            public String getDebugOutput( Memory m ) {
+                state = State.COMBINE;
+                return super.getDebugOutput( m );
+            }
+        } );
+        PseudoCodeNode conflictsStage = new PseudoCodeNode( "-- mark type 1 conflicts --", vars, tree, new Comment() ) {
+            @Override
+            public String getDebugOutput( Memory m ) {
+                state = State.CONFLICTS;
+                return ConflictDetection.buildDebugString( m );
+            }
+        };
+        root.add( conflictsStage );
+        conflictsStage.add( conflictDetectionFunction );
+        PseudoCodeNode blockCalc = BlockCalc.calculateBlockGraph( tree, calcLayout );
+        PseudoCodeNode placeBlock = PlaceBlock.place_block( tree );
+        PseudoCodeNode horizontalCompaction = Compaction.horizontalCompaction( tree, placeBlock );
+        calcLayout.add( new PseudoCodeNode( "call calculateBlockGraph( layout, graph )", vars, tree, new FunctionCall( blockCalc, vars ) ) );
+        calcLayout.add( new PseudoCodeNode( "call horizontalCompaction( layout, graph )", vars, tree, new FunctionCall( horizontalCompaction, vars ) ) );
+        PseudoCodeNode extremalLayoutStage = new PseudoCodeNode( "-- Compute an extremal layout --", vars, tree, new Comment() ) {
+            @Override
+            public String getDebugOutput( Memory m ) {
+                if( !m.isDefined( "graph", MemoryType.LOCAL ) || !m.isDefined( "layout", MemoryType.LOCAL ) )
+                    return "";
+                String info = "| Node | Shift | Sink | Root | Align |  x  |  xDef  |\n";
+                info +=       "|------|-------|------|------|-------|-----|--------|\n";
+                LayeredGraphNode graph = m.read( "graph", MemoryType.LOCAL );
+                LayoutType type = LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) );
+                for( LayeredGraphNode n : graph.getContainedNodes() )
+                {
+                    info += "|" + TextLayoutHelper.strToLen( n.getName(), 6 ) + 
+                            "|" + TextLayoutHelper.strToLen( n.getShift( type ) + "", 7 ) + 
+                            "|" + TextLayoutHelper.strToLen( n.getSink( type ).getName(), 6 ) + 
+                            "|" + TextLayoutHelper.strToLen( n.getRoot( type ).getName(), 6 ) + 
+                            "|" + TextLayoutHelper.strToLen( n.getAlign( type ).getName(), 7 ) + 
+                            "|" + TextLayoutHelper.strToLen( n.getX( type ) + "", 5 ) + 
+                            "|" + TextLayoutHelper.strToLen( !n.isXUndefined( type ) + "", 8 ) + "|\n";
+                }
+                return info;
+            }
+        };
+        root.add( extremalLayoutStage );
+        extremalLayoutStage.add( calcLayout );
+        extremalLayoutStage.add( new PseudoCodeNode( "-- vertical alignment --", vars, tree, new Comment() ) );
+        extremalLayoutStage.add( blockCalc );
+        extremalLayoutStage.add( new PseudoCodeNode( "-- horizontal compaction --", vars, tree, new Comment() ) );
+        extremalLayoutStage.add( horizontalCompaction );
+        extremalLayoutStage.add( placeBlock );
+        root.add( new PseudoCodeNode( "-- balancing --", vars, tree, new Comment() ) );
         root.add( combine );
         processor = new PseudoCodeProcessor( root );
         return root;

+ 44 - 69
src/bk/BlockCalc.java

@@ -5,87 +5,48 @@ import java.util.List;
 
 import javax.swing.JTree;
 
-import animation.AlgorithmStage;
 import animation.CodeLine;
 import animation.ControlFlow;
 import animation.Memory;
 import animation.PseudoCodeNode;
 import animation.Memory.MemoryType;
 import animation.Memory.ReadOnlyMemory;
-import bk.BKNodePlacement.State;
 import codelines.AbstractForLoop;
 import codelines.DeclareVariable;
 import codelines.ForEachLoop;
+import codelines.FunctionCall;
 import codelines.FunctionDefinition;
 import codelines.IfLoop;
 import codelines.SetVariable;
 import graph.LayeredGraphEdge;
 import graph.LayeredGraphNode;
-import lib.TextLayoutHelper;
 
 /**
  * The stage of the BK node placement algorithm where the blocks are computed.
  * @author kolja
  *
  */
-public class BlockCalc implements AlgorithmStage {
-
-    BKNodePlacement alg;
-    
-    public BlockCalc( BKNodePlacement a )
-    {
-        alg = a;
-    }
+public class BlockCalc {
     
-    @Override
-    public PseudoCodeNode createPseudocodeTree( JTree tree ) {
-        String[] vars = { "graph", "L", "r", "neighbors", "layout", "m", "i", "k", "mids" };
+    public static PseudoCodeNode calculateBlockGraph( JTree tree, PseudoCodeNode claclLayout ) {
+        String[] vars = { "graph", "L", "r", "neighbors", "layout", "m", "i", "k", "mids", "n" };
         @SuppressWarnings("serial")
-        PseudoCodeNode root = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "function calculateBlockGraph( layout, graph )", vars ), tree, new FunctionDefinition( new String[]{ "layout", "graph" } ) ) {
+        PseudoCodeNode root = new PseudoCodeNode( "function calculateBlockGraph( layout, graph )", vars, tree, new FunctionDefinition( new String[]{ "layout", "graph" } ) ) {
             @Override
             public String getDebugOutput( Memory m )
             {
-                switch( m.<String>read( "layout", MemoryType.LOCAL ) )
-                {
-                case "DOWN_RIGHT":
-                    alg.setAlgorithmState( State.LAYOUT1 );
-                    break;
-                case "DOWN_LEFT":
-                    alg.setAlgorithmState( State.LAYOUT2 );
-                    break;
-                case "UP_RIGHT":
-                    alg.setAlgorithmState( State.LAYOUT3 );
-                    break;
-                case "UP_LEFT":
-                    alg.setAlgorithmState( State.LAYOUT4 );
-                    break;
-                }
-                if( m.isSomewhereDefined( "i", MemoryType.LOCAL ) && m.isSomewhereDefined( "k", MemoryType.LOCAL ) )
-                    m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL).getContainedLayers().get(m.read( "i", MemoryType.LOCAL )).get(m.<Integer>read( "k", MemoryType.LOCAL ) ).setSelected( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) );
-                String info = "| Node | Shift | Sink | Root | Align |  x  |  xDef  |\n";
-                info +=       "|------|-------|------|------|-------|-----|--------|\n";
-                LayeredGraphNode graph = m.read( "graph", MemoryType.LOCAL );
-                LayoutType layout = LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) );
-                for( LayeredGraphNode n : graph.getContainedNodes() )
-                {
-                    info += "|" + TextLayoutHelper.strToLen( n.getName(), 6 ) + 
-                            "|" + TextLayoutHelper.strToLen( n.getShift( layout ) + "", 7 ) + 
-                            "|" + TextLayoutHelper.strToLen( n.getSink( layout ).getName(), 6 ) + 
-                            "|" + TextLayoutHelper.strToLen( n.getRoot( layout ).getName(), 6 ) + 
-                            "|" + TextLayoutHelper.strToLen( n.getAlign( layout ).getName(), 7 ) + 
-                            "|" + TextLayoutHelper.strToLen( n.getX( layout ) + "", 5 ) + 
-                            "|" + TextLayoutHelper.strToLen( !n.isXUndefined( layout ) + "", 8 ) + "|\n";
-                }
-                return info;
+                if( m.isSomewhereDefined( "n", MemoryType.LOCAL ) )
+                    m.<LayeredGraphNode>read( "n", MemoryType.LOCAL).setSelected( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) );
+                return super.getDebugOutput( m );
             }
         };
-        root.add( new PseudoCodeNode(TextLayoutHelper.setupPseudoCode( "L = graph.getContainedLayers();", vars), tree, new DeclareVariable<ArrayList<ArrayList<LayeredGraphNode>>>( "L" ) {
+        root.add( new PseudoCodeNode( "L = graph.getContainedLayers();", vars, tree, new DeclareVariable<ArrayList<ArrayList<LayeredGraphNode>>>( "L" ) {
             @Override
             protected ArrayList<ArrayList<LayeredGraphNode>> value(ReadOnlyMemory m) {
                 return m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).getContainedLayers();
             }
         } ) );
-        PseudoCodeNode layerLoop = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "for i=layout.contains('DOWN') ? 0 : |L|-1 to layout.contains('DOWN') ? |L|-1 : 0 do", vars ), tree, new AbstractForLoop<Integer>( "i" ) {
+        PseudoCodeNode layerLoop = new PseudoCodeNode( "for i=layout.contains('DOWN') ? 0 : |L|-1 to layout.contains('DOWN') ? |L|-1 : 0 do", vars, tree, new AbstractForLoop<Integer>( "i" ) {
             @Override
             protected Integer begin(ReadOnlyMemory m) {
                 if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "DOWN" ) )
@@ -106,7 +67,7 @@ public class BlockCalc implements AlgorithmStage {
             }
         });
         root.add( layerLoop );
-        layerLoop.add( new PseudoCodeNode(TextLayoutHelper.setupPseudoCode( "r = layout.contains('RIGHT') ? -1 : INFINITY;", vars), tree, new DeclareVariable<Double>( "r" ) {
+        layerLoop.add( new PseudoCodeNode( "r = layout.contains('RIGHT') ? -1 : INFINITY;", vars, tree, new DeclareVariable<Double>( "r" ) {
             @Override
             protected Double value(ReadOnlyMemory m) {
                 if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "RIGHT" ) )
@@ -114,7 +75,7 @@ public class BlockCalc implements AlgorithmStage {
                 return Double.POSITIVE_INFINITY;
             }
         } ) );
-        PseudoCodeNode nodeLoop = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "for k=layout.contains('RIGHT') ? 0 : |L[i]|-1 to layout.contains('RIGHT') ? |L[i]|-1 : 0 do", vars ), tree, new AbstractForLoop<Integer>( "k" ) {
+        PseudoCodeNode nodeLoop = new PseudoCodeNode( "for k=layout.contains('RIGHT') ? 0 : |L[i]|-1 to layout.contains('RIGHT') ? |L[i]|-1 : 0 do", vars, tree, new AbstractForLoop<Integer>( "k" ) {
             @Override
             protected Integer begin( ReadOnlyMemory m) {
                 if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "RIGHT" ) )
@@ -134,12 +95,26 @@ public class BlockCalc implements AlgorithmStage {
                 return m.<Integer>read( "k", MemoryType.LOCAL ) >= 0;
             }
         });
-        nodeLoop.add( new PseudoCodeNode(TextLayoutHelper.setupPseudoCode( "neighbors = layout.contains('DOWN') ? L[i][k].predecessors : L[i][k].successors", vars), tree, new DeclareVariable<ArrayList<LayeredGraphNode>>( "neighbors" ) {
+        nodeLoop.add( new PseudoCodeNode( "n = L[i][k];", vars, tree, new DeclareVariable<LayeredGraphNode>( "n" ) {
+            @Override
+            protected LayeredGraphNode value(ReadOnlyMemory m) {
+                return m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) ).get( m.read( "k", MemoryType.LOCAL ) );
+            }
+        }));
+        PseudoCodeNode ifNode = new PseudoCodeNode( "if n has subgraph then", vars, tree, new IfLoop() {
+            @Override
+            protected boolean condition(ReadOnlyMemory m) {
+                return m.<LayeredGraphNode>read( "n", MemoryType.LOCAL ).getContainedNodes().size() > 0;
+            }
+        } );
+        nodeLoop.add( ifNode );
+        ifNode.add( new PseudoCodeNode( "call calcLayout( layout, n );", vars, tree, new FunctionCall( root, new String[]{ "layout", "n" } ) ) );
+        nodeLoop.add( new PseudoCodeNode( "neighbors = layout.contains('DOWN') ? predecessors(n) : successors(n)", vars, tree, new DeclareVariable<ArrayList<LayeredGraphNode>>( "neighbors" ) {
             @Override
             protected ArrayList<LayeredGraphNode> value(ReadOnlyMemory m) {
-                ArrayList<LayeredGraphEdge> list = m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) ).get( m.read( "k", MemoryType.LOCAL ) ).getSortedOutgoingEdges();
+                ArrayList<LayeredGraphEdge> list = m.<LayeredGraphNode>read( "n", MemoryType.LOCAL ).getSortedOutgoingEdges();
                 if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "DOWN" ) )
-                    list = m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) ).get( m.read( "k", MemoryType.LOCAL ) ).getSortedIncomingEdges();
+                    list = m.<LayeredGraphNode>read( "n", MemoryType.LOCAL ).getSortedIncomingEdges();
                 ArrayList<LayeredGraphNode> result = new ArrayList<LayeredGraphNode>();
                 for( LayeredGraphEdge e : list )
                 {
@@ -152,7 +127,7 @@ public class BlockCalc implements AlgorithmStage {
             }
         } ) );
         layerLoop.add( nodeLoop );
-        nodeLoop.add( new PseudoCodeNode(TextLayoutHelper.setupPseudoCode( "neighbors = layout.contains('RIGHT') ? neighbors : reverse( neighbors )", vars), tree, new SetVariable<ArrayList<LayeredGraphNode>>( "neighbors" ) {
+        nodeLoop.add( new PseudoCodeNode( "neighbors = layout.contains('RIGHT') ? neighbors : reverse( neighbors )", vars, tree, new SetVariable<ArrayList<LayeredGraphNode>>( "neighbors" ) {
             @Override
             protected ArrayList<LayeredGraphNode> value(ReadOnlyMemory m) {
                 ArrayList<LayeredGraphNode> list = m.read( "neighbors", MemoryType.LOCAL );
@@ -167,14 +142,14 @@ public class BlockCalc implements AlgorithmStage {
                 }
             }
         } ) );
-        PseudoCodeNode ifNeighbors = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "if |neighbors| > 0 then", vars ), tree, new IfLoop() {
+        PseudoCodeNode ifNeighbors = new PseudoCodeNode( "if |neighbors| > 0 then", vars, tree, new IfLoop() {
             @Override
             protected boolean condition( ReadOnlyMemory m) {
                 return m.<ArrayList<LayeredGraphNode>>read( "neighbors", MemoryType.LOCAL ).size() > 0;
             }
         });
         nodeLoop.add( ifNeighbors );
-        ifNeighbors.add( new PseudoCodeNode(TextLayoutHelper.setupPseudoCode( "mids = [roundDown((|neighbors|-1)/2),roundUp((|neighbors|-1)/2)]", vars), tree, new DeclareVariable<ArrayList<Integer>>( "mids" ) {
+        ifNeighbors.add( new PseudoCodeNode( "mids = [roundDown((|neighbors|-1)/2),roundUp((|neighbors|-1)/2)]", vars, tree, new DeclareVariable<ArrayList<Integer>>( "mids" ) {
             @Override
             protected ArrayList<Integer> value(ReadOnlyMemory m) {
                 int size = m.<ArrayList<LayeredGraphNode>>read( "neighbors", MemoryType.LOCAL ).size() - 1;
@@ -186,27 +161,27 @@ public class BlockCalc implements AlgorithmStage {
                 return list;
             }
         } ) );
-        PseudoCodeNode midLoop = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "foreach m in mids do", vars ), tree, new ForEachLoop<Integer>( "m" ) {
+        PseudoCodeNode midLoop = new PseudoCodeNode( "foreach m in mids do", vars, tree, new ForEachLoop<Integer>( "m" ) {
             @Override
             protected List<Integer> list(ReadOnlyMemory m) {
                 return m.read( "mids", MemoryType.LOCAL );
             }
         } );
         ifNeighbors.add( midLoop );
-        PseudoCodeNode ifAlign = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "if align( L[i][k] ) == L[i][k] then", vars ), tree, new IfLoop() {
+        PseudoCodeNode ifAlign = new PseudoCodeNode( "if align[n] == n then", vars, tree, new IfLoop() {
             @Override
             protected boolean condition(ReadOnlyMemory m) {
-                LayeredGraphNode n = m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) ).get( m.read( "k", MemoryType.LOCAL ) );
+                LayeredGraphNode n = m.read( "n", MemoryType.LOCAL );
                 return n.getAlign( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) ) == n;
             }
         });
         midLoop.add( ifAlign );
-        PseudoCodeNode ifMarked = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "if (neighbors[m],L[i][k]) not conflicted and ((r < pos(neighbors[m]) and layout.contains('RIGHT')) or (r > pos(neighbors[m]) and layout.contains('LEFT'))) ", vars ), tree, new IfLoop() {
+        PseudoCodeNode ifMarked = new PseudoCodeNode( "if (neighbors[m],n) not conflicted and ((r < pos(neighbors[m]) and layout.contains('RIGHT')) or (r > pos(neighbors[m]) and layout.contains('LEFT'))) then", vars, tree, new IfLoop() {
             @Override
             protected boolean condition(ReadOnlyMemory m) {
                 LayeredGraphEdge e = m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).findEdgeBetween( 
                         m.<ArrayList<LayeredGraphNode>>read( "neighbors", MemoryType.LOCAL ).get( m.read( "m", MemoryType.LOCAL ) ), 
-                        m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) ).get( m.read( "k", MemoryType.LOCAL ) ) );
+                        m.read( "n", MemoryType.LOCAL ) );
                 ArrayList<LayeredGraphNode> layerBefore;
                 if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "DOWN" ) )
                     layerBefore = m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).get( m.<Integer>read( "i", MemoryType.LOCAL ) - 1 );
@@ -219,11 +194,11 @@ public class BlockCalc implements AlgorithmStage {
             }
         });
         ifAlign.add( ifMarked );
-        ifMarked.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "align( neighbors[m] ) = L[i][k];", vars ), tree, new CodeLine() {
+        ifMarked.add( new PseudoCodeNode( "align[neighbors[m]] = n;", vars, tree, new CodeLine() {
             @Override
             public ControlFlow runForward(Memory m) {
                 LayeredGraphNode u = m.<ArrayList<LayeredGraphNode>>read( "neighbors", MemoryType.LOCAL ).get( m.read( "m", MemoryType.LOCAL ) );
-                LayeredGraphNode v = m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) ).get( m.read( "k", MemoryType.LOCAL ) );
+                LayeredGraphNode v = m.read( "n", MemoryType.LOCAL );
                 LayeredGraphNode old = u.getAlign( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) );
                 u.setAlign( v, LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) );
                 actions.push( (Memory mem) -> {
@@ -232,11 +207,11 @@ public class BlockCalc implements AlgorithmStage {
                 return new ControlFlow( ControlFlow.STEP_OVER );
             }
         }) );
-        ifMarked.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "root( L[i][k] ) = root( neighbors[m] );", vars ), tree, new CodeLine() {
+        ifMarked.add( new PseudoCodeNode( "root[n] = root[neighbors[m]];", vars, tree, new CodeLine() {
             @Override
             public ControlFlow runForward(Memory m) {
                 LayeredGraphNode u = m.<ArrayList<LayeredGraphNode>>read( "neighbors", MemoryType.LOCAL ).get( m.read( "m", MemoryType.LOCAL ) );
-                LayeredGraphNode v = m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) ).get( m.read( "k", MemoryType.LOCAL ) );
+                LayeredGraphNode v = m.read( "n", MemoryType.LOCAL );
                 LayeredGraphNode old = v.getRoot( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) );
                 v.setRoot( u.getRoot( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) ), LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) );
                 actions.push( (Memory mem) -> {
@@ -245,10 +220,10 @@ public class BlockCalc implements AlgorithmStage {
                 return new ControlFlow( ControlFlow.STEP_OVER );
             }
         }) );
-        ifMarked.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "align( L[i][k] ) = root( L[i][k] );", vars ), tree, new CodeLine() {
+        ifMarked.add( new PseudoCodeNode( "align[n] = root[n];", vars, tree, new CodeLine() {
             @Override
             public ControlFlow runForward(Memory m) {
-                LayeredGraphNode v = m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) ).get( m.read( "k", MemoryType.LOCAL ) );
+                LayeredGraphNode v = m.read( "n", MemoryType.LOCAL );
                 LayeredGraphNode old = v.getAlign( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) );
                 v.setAlign( v.getRoot( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) ), LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) );
                 actions.push( (Memory mem) -> {
@@ -257,7 +232,7 @@ public class BlockCalc implements AlgorithmStage {
                 return new ControlFlow( ControlFlow.STEP_OVER );
             }
         }) );
-        ifMarked.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "r = pos( neighbors[m] );", vars ), tree, new SetVariable<Double>( "r" ) {
+        ifMarked.add( new PseudoCodeNode( "r = pos(neighbors[m]);", vars, tree, new SetVariable<Double>( "r" ) {
             @Override
             protected Double value(ReadOnlyMemory m) {
                 ArrayList<LayeredGraphNode> layerBefore;

+ 3 - 6
src/bk/Combine.java

@@ -2,22 +2,19 @@ package bk;
 
 import javax.swing.JTree;
 
-import animation.AlgorithmStage;
 import animation.PseudoCodeNode;
 import codelines.FunctionDefinition;
-import lib.TextLayoutHelper;
 
 /**
  * The stage of the combination of the four extremal layouts.
  * @author kolja
  *
  */
-public class Combine implements AlgorithmStage {
+public class Combine {
 
-    @Override
-    public PseudoCodeNode createPseudocodeTree( JTree tree ) {
+    public static PseudoCodeNode combine( JTree tree ) {
         String[] vars = { "graph" };
-        PseudoCodeNode root = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "function combine( graph )", vars ), tree, new FunctionDefinition( vars ) );
+        PseudoCodeNode root = new PseudoCodeNode( "function combine( graph )", vars, tree, new FunctionDefinition( vars ) );
         return root;
     }
 }

+ 155 - 7
src/bk/Compaction.java

@@ -1,23 +1,171 @@
 package bk;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import javax.swing.JTree;
 
-import animation.AlgorithmStage;
+import animation.CodeLine;
+import animation.ControlFlow;
+import animation.Memory;
+import animation.Memory.MemoryType;
+import animation.Memory.ReadOnlyMemory;
 import animation.PseudoCodeNode;
+import codelines.AbstractForLoop;
+import codelines.DeclareVariable;
+import codelines.ForEachLoop;
+import codelines.FunctionCall;
 import codelines.FunctionDefinition;
-import lib.TextLayoutHelper;
+import codelines.IfLoop;
+import graph.LayeredGraphNode;
 
 /**
  * The stage of compacting the layout.
  * @author kolja
  *
  */
-public class Compaction implements AlgorithmStage {
+public class Compaction {
 
-    @Override
-    public PseudoCodeNode createPseudocodeTree( JTree tree ) {
-        String[] vars = { "layout", "graph" };
-        PseudoCodeNode root = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "function horizontalCompaction( layout, graph )", vars ), tree, new FunctionDefinition( vars ) );
+    public static PseudoCodeNode horizontalCompaction( JTree tree, PseudoCodeNode placeBlock ) {
+        String[] vars = { "i", "L", "layout", "graph", "k", "v" };
+        @SuppressWarnings("serial")
+        PseudoCodeNode root = new PseudoCodeNode( "function horizontalCompaction( layout, graph )", vars, tree, new FunctionDefinition( new String[]{ "layout", "graph" } ) ) {
+            @Override
+            public String getDebugOutput( Memory m )
+            {
+                if( m.isSomewhereDefined( "v", MemoryType.LOCAL ) )
+                    m.<LayeredGraphNode>read( "v", MemoryType.LOCAL).setSelected( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) );
+                return super.getDebugOutput( m );
+            }
+        };
+        root.add( new PseudoCodeNode( "L = graph.getContainedLayers();", vars, tree, new DeclareVariable<ArrayList<ArrayList<LayeredGraphNode>>>( "L" ) {
+            @Override
+            protected ArrayList<ArrayList<LayeredGraphNode>> value(ReadOnlyMemory m) {
+                return m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).getContainedLayers();
+            }
+        } ) );
+        PseudoCodeNode firstLoop = new PseudoCodeNode( "for i=layout.contains('DOWN') ? 0 : |L|-1 to layout.contains('DOWN') ? |L|-1 : 0 do", vars, tree, new AbstractForLoop<Integer>( "i" ) {
+            @Override
+            protected Integer begin(ReadOnlyMemory m) {
+                if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "DOWN" ) )
+                    return 0;
+                return m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).size() - 1;
+            }
+            @Override
+            protected Integer step(ReadOnlyMemory m) {
+                if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "DOWN" ) )
+                    return m.<Integer>read( "i", MemoryType.LOCAL ) + 1;
+                return m.<Integer>read( "i", MemoryType.LOCAL ) - 1;
+            }
+            @Override
+            protected boolean condition(ReadOnlyMemory m) {
+                if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "DOWN" ) )
+                    return m.<Integer>read( "i", MemoryType.LOCAL ) <= m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).size() - 1;
+                return m.<Integer>read( "i", MemoryType.LOCAL ) >= 0;
+            }
+        });
+        root.add( firstLoop );
+        PseudoCodeNode nodeLoop = new PseudoCodeNode( "for k=layout.contains('RIGHT') ? 0 : |L[i]|-1 to layout.contains('RIGHT') ? |L[i]|-1 : 0 do", vars, tree, new AbstractForLoop<Integer>( "k" ) {
+            @Override
+            protected Integer begin( ReadOnlyMemory m) {
+                if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "RIGHT" ) )
+                    return 0;
+                return m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) ).size() - 1;
+            }
+            @Override
+            protected Integer step( ReadOnlyMemory m) {
+                if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "RIGHT" ) )
+                    return m.<Integer>read( "k", MemoryType.LOCAL ) + 1;
+                return m.<Integer>read( "k", MemoryType.LOCAL ) - 1;
+            }
+            @Override
+            protected boolean condition( ReadOnlyMemory m) {
+                if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "RIGHT" ) )
+                    return m.<Integer>read( "k", MemoryType.LOCAL ) <= m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) ).size() - 1;
+                return m.<Integer>read( "k", MemoryType.LOCAL ) >= 0;
+            }
+        });
+        firstLoop.add( nodeLoop );
+        nodeLoop.add( new PseudoCodeNode( "v = L[i][k];", vars, tree, new DeclareVariable<LayeredGraphNode>( "v" ) {
+            @Override
+            protected LayeredGraphNode value(ReadOnlyMemory m) {
+                return m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) ).get( m.read( "k", MemoryType.LOCAL ) );
+            }
+        }));
+        PseudoCodeNode ifRoot = new PseudoCodeNode( "if root[v] == v then", vars, tree, new IfLoop() {
+            @Override
+            protected boolean condition(ReadOnlyMemory m) {
+                return m.<LayeredGraphNode>read( "v", MemoryType.LOCAL ).getRoot( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) ) == m.<LayeredGraphNode>read( "v", MemoryType.LOCAL );
+            }
+        });
+        nodeLoop.add( ifRoot );
+        ifRoot.add( new PseudoCodeNode( "call place_block(v);", vars, tree, new FunctionCall( placeBlock, new String[]{ "v" } ) ) );
+        PseudoCodeNode secondLoop = new PseudoCodeNode( "for i=layout.contains('DOWN') ? 0 : |L|-1 to layout.contains('DOWN') ? |L|-1 : 0 do", vars, tree, new AbstractForLoop<Integer>( "i" ) {
+            @Override
+            protected Integer begin(ReadOnlyMemory m) {
+                if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "DOWN" ) )
+                    return 0;
+                return m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).size() - 1;
+            }
+            @Override
+            protected Integer step(ReadOnlyMemory m) {
+                if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "DOWN" ) )
+                    return m.<Integer>read( "i", MemoryType.LOCAL ) + 1;
+                return m.<Integer>read( "i", MemoryType.LOCAL ) - 1;
+            }
+            @Override
+            protected boolean condition(ReadOnlyMemory m) {
+                if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "DOWN" ) )
+                    return m.<Integer>read( "i", MemoryType.LOCAL ) <= m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).size() - 1;
+                return m.<Integer>read( "i", MemoryType.LOCAL ) >= 0;
+            }
+        });
+        root.add( secondLoop );
+        PseudoCodeNode foreach = new PseudoCodeNode( "foreach v in L[i] do", vars, tree, new ForEachLoop<LayeredGraphNode>( "v" ) {
+            @Override
+            protected List<LayeredGraphNode> list(ReadOnlyMemory m) {
+                return m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) );
+            }
+        });
+        secondLoop.add( foreach );
+        foreach.add( new PseudoCodeNode( "x[v] = x[root[v]];", vars, tree, new CodeLine() {
+            @Override
+            public ControlFlow runForward(Memory m) {
+                LayeredGraphNode v = m.read( "v", MemoryType.LOCAL );
+                LayoutType layout = LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) );
+                double old = v.getX( layout );
+                boolean oldDef = !v.isXUndefined( layout );
+                v.setX( v.getRoot( layout ).getX( layout ), true, layout );
+                actions.push( (Memory mem) -> {
+                    v.setX( old, oldDef, layout );
+                });
+                return new ControlFlow( ControlFlow.STEP_OVER );
+            }
+        }));
+        PseudoCodeNode ifShift = new PseudoCodeNode( "if v == root[v] and ((layout.contains('RIGHT') and shift[sink[v]] < ∞ ) or (layout.contains('LEFT') and shift[sink[v]] > -∞ )) then", vars, tree, new IfLoop() {
+            @Override
+            protected boolean condition(ReadOnlyMemory m) {
+                LayeredGraphNode v = m.read( "v", MemoryType.LOCAL );
+                String lStr = m.read( "layout", MemoryType.LOCAL );
+                LayoutType layout = LayoutType.fromString( lStr );
+                return v == v.getRoot( layout ) && ((lStr.contains( "RIGHT" ) && v.getSink( layout ).getShift( layout ) < Double.POSITIVE_INFINITY ) || (lStr.contains( "LEFT" ) && v.getSink( layout ).getShift( layout ) > Double.NEGATIVE_INFINITY ));
+            }
+        });
+        foreach.add( ifShift );
+        ifShift.add( new PseudoCodeNode( "x[v] += shift[sink[v]];", vars, tree, new CodeLine() {
+            @Override
+            public ControlFlow runForward(Memory m) {
+                LayeredGraphNode v = m.read( "v", MemoryType.LOCAL );
+                LayoutType layout = LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) );
+                double old = v.getX( layout );
+                boolean oldDef = !v.isXUndefined( layout );
+                v.setX( v.getSink( layout ).getShift( layout ), true, layout );
+                actions.push( (Memory mem) -> {
+                    v.setX( old, oldDef, layout );
+                });
+                return new ControlFlow( ControlFlow.STEP_OVER );
+            }
+        }));
         return root;
     }
 }

+ 78 - 92
src/bk/ConflictDetection.java

@@ -5,14 +5,12 @@ import java.util.List;
 
 import javax.swing.JTree;
 
-import animation.AlgorithmStage;
 import animation.CodeLine;
 import animation.ControlFlow;
 import animation.Memory;
 import animation.PseudoCodeNode;
 import animation.Memory.MemoryType;
 import animation.Memory.ReadOnlyMemory;
-import bk.BKNodePlacement.State;
 import bk.LayoutType;
 import codelines.DeclareVariable;
 import codelines.ForEachLoop;
@@ -33,109 +31,97 @@ import lib.TextLayoutHelper;
  * @author kolja and eren
  *
  */
-public class ConflictDetection implements AlgorithmStage {
-
-    private BKNodePlacement alg;
+public class ConflictDetection {
     
-    public ConflictDetection( BKNodePlacement bknpa )
-    {
-        alg = bknpa;
+    public static String buildDebugString( Memory m ) {
+        if( m.isSomewhereDefined( "l", MemoryType.LOCAL ) && m.isSomewhereDefined( "i", MemoryType.LOCAL ) && 
+                m.<Integer>read( "l", MemoryType.LOCAL ) < m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL).getContainedLayers().get( m.<Integer>read( "i", MemoryType.LOCAL ) + 1 ).size() )
+            m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL).getContainedLayers().get(m.<Integer>read( "i", MemoryType.LOCAL ) + 1).get(m.<Integer>read( "l", MemoryType.LOCAL )).setSelected(null);
+        
+        if( m.isSomewhereDefined( "i", MemoryType.LOCAL ) && m.isSomewhereDefined( "l1", MemoryType.LOCAL ) &&
+                m.<Integer>read( "l1", MemoryType.LOCAL ) < m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL).getContainedLayers().get(m.<Integer>read( "i", MemoryType.LOCAL ) + 1).size() ) {
+            m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL).getContainedLayers().get(m.<Integer>read( "i", MemoryType.LOCAL ) + 1).get(m.<Integer>read( "l1", MemoryType.LOCAL )).setSelected(null);
+        }
+        
+        if( m.isSomewhereDefined( "i", MemoryType.LOCAL ) && m.isSomewhereDefined( "k0", MemoryType.LOCAL ) && 
+                m.<Integer>read( "k0", MemoryType.LOCAL ) <  m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL).getContainedLayers().get(m.read( "i", MemoryType.LOCAL )).size()) {
+            m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL).getContainedLayers().get(m.read( "i", MemoryType.LOCAL )).get(m.<Integer>read( "k0", MemoryType.LOCAL )).setSelected(null);
+        }
+        
+        if( m.isSomewhereDefined( "i", MemoryType.LOCAL ) && m.isSomewhereDefined( "k1", MemoryType.LOCAL ) && 
+                m.<Integer>read( "k1", MemoryType.LOCAL ) < m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL).getContainedLayers().get(m.read( "i", MemoryType.LOCAL )).size() ) {
+            m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL).getContainedLayers().get(m.read( "i", MemoryType.LOCAL )).get(m.<Integer>read( "k1", MemoryType.LOCAL )).setSelected(null);
+        }
+        
+        if( m.isSomewhereDefined( "n", MemoryType.LOCAL ) )
+        {
+            m.<LayeredGraphNode>read( "n", MemoryType.LOCAL ).setSelected( null );
+        }
+        String info = "| i  | l  | l1 | k0 | k1 |  v  |  n  |\n";
+        info +=       "|----|----|----|----|----|-----|-----|\n";
+        String i = "null";
+        String l = "null";
+        String l1 = "null";
+        String k0 = "null";
+        String k1 = "null";
+        String v = "null";
+        String n = "null";
+        if( m.isSomewhereDefined( "i", MemoryType.LOCAL ) )
+            i = "" + m.<Integer>read( "i", MemoryType.LOCAL );
+        if( m.isSomewhereDefined( "l", MemoryType.LOCAL ) )
+            l = "" + m.<Integer>read( "l", MemoryType.LOCAL );
+        if( m.isSomewhereDefined( "l1", MemoryType.LOCAL ) )
+            l1 = "" + m.<Integer>read( "l1", MemoryType.LOCAL );
+        if( m.isSomewhereDefined( "k0", MemoryType.LOCAL ) )
+            k0 = "" + m.<Integer>read( "k0", MemoryType.LOCAL );
+        if( m.isSomewhereDefined( "k1", MemoryType.LOCAL ) )
+            k1 = "" + m.<Integer>read( "k1", MemoryType.LOCAL );
+        if( m.isSomewhereDefined( "v", MemoryType.LOCAL ) && m.<LayeredGraphEdge>read( "v", MemoryType.LOCAL ).getSources().get( 0 ).getName() != null )
+            v = "" + m.<LayeredGraphEdge>read( "v", MemoryType.LOCAL ).getSources().get( 0 ).getName();
+        if( m.isSomewhereDefined( "n", MemoryType.LOCAL ) && m.<LayeredGraphNode>read( "n", MemoryType.LOCAL ).getName() != null )
+            n = "" + m.<LayeredGraphNode>read( "n", MemoryType.LOCAL ).getName();
+        info += "|" + TextLayoutHelper.strToLen( i, 4 ) + 
+                "|" + TextLayoutHelper.strToLen( l, 4 ) + 
+                "|" + TextLayoutHelper.strToLen( l1, 4 ) + 
+                "|" + TextLayoutHelper.strToLen( k0, 4 ) + 
+                "|" + TextLayoutHelper.strToLen( k1, 4 ) + 
+                "|" + TextLayoutHelper.strToLen( v, 5 ) + 
+                "|" + TextLayoutHelper.strToLen( n, 5 ) + "|\n";
+        return info;
     }
     
-    @Override
-    public PseudoCodeNode createPseudocodeTree(JTree tree) {
+    public static PseudoCodeNode mark_conflicts(JTree tree) {
         String vars[] = { "i", "L", "k0", "l", "l1", "k1", "v", "graph", "n" };
         String params[] = { "graph" };
-        @SuppressWarnings("serial")
-        PseudoCodeNode root = new PseudoCodeNode(TextLayoutHelper.setupPseudoCode("function mark_conflicts( graph )", vars), tree, new FunctionDefinition( params ) ) {
-            @Override
-            public String getDebugOutput( Memory m )
-            {
-                alg.setAlgorithmState( State.CONFLICTS );
-                if( m.isSomewhereDefined( "l", MemoryType.LOCAL ) && m.isSomewhereDefined( "i", MemoryType.LOCAL ) && 
-                        m.<Integer>read( "l", MemoryType.LOCAL ) < m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL).getContainedLayers().get( m.<Integer>read( "i", MemoryType.LOCAL ) + 1 ).size() )
-                    m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL).getContainedLayers().get(m.<Integer>read( "i", MemoryType.LOCAL ) + 1).get(m.<Integer>read( "l", MemoryType.LOCAL )).setSelected(null);
-                
-                if( m.isSomewhereDefined( "i", MemoryType.LOCAL ) && m.isSomewhereDefined( "l1", MemoryType.LOCAL ) &&
-                        m.<Integer>read( "l1", MemoryType.LOCAL ) < m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL).getContainedLayers().get(m.<Integer>read( "i", MemoryType.LOCAL ) + 1).size() ) {
-                    m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL).getContainedLayers().get(m.<Integer>read( "i", MemoryType.LOCAL ) + 1).get(m.<Integer>read( "l1", MemoryType.LOCAL )).setSelected(null);
-                }
-                
-                if( m.isSomewhereDefined( "i", MemoryType.LOCAL ) && m.isSomewhereDefined( "k0", MemoryType.LOCAL ) && 
-                        m.<Integer>read( "k0", MemoryType.LOCAL ) <  m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL).getContainedLayers().get(m.read( "i", MemoryType.LOCAL )).size()) {
-                    m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL).getContainedLayers().get(m.read( "i", MemoryType.LOCAL )).get(m.<Integer>read( "k0", MemoryType.LOCAL )).setSelected(null);
-                }
-                
-                if( m.isSomewhereDefined( "i", MemoryType.LOCAL ) && m.isSomewhereDefined( "k1", MemoryType.LOCAL ) && 
-                        m.<Integer>read( "k1", MemoryType.LOCAL ) < m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL).getContainedLayers().get(m.read( "i", MemoryType.LOCAL )).size() ) {
-                    m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL).getContainedLayers().get(m.read( "i", MemoryType.LOCAL )).get(m.<Integer>read( "k1", MemoryType.LOCAL )).setSelected(null);
-                }
-                
-                if( m.isSomewhereDefined( "n", MemoryType.LOCAL ) )
-                {
-                    m.<LayeredGraphNode>read( "n", MemoryType.LOCAL ).setSelected( null );
-                }
-                String info = "| i  | l  | l1 | k0 | k1 |  v  |  n  |\n";
-                info +=       "|----|----|----|----|----|-----|-----|\n";
-                String i = "null";
-                String l = "null";
-                String l1 = "null";
-                String k0 = "null";
-                String k1 = "null";
-                String v = "null";
-                String n = "null";
-                if( m.isSomewhereDefined( "i", MemoryType.LOCAL ) )
-                    i = "" + m.<Integer>read( "i", MemoryType.LOCAL );
-                if( m.isSomewhereDefined( "l", MemoryType.LOCAL ) )
-                    l = "" + m.<Integer>read( "l", MemoryType.LOCAL );
-                if( m.isSomewhereDefined( "l1", MemoryType.LOCAL ) )
-                    l1 = "" + m.<Integer>read( "l1", MemoryType.LOCAL );
-                if( m.isSomewhereDefined( "k0", MemoryType.LOCAL ) )
-                    k0 = "" + m.<Integer>read( "k0", MemoryType.LOCAL );
-                if( m.isSomewhereDefined( "k1", MemoryType.LOCAL ) )
-                    k1 = "" + m.<Integer>read( "k1", MemoryType.LOCAL );
-                if( m.isSomewhereDefined( "v", MemoryType.LOCAL ) && m.<LayeredGraphEdge>read( "v", MemoryType.LOCAL ).getSources().get( 0 ).getName() != null )
-                    v = "" + m.<LayeredGraphEdge>read( "v", MemoryType.LOCAL ).getSources().get( 0 ).getName();
-                if( m.isSomewhereDefined( "n", MemoryType.LOCAL ) && m.<LayeredGraphNode>read( "n", MemoryType.LOCAL ).getName() != null )
-                    n = "" + m.<LayeredGraphNode>read( "n", MemoryType.LOCAL ).getName();
-                info += "|" + TextLayoutHelper.strToLen( i, 4 ) + 
-                        "|" + TextLayoutHelper.strToLen( l, 4 ) + 
-                        "|" + TextLayoutHelper.strToLen( l1, 4 ) + 
-                        "|" + TextLayoutHelper.strToLen( k0, 4 ) + 
-                        "|" + TextLayoutHelper.strToLen( k1, 4 ) + 
-                        "|" + TextLayoutHelper.strToLen( v, 5 ) + 
-                        "|" + TextLayoutHelper.strToLen( n, 5 ) + "|\n";
-                return info;
-            }
-        };
-        PseudoCodeNode text = new PseudoCodeNode(TextLayoutHelper.setupPseudoCodeStage( "-- mark conflicts in subgraphs --" ), tree, new Comment() );
+        PseudoCodeNode root = new PseudoCodeNode( "function mark_conflicts( graph )", vars, tree, new FunctionDefinition( params ) );
+        PseudoCodeNode text = new PseudoCodeNode( "-- mark conflicts in subgraphs --", vars, tree, new Comment() );
         root.add( text );
-        PseudoCodeNode foreach = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "foreach n in graph.getContainedNodes() do", vars ), tree, new ForEachLoop<LayeredGraphNode>( "n" ) {
+        PseudoCodeNode foreach = new PseudoCodeNode( "foreach n in graph.getContainedNodes() do", vars, tree, new ForEachLoop<LayeredGraphNode>( "n" ) {
 			@Override
 			protected List<LayeredGraphNode> list(ReadOnlyMemory m) {
 				return m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).getContainedNodes();
 			}
         } );
         root.add( foreach );
-        PseudoCodeNode ifNode = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "if n has subgraph then", vars ), tree, new IfLoop() {
+        PseudoCodeNode ifNode = new PseudoCodeNode( "if n has subgraph then", vars, tree, new IfLoop() {
 			@Override
 			protected boolean condition(ReadOnlyMemory m) {
 				return m.<LayeredGraphNode>read( "n", MemoryType.LOCAL ).getContainedLayers().size() > 0;
 			}
         } );
         foreach.add( ifNode );
-        PseudoCodeNode call = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "call mark_conflicts( n );", vars ), tree, new FunctionCall( root, new String[]{ "n" } ) );
+        PseudoCodeNode call = new PseudoCodeNode( "call mark_conflicts( n );", vars, tree, new FunctionCall( root, new String[]{ "n" } ) );
         ifNode.add( call );
-        text = new PseudoCodeNode(TextLayoutHelper.setupPseudoCodeStage( "-- mark conflicts in graph --" ), tree, new Comment() );
+        text = new PseudoCodeNode( "-- mark conflicts in graph --", vars, tree, new Comment() );
         root.add( text );
-        PseudoCodeNode init = new PseudoCodeNode(TextLayoutHelper.setupPseudoCode( "L = graph.getContainedLayers();", vars), tree, new DeclareVariable<ArrayList<ArrayList<LayeredGraphNode>>>( "L" ) {
+        PseudoCodeNode init = new PseudoCodeNode( "L = graph.getContainedLayers();", vars, tree, new DeclareVariable<ArrayList<ArrayList<LayeredGraphNode>>>( "L" ) {
             @Override
             protected ArrayList<ArrayList<LayeredGraphNode>> value(ReadOnlyMemory m) {
                 return m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).getContainedLayers();
             }
         } );
         root.add( init );
-        PseudoCodeNode outerLoop = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "for i=1 to |L|-2 do", vars ), tree, new ForLoop( "i" ) {
+        PseudoCodeNode outerLoop = new PseudoCodeNode( "for i=1 to |L|-2 do", vars, tree, new ForLoop( "i" ) {
 			@Override
 			protected int minimum( ReadOnlyMemory m ) {
 				return 1;
@@ -146,7 +132,7 @@ public class ConflictDetection implements AlgorithmStage {
 			}
         } );
         root.add( outerLoop );
-        PseudoCodeNode line = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "k0 = 0; l = 0;", vars ), tree, new CodeLine() {
+        PseudoCodeNode line = new PseudoCodeNode( "k0 = 0; l = 0;", vars, tree, new CodeLine() {
 			@Override
 			public ControlFlow runForward(Memory m) {
 				m.declare( "k0", 0, MemoryType.LOCAL );
@@ -159,7 +145,7 @@ public class ConflictDetection implements AlgorithmStage {
 			}
         } );
         outerLoop.add( line );
-        PseudoCodeNode innerLoop = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "for l1=0 to |L[i+1]|-1 do", vars ), tree, new ForLoop( "l1" ) {
+        PseudoCodeNode innerLoop = new PseudoCodeNode( "for l1=0 to |L[i+1]|-1 do", vars, tree, new ForLoop( "l1" ) {
 			@Override
 			protected int minimum(ReadOnlyMemory m) {
 				return 0;
@@ -170,7 +156,7 @@ public class ConflictDetection implements AlgorithmStage {
 			}
         } );
         outerLoop.add( innerLoop );
-        ifNode = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "if l1==|L[i+1]|-1 or L[i+1][l1] incident to inner segment between L[i+1] and L[i] then", vars ), tree, new IfLoop() {
+        ifNode = new PseudoCodeNode( "if l1==|L[i+1]|-1 or L[i+1][l1] incident to inner segment between L[i+1] and L[i] then", vars, tree, new IfLoop() {
 			@Override
 			protected boolean condition(ReadOnlyMemory m) {
 	            return m.<Integer>read( "l1", MemoryType.LOCAL ) == m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).getContainedLayers().get( m.<Integer>read( "i", MemoryType.LOCAL ) + 1).size() - 1 || 
@@ -178,14 +164,14 @@ public class ConflictDetection implements AlgorithmStage {
 			}
         } );
         innerLoop.add( ifNode );
-        line = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "k1 = |L[i]|-1;", vars ), tree, new DeclareVariable<Integer>( "k1" ) {
+        line = new PseudoCodeNode( "k1 = |L[i]|-1;", vars, tree, new DeclareVariable<Integer>( "k1" ) {
 			@Override
 			protected Integer value(ReadOnlyMemory m) {
 				return (int)m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) ).size() - 1;
 			}
         } );
         ifNode.add( line );
-        PseudoCodeNode innerIfNode = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "if L[i+1][l1] incident to inner segment between L[i+1] and L[i] then", vars ), tree, new IfLoop() {
+        PseudoCodeNode innerIfNode = new PseudoCodeNode( "if L[i+1][l1] incident to inner segment between L[i+1] and L[i] then", vars, tree, new IfLoop() {
 			@Override
 			protected boolean condition(ReadOnlyMemory m) {
 				return incidentToInnerSegmentBetweenLiPlusOneAndLi( m );
@@ -193,7 +179,7 @@ public class ConflictDetection implements AlgorithmStage {
 		} );
         ifNode.add( innerIfNode );
         
-        line = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "k1 = pos(pred(L[i+1][l1])[0]);", vars ), tree, new SetVariable<Integer>( "k1" ) {
+        line = new PseudoCodeNode( "k1 = pos(pred(L[i+1][l1])[0]);", vars, tree, new SetVariable<Integer>( "k1" ) {
 			@Override
 			protected Integer value(ReadOnlyMemory m) {
 				return (int)m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).getContainedLayers().get( m.read( "i", MemoryType.LOCAL ) ).indexOf(
@@ -201,21 +187,21 @@ public class ConflictDetection implements AlgorithmStage {
 			}
         } );
         innerIfNode.add( line );
-        PseudoCodeNode whileLoop = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "while l <= l1 do", vars ), tree, new WhileLoop() {
+        PseudoCodeNode whileLoop = new PseudoCodeNode( "while l <= l1 do", vars, tree, new WhileLoop() {
 			@Override
 			protected boolean condition( ReadOnlyMemory m ) {
 				return m.<Integer>read( "l", MemoryType.LOCAL ) <= m.<Integer>read( "l1", MemoryType.LOCAL );
 			}
         } );
         ifNode.add( whileLoop );
-        foreach = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "foreach v in pred(L[i+1][l]) do", vars ), tree, new ForEachLoop<LayeredGraphEdge>( "v" ) {
+        foreach = new PseudoCodeNode( "foreach v in pred(L[i+1][l]) do", vars, tree, new ForEachLoop<LayeredGraphEdge>( "v" ) {
 			@Override
 			protected List<LayeredGraphEdge> list(ReadOnlyMemory m) {
 				return m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).getContainedLayers().get( m.<Integer>read( "i", MemoryType.LOCAL ) + 1 ).get( m.read( "l", MemoryType.LOCAL ) ).getIncomingEdges();
 			}
         } );
         whileLoop.add( foreach );
-        innerIfNode = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "if pos(v) < k0 or pos(v) > k1 then", vars ), tree, new IfLoop() {
+        innerIfNode = new PseudoCodeNode( "if pos(v) < k0 or pos(v) > k1 then", vars, tree, new IfLoop() {
 			@Override
 			protected boolean condition(ReadOnlyMemory m) {
 			    int k = m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).getContainedLayers().get( m.read( "i", MemoryType.LOCAL ) ).indexOf( m.<LayeredGraphEdge>read( "v", MemoryType.LOCAL ).getSources().get( 0 ) );
@@ -223,7 +209,7 @@ public class ConflictDetection implements AlgorithmStage {
 			}
         } );
         foreach.add( innerIfNode );
-        line = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "mark segment (v,L[i+1][l]);", vars ), tree, new CodeLine() {
+        line = new PseudoCodeNode( "mark segment (v,L[i+1][l]);", vars, tree, new CodeLine() {
 			@Override
 			public ControlFlow runForward(Memory m) {
 				LayeredGraphEdge e = m.read( "v", MemoryType.LOCAL );
@@ -236,14 +222,14 @@ public class ConflictDetection implements AlgorithmStage {
 			}
         } );
         innerIfNode.add( line );
-        line = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "l = l+1;", vars ), tree, new SetVariable<Integer>( "l" ) {
+        line = new PseudoCodeNode( "l = l+1;", vars, tree, new SetVariable<Integer>( "l" ) {
 			@Override
 			protected Integer value(ReadOnlyMemory m) {
 				return (int)m.<Integer>read( "l", MemoryType.LOCAL ) + 1;
 			}
         } );
         whileLoop.add( line );
-        line = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "k0 = k1;", vars ), tree, new SetVariable<Integer>( "k0" ) {
+        line = new PseudoCodeNode( "k0 = k1;", vars, tree, new SetVariable<Integer>( "k0" ) {
 			@Override
 			protected Integer value(ReadOnlyMemory m) {
 				return (int)m.<Integer>read( "k1", MemoryType.LOCAL );
@@ -253,7 +239,7 @@ public class ConflictDetection implements AlgorithmStage {
         return root;
     }
     
-    private boolean incidentToInnerSegmentBetweenLiPlusOneAndLi( ReadOnlyMemory m ) {
+    private static boolean incidentToInnerSegmentBetweenLiPlusOneAndLi( ReadOnlyMemory m ) {
         LayeredGraphNode curr = m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).getContainedLayers().get( m.<Integer>read( "i", MemoryType.LOCAL ) + 1 ).get( m.read( "l1", MemoryType.LOCAL ) );
         for (LayeredGraphEdge e : curr.getIncomingEdges()) {
             if (e.isDummyEdge()) {

+ 167 - 0
src/bk/PlaceBlock.java

@@ -0,0 +1,167 @@
+package bk;
+
+import javax.swing.JTree;
+
+import animation.CodeLine;
+import animation.ControlFlow;
+import animation.Memory;
+import animation.Memory.MemoryType;
+import animation.Memory.ReadOnlyMemory;
+import animation.PseudoCodeNode;
+import codelines.FunctionCall;
+import codelines.FunctionDefinition;
+import codelines.IfLoop;
+import codelines.SetVariable;
+import codelines.WhileLoop;
+import graph.LayeredGraphNode;
+// PAPER = OUR
+
+// DOWN = RIGHT
+// UP = LEFT
+// RIGHT = DOWN
+// LEFT = UP
+public class PlaceBlock{
+
+    public static PseudoCodeNode place_block(JTree tree) {
+        String vars[] = { "v", "w", "layout", "x", "y", "graph", "u", "root", "align", "first" };
+        @SuppressWarnings("serial")
+        PseudoCodeNode root = new PseudoCodeNode( "function place_block( v, layout )", vars, tree, new FunctionDefinition(new String[]{ "v", "layout" } ) ) {
+            @Override
+            public String getDebugOutput( Memory m )
+            {
+                if( m.isSomewhereDefined( "v", MemoryType.LOCAL ) && !m.isSomewhereDefined( "w", MemoryType.LOCAL ) )
+                    m.<LayeredGraphNode>read( "v", MemoryType.LOCAL).setSelected( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) );
+                if( m.isSomewhereDefined( "w", MemoryType.LOCAL ) )
+                    m.<LayeredGraphNode>read( "w", MemoryType.LOCAL).setSelected( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) );
+                return super.getDebugOutput( m );
+            }
+        };
+        PseudoCodeNode ifUndef = new PseudoCodeNode( "if x[v] == undefined then", vars, tree, new IfLoop() {
+            @Override
+            protected boolean condition(ReadOnlyMemory m) {
+                return m.<LayeredGraphNode>read( "v", MemoryType.LOCAL ).isXUndefined( m.read( "layout", MemoryType.LOCAL ) );
+            }
+        });
+        root.add( ifUndef );
+        ifUndef.add( new PseudoCodeNode( "x[v] = 0; w = v; first = true;", vars, tree, new CodeLine() {
+            @Override
+            public ControlFlow runForward(Memory m) {
+                m.declare( "w", m.read( "v", MemoryType.LOCAL ), MemoryType.LOCAL );
+                m.declare( "first", true, MemoryType.LOCAL );
+                double oldX = m.<LayeredGraphNode>read( "v", MemoryType.LOCAL ).getX( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) );
+                m.<LayeredGraphNode>read( "v", MemoryType.LOCAL ).setX( 0, true, LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) );
+                actions.push( (Memory mem) -> {
+                    mem.undeclare( "w", MemoryType.LOCAL );
+                    mem.undeclare( "first", MemoryType.LOCAL );
+                    m.<LayeredGraphNode>read( "v", MemoryType.LOCAL ).setX( oldX, false, LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) );
+                });
+                return new ControlFlow( ControlFlow.STEP_OVER );
+            }
+        }));
+        PseudoCodeNode whilewv = new PseudoCodeNode( "while w != v or first", vars, tree, new WhileLoop() {
+            @Override
+            protected boolean condition(ReadOnlyMemory m) {
+                return m.read( "w", MemoryType.LOCAL ) != m.read( "v", MemoryType.LOCAL ) || m.<Boolean>read( "first", MemoryType.LOCAL );
+            }
+        });
+        ifUndef.add( whilewv );
+        whilewv.add( new PseudoCodeNode( "first = false;", vars, tree, new SetVariable<Boolean>( "first" ) {
+            @Override
+            protected Boolean value(ReadOnlyMemory m) {
+                return false;
+            }
+        }));
+        PseudoCodeNode ifPos = new PseudoCodeNode( "if (layout.contains('RIGHT') and pos(w)>0) or (layout.contains('LEFT') and pos(w)<|layerOf(w)|-1) then", vars, tree, new IfLoop() {
+            @Override
+            protected boolean condition(ReadOnlyMemory m) {
+                LayeredGraphNode w = m.read( "w", MemoryType.LOCAL );
+                LayeredGraphNode graph = w.parent();
+                return (m.<String>read( "layout", MemoryType.LOCAL ).contains( "RIGHT" ) && graph.getContainedLayers().get( w.getLayer() ).indexOf( w ) > 0 ) ||
+                       (m.<String>read( "layout", MemoryType.LOCAL ).contains( "LEFT" ) && graph.getContainedLayers().get( w.getLayer() ).indexOf( w ) < graph.getContainedLayers().get( w.getLayer() ).size() - 1 );
+            }
+        });
+        whilewv.add( ifPos );
+        ifPos.add( new PseudoCodeNode( "u = layout.contains('RIGHT') ? root[fore(w)] : root[foll(w)];", vars, tree, new SetVariable<LayeredGraphNode>( "w" ) {
+            @Override
+            protected LayeredGraphNode value(ReadOnlyMemory m) {
+                LayeredGraphNode w = m.read( "w", MemoryType.LOCAL );
+                LayeredGraphNode graph = w.parent();
+                if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "RIGHT" ) )
+                    return graph.getContainedLayers().get( w.getLayer() ).get( graph.getContainedLayers().get( w.getLayer() ).indexOf( w ) - 1 );
+                return graph.getContainedLayers().get( w.getLayer() ).get( graph.getContainedLayers().get( w.getLayer() ).indexOf( w ) + 1 );
+            }
+        }));
+        ifPos.add( new PseudoCodeNode( "call place_block( u, layout );", vars, tree, new FunctionCall( root, new String[]{ "u", "layout" } ) ) );
+        ifPos.add( new PseudoCodeNode( "sink[v] = sink[v] == v ? sink[u] : sink[v];", vars, tree, new CodeLine() {
+            @Override
+            public ControlFlow runForward(Memory m) {
+                LayeredGraphNode v = m.read( "v", MemoryType.LOCAL );
+                LayeredGraphNode u = m.read( "u", MemoryType.LOCAL );
+                LayoutType layout = LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) );
+                LayeredGraphNode old = v.getSink( layout );
+                v.setSink( old == v ? u.getSink( layout ) : old, layout );
+                actions.push( (Memory mem) -> {
+                   v.setSink( old, layout ); 
+                });
+                return new ControlFlow( ControlFlow.STEP_OVER );
+            }
+        }));
+        PseudoCodeNode ifSink1 = new PseudoCodeNode( "if sink[v] != sink[u] then", vars, tree, new IfLoop() {
+            @Override
+            protected boolean condition(ReadOnlyMemory m) {
+                LayoutType layout = LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) );
+                return m.<LayeredGraphNode>read( "v", MemoryType.LOCAL ).getSink( layout ) != m.<LayeredGraphNode>read( "u", MemoryType.LOCAL ).getSink( layout );
+            }
+        });
+        ifPos.add( ifSink1 );
+        ifSink1.add( new PseudoCodeNode( "shift[sink[u]] = layout.contains('RIGHT') ? max(shift[sink[u]], x[v] + x[u] + 45) : min(shift[sink[u]], x[v] - x[u] - 45);", vars, tree, new CodeLine() {
+            @Override
+            public ControlFlow runForward(Memory m) {
+                String lStr = m.read( "layout", MemoryType.LOCAL );
+                LayoutType layout = LayoutType.fromString( lStr );
+                LayeredGraphNode v = m.read( "v", MemoryType.LOCAL );
+                LayeredGraphNode u = m.read( "u", MemoryType.LOCAL );
+                double old = u.getSink( layout ).getShift( layout );
+                u.getSink( layout ).setShift( lStr.contains( "RIGHT" ) ? 
+                        Math.min( u.getSink( layout ).getShift( layout ), v.getX( layout ) - u.getX( layout ) - 45 ) : 
+                            Math.max( u.getSink( layout ).getShift( layout ), v.getX( layout ) + u.getX( layout ) + 45 ), layout);
+                actions.push( (Memory mem) -> {
+                    u.getSink( layout ).setShift( old, layout );
+                });
+                return new ControlFlow( ControlFlow.STEP_OVER );
+            }
+        }));
+        PseudoCodeNode ifSink2 = new PseudoCodeNode( "if sink[v] == sink[u] then", vars, tree, new IfLoop() {
+            @Override
+            protected boolean condition(ReadOnlyMemory m) {
+                LayoutType layout = LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) );
+                return m.<LayeredGraphNode>read( "v", MemoryType.LOCAL ).getSink( layout ) == m.<LayeredGraphNode>read( "u", MemoryType.LOCAL ).getSink( layout );
+            }
+        });
+        ifPos.add( ifSink2 );
+        ifSink2.add( new PseudoCodeNode( "x[v] = layout.contains('RIGHT') ? min(shift[sink[u]], x[v] - x[u] - 45) : max(shift[sink[u]], x[v] + x[u] + 45);", vars, tree, new CodeLine() {
+            @Override
+            public ControlFlow runForward(Memory m) {
+                String lStr = m.read( "layout", MemoryType.LOCAL );
+                LayoutType layout = LayoutType.fromString( lStr );
+                LayeredGraphNode v = m.read( "v", MemoryType.LOCAL );
+                LayeredGraphNode u = m.read( "u", MemoryType.LOCAL );
+                double old = v.getX( layout );
+                boolean oldDef = !v.isXUndefined( layout );
+                v.setX( lStr.contains( "RIGHT" ) ? Math.max( v.getX( layout ), u.getX( layout ) + 45 ) : Math.min( v.getX( layout ), u.getX( layout ) - 45 ), true, layout );
+                actions.push( (Memory mem) -> {
+                    v.setX( old, oldDef, layout );
+                });
+                return new ControlFlow( ControlFlow.STEP_OVER );
+            }
+        }));
+        whilewv.add( new PseudoCodeNode( "w = align[w];", vars, tree, new SetVariable<LayeredGraphNode>( "w" ) {
+            @Override
+            protected LayeredGraphNode value(ReadOnlyMemory m) {
+                return m.<LayeredGraphNode>read( "w", MemoryType.LOCAL ).getAlign( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) );
+            }
+        }));
+        return root;
+    }
+
+}

+ 7 - 6
src/lib/TextLayoutHelper.java

@@ -24,8 +24,8 @@ public class TextLayoutHelper {
         return s;
     }
     
-    private static String[] keywords = { "for", "do", "to", "then", "else", "if", "foreach", "while", "or", "and", "call", "function" };
-    private static String[] delimiter = { "\\+", "\\-", "\\[", "\\]", "\\|", " ", "^", "$", "\\=", "\\,", "\\(", "\\;", "\\." };
+    private static String[] keywords = { "for", "do", "to", "then", "else", "if", "foreach", "while", "or", "and", "call", "function", "false", "true", "undefined" };
+    private static String[] delimiter = { "\\+", "\\-", "\\[", "\\]", "\\|", " ", "^", "$", "\\=", "\\,", "\\(", "\\;", "\\.", "\\)" };
     
     private static String getDelimiterRegex()
     {
@@ -38,17 +38,18 @@ public class TextLayoutHelper {
         return reg;
     }
     
-    public static String setupPseudoCodeStage( String s )
+    public static String setupPseudoCodeComment( String s )
     {
         return "<html><font color=#FDD017>"+s+"</font></html>";
     }
     
     public static String setupPseudoCode( String s, String[] vars )
     {
-        System.out.print( s + " -> " );
+        if( s.startsWith( "--" ) )
+            return setupPseudoCodeComment( s );
         String delimiter = getDelimiterRegex();
         String ret = "<html>";
-        String current = s.replaceAll( "&", "&amp" ).replaceAll( "<", "&lt").replaceAll( ">", "&gt");
+        String current = s.replaceAll( "&", "&amp" ).replaceAll( "<", " &lt ").replaceAll( ">", " &gt ");
         for( String k : keywords )
         {
             current = current.replaceAll( delimiter + "(" + k + ")" + delimiter, "$1<font color=orange>$2</font>$3" );
@@ -57,8 +58,8 @@ public class TextLayoutHelper {
         {
             current = current.replaceAll( delimiter + "(" + v + ")" + delimiter, "$1<font color=#3BB9FF>$2</font>$3" );
         }
+        current = current.replaceAll( "\\'(.*?)\\'", "'<font color=#3cb371>$1</font>'" );
         ret += current + "</html>";
-        System.out.println( ret );
         return ret;
     }