package org.ggp.base.util.gdl.transforms; import java.util.ArrayList; import java.util.List; import org.ggp.base.util.gdl.grammar.Gdl; import org.ggp.base.util.gdl.grammar.GdlConstant; import org.ggp.base.util.gdl.grammar.GdlDistinct; import org.ggp.base.util.gdl.grammar.GdlFunction; import org.ggp.base.util.gdl.grammar.GdlLiteral; import org.ggp.base.util.gdl.grammar.GdlNot; import org.ggp.base.util.gdl.grammar.GdlOr; import org.ggp.base.util.gdl.grammar.GdlPool; import org.ggp.base.util.gdl.grammar.GdlProposition; import org.ggp.base.util.gdl.grammar.GdlRelation; import org.ggp.base.util.gdl.grammar.GdlRule; import org.ggp.base.util.gdl.grammar.GdlVariable; /** * As a GDL transformer, this class takes in a GDL description of a game, * transforms it in some way, and outputs a new GDL descriptions of a game * which is functionally equivalent to the original game. * * DeORer removes OR rules from the GDL. Technically, these rules shouldn't * be in the GDL in the first place, but it's very straightforward to remove * them, so we do that so that we can handle GDL descriptions that use OR. * * @author Ethan Dreyfuss */ public class DeORer { public static List<Gdl> run(List<Gdl> description) { List<Gdl> newDesc = new ArrayList<Gdl>(); for(Gdl gdl : description) { if(gdl instanceof GdlRule) { GdlRule rule = (GdlRule)gdl; List<List<GdlLiteral>> newBodies = deOr(rule.getBody()); for(List<GdlLiteral> body : newBodies) { newDesc.add(GdlPool.getRule(rule.getHead(), body)); } } else newDesc.add(gdl); } return newDesc; } private static List<List<GdlLiteral>> deOr(List<GdlLiteral> rhs) { List<List<GdlLiteral>> wrapped = new ArrayList<List<GdlLiteral>>(); wrapped.add(rhs); return deOr2(wrapped); } private static List<List<GdlLiteral>> deOr2(List<List<GdlLiteral>> rhsList) { List<List<GdlLiteral>> rval = new ArrayList<List<GdlLiteral>>(); boolean expandedSomething = false; for(List<GdlLiteral> rhs : rhsList) { int i=0; if(!expandedSomething) { for(GdlLiteral lit : rhs) { if(!expandedSomething) { List<Gdl> expandedList = expandFirstOr(lit); if(expandedList.size() > 1) { for(Gdl replacement : expandedList) { List<GdlLiteral> newRhs = new ArrayList<GdlLiteral>(rhs); if(!(replacement instanceof GdlLiteral)) throw new RuntimeException("Top level return value is different type of gdl."); GdlLiteral newLit = (GdlLiteral)replacement; newRhs.set(i, newLit); rval.add(newRhs); } expandedSomething = true; break; } } i++; } if(!expandedSomething) //If I didn't find anything to expand rval.add(rhs); } else rval.add(rhs); //If I've already expanded this function call } if(!expandedSomething) return rhsList; else return deOr2(rval); } private static List<Gdl> expandFirstOr(Gdl gdl) { List<Gdl> rval; List<Gdl> expandedChild; if(gdl instanceof GdlDistinct) { //Can safely be ignored, won't contain 'or' rval = new ArrayList<Gdl>(); rval.add(gdl); return rval; } else if(gdl instanceof GdlNot) { GdlNot not = (GdlNot)gdl; expandedChild = expandFirstOr(not.getBody()); rval = new ArrayList<Gdl>(); for(Gdl g : expandedChild) { if(!(g instanceof GdlLiteral)) throw new RuntimeException("Not must have literal child."); GdlLiteral lit = (GdlLiteral)g; rval.add(GdlPool.getNot(lit)); } return rval; } else if(gdl instanceof GdlOr) { GdlOr or = (GdlOr)gdl; rval = new ArrayList<Gdl>(); for(int i=0; i<or.arity(); i++) { rval.add(or.get(i)); } return rval; } else if(gdl instanceof GdlProposition) { //Can safely be ignored, won't contain 'or' rval = new ArrayList<Gdl>(); rval.add(gdl); return rval; } else if(gdl instanceof GdlRelation) { //Can safely be ignored, won't contain 'or' rval = new ArrayList<Gdl>(); rval.add(gdl); return rval; } else if(gdl instanceof GdlRule) { throw new RuntimeException("This should be used to remove 'or's from the body of a rule, and rules can't be nested"); } else if(gdl instanceof GdlConstant) { //Can safely be ignored, won't contain 'or' rval = new ArrayList<Gdl>(); rval.add(gdl); return rval; } else if(gdl instanceof GdlFunction) { //Can safely be ignored, won't contain 'or' rval = new ArrayList<Gdl>(); rval.add(gdl); return rval; } else if(gdl instanceof GdlVariable) { //Can safely be ignored, won't contain 'or' rval = new ArrayList<Gdl>(); rval.add(gdl); return rval; } else { throw new RuntimeException("Uh oh, gdl hierarchy must have been extended without updating this code."); } } }