package dk.itu.mario.level.grammar; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import dk.itu.mario.level.LevelComponent; public class LevelGrammarFactory { public static LevelGrammar createGrammar(File grammarFile) throws FileNotFoundException, IOException { FileInputStream fis = new FileInputStream(grammarFile); LevelGrammar levelGrammar = new LevelGrammar(); try { InputStreamReader reader = new InputStreamReader(fis); BufferedReader buf = new BufferedReader(reader); String line; while ((line = buf.readLine()) != null) { line = line.trim(); // trim off newline/whitespace if (line.length() == 0 || line.startsWith("#")) { continue; } //System.out.println("Read: " + line); //split on whitespace String[] fields; if (line.startsWith("VAR")) { fields = line.split("\\s"); if ("=".equals(fields[2]) && fields.length == 4) { levelGrammar.addVariable(new Variable(fields[1],LevelComponent.TYPE.valueOf(fields[3]))); } else { throw new RuntimeException("Invalid VAR syntax: " + line); } } else if (line.startsWith("RULE")) { fields = line.split("->"); String ruleName = fields[0].split("\\s")[1]; //System.out.println("Rule name: " + ruleName); Variable lhs = levelGrammar.getVariable(ruleName); if (lhs == null) { throw new RuntimeException("LHS variable not found: " + ruleName); } Clause rhs = getClause(fields[1].trim(),levelGrammar); levelGrammar.addProductionRule(new ProductionRule(lhs,rhs)); } else if (line.startsWith("START")) { fields = line.split("\\s"); if ("=".equals(fields[1]) && fields.length == 3) { levelGrammar.setStart(fields[2]); } else { throw new RuntimeException("Invalid START syntax: " + line); } } else { throw new RuntimeException("Unable to parse grammar file " + grammarFile.getName() + " due to invalid line: " + line); } } return levelGrammar; } finally { fis.close(); } } private static Clause getClause(String clause, LevelGrammar grammar) { if (!clause.contains("|") && !clause.contains("+")) { return grammar.getVariable(clause); } int lBraceIndex = clause.indexOf("{"); boolean isOrClause = false; int rBraceIndex = 0; double[] chances = {}; if (lBraceIndex != -1) { isOrClause = true; rBraceIndex = clause.indexOf("}"); //System.out.println("Read OR-clause probabilities from: " + lBraceIndex + " to " + rBraceIndex); String[] doubleFields = clause.substring(lBraceIndex+1,rBraceIndex).split(","); chances = new double[doubleFields.length]; for (int i = 0; i < doubleFields.length; i++) { chances[i] = Double.valueOf(doubleFields[i]); } } String remainder = clause.substring(rBraceIndex); List rhsClauseStrings = new ArrayList(); if (remainder.contains("(")) { int nextLeftIndex = -1; do { nextLeftIndex = remainder.indexOf("(", nextLeftIndex+1); if (nextLeftIndex != -1) { int nextRightIndex = remainder.indexOf(")", nextLeftIndex+1); if (nextRightIndex == -1) { throw new RuntimeException("Unmatched left '(' in clause"); } rhsClauseStrings.add(remainder.substring(nextLeftIndex+1,nextRightIndex)); nextLeftIndex = nextRightIndex; } } while (nextLeftIndex != -1); } else { isOrClause = remainder.contains("|"); if (isOrClause) { for (String subclause : remainder.split("\\|")) { rhsClauseStrings.add(subclause.trim()); } } else { for (String subclause : remainder.split("\\+")) { rhsClauseStrings.add(subclause.trim()); } } } List rhsClauses = new ArrayList(); for (String subclause : rhsClauseStrings) { rhsClauses.add(getClause(subclause,grammar)); } if (isOrClause) { return new OrClause(chances, rhsClauses); } else { return new AndClause(rhsClauses); } } public static LevelGrammar createGrammar() { LevelGrammar grammar = new LevelGrammar(); Variable v_START = new Variable("S", LevelComponent.TYPE.LEVEL); Variable v_LAND_SEGMENT = new Variable("HALF_LVL", LevelComponent.TYPE.LEVEL_SEGMENT); Variable v_LO_HI = new Variable("LO_HI", LevelComponent.TYPE.LO_HI); Variable v_HI_LO = new Variable("HI_LO", LevelComponent.TYPE.HI_LO); Variable v_LO_PATH = new Variable("LO_PATH", LevelComponent.TYPE.LO_PATH); Variable v_HI_PATH = new Variable("HI_PATH", LevelComponent.TYPE.HI_PATH); Variable v_lo_path = new Variable("lo_path", LevelComponent.TYPE.FLAT_LO); Variable v_hi_path = new Variable("hi_path", LevelComponent.TYPE.FLAT_HI); grammar.addVariable(v_START); grammar.addVariable(v_LAND_SEGMENT); grammar.addVariable(v_LO_HI); grammar.addVariable(v_HI_LO); grammar.addVariable(v_LO_PATH); grammar.addVariable(v_HI_PATH); grammar.addProductionRule(new ProductionRule(v_START,v_LAND_SEGMENT,v_LAND_SEGMENT)); grammar.addProductionRule( new ProductionRule(v_LAND_SEGMENT, new OrClause( new double[] {0.25,0.65,0.10}, new AndClause(v_LO_HI,v_HI_LO), v_LO_PATH, new AndClause(v_LAND_SEGMENT,v_LAND_SEGMENT) ) ) ); grammar.addProductionRule( new ProductionRule(v_LO_HI, v_LO_PATH, v_HI_PATH) ); grammar.addProductionRule( new ProductionRule(v_HI_LO, v_HI_PATH, v_LO_PATH) ); grammar.addProductionRule( new ProductionRule(v_HI_PATH, new OrClause( new double[] {0.25,0.75}, new AndClause(v_HI_PATH,v_HI_PATH), v_hi_path ) ) ); grammar.addProductionRule( new ProductionRule(v_LO_PATH, new OrClause( new double[] {0.25,0.75}, new AndClause(v_LO_PATH,v_LO_PATH), v_lo_path ) ) ); grammar.setStart(v_START); return grammar; } }