/************************************* * * Main.java :: Bryan Chadwick * (One possible) Solution for the Extra Credit, Leaf Covering Problem * * See trees.cd/trees.beh for structures and a bit of other code. * *************************************/ import trees.*; import edu.neu.ccs.demeterf.*; import edu.neu.ccs.demeterf.demfgen.lib.*; import java.io.FileInputStream; /** Main class for Leaf Covering check */ public class Main{ /** Shorter print method...*/ static void p(String s){ System.out.println(s); } /** Main Program... */ public static void main(String[] args) throws Exception{ if(args.length != 1){ p(" usage: java Main "); return; } Problem pr = Problem.parse(new FileInputStream(args[0])); List not = uncovered(pr.ms, pr.ts); p(" Covered? == "+not.isEmpty()); /* Print the uncovered Leafs... */ if(!not.isEmpty()) p(" UnCovered Leafs:\n"+not.toString("\n"," ")); } /** Return the List of leaf Tuples implied by the Trees * 'ts' that are not covered by a Tuple in 'm' */ static List uncovered(final List m, final List ts){ final List leafs = leafTuples(ts); return leafs.filterout(new List.Pred(){ public boolean huh(final Tuple l){ return m.fold(new List.Fold(){ public Boolean fold(Tuple n, Boolean r){ return r || covers(ts,n,l); } }, false); } }); } /** In the given list of Trees, are all the elements of 'a' ancestors * of corresponding elements of 'b'? */ static boolean covers(List ts, Tuple a, Tuple b){ if(ts.isEmpty())return true; return (covers(ts.top(),a.first(),b.first()) && covers(ts.pop(),a.rest(),b.rest())); } /** In the given Tree, is 'a' an ancestor of the Leaf 'b'? */ static boolean covers(Tree t, ident a, ident b){ return leafs(find(t,a)).contains(""+b); } /** Class used to traverse the Tree, and find a matching subtree * * The basic idea is to search the whole tree. If a leaf matches * then we return it. If the subtree exist below a Node, we return * it. Otherwise we check the current Node name, and return the * current Node or None. Everything happens bottom up. */ static class Finder extends ID{ Option combine(Leaf t, ident n, ident f){ return (n.equals(f))?Option.some(t):Option.none(); } Option combine(Node t, ident n, Option ch, ident f){ if(ch.isSome())return ch; return (n.equals(f))?Option.some(t):Option.none(); } Option combine(Empty t){ return Option.none(); } Option combine(Cons t, Some s){ return s; } Option combine(Cons t, None s, Option o){ return o; } } /** Find the subtree that is tagged with the identifier 'f' */ static Tree find(Tree t, ident f){ return new Traversal(new Finder()) .>traverse(t,f).inner(); } /** Find all possible tuple combinations of the leafs from the trees */ static List leafTuples(List ts){ final List> leafs = ts.map(new List.Map>(){ public List map(Tree t){ return leafs(t); } }); return leafs.foldr(new List.Fold, List>(){ public List fold(final List ss, final List tl){ return ss.foldr(new List.Fold>(){ public List fold(final String s, List fl){ return tl.map(new List.Map(){ public Tuple map(Tuple t){ return t.push(s); } }).append(fl); } }, List.create()); } }, List.create(new Tuple(List.create()))); } /** Function Class to grab all the Leaf labels in a Tree */ static class Leafs extends ID{ String combine(ident i){ return ""+i; } List combine(Tree t, String n){ return List.create(n); } List combine(Tree t, String n, List l){ return l; } List combine(Empty e){ return List.create(); } List combine(Cons c, List f, List r){ return f.append(r); } } /** Find all the Leafs of the given Tree */ static List leafs(Tree t){ return new Traversal(new Leafs()).traverse(t); } /** Find all immediate children of the given Tree */ static List children(Tree t){ return Traversal.onestep(new ID(){ List combine(Tree t){ return List.create(); } List combine(Tree t, ident n, List l){ return l; } }).traverse(t); } }