/* CVS: $Id: ConstructionKnowledgeCatalog.java,v 1.30 2001/03/19 10:29:31 gvijf Exp $ */ package evolution.constructions; import java.io.*; import java.util.*; import java.net.URL; import evolution.*; import evolution.lands.*; /** * KnowledgeCatalog for constructions. */ public class ConstructionKnowledgeCatalog extends KnowledgeCatalog { /** * Create a new KnowledgeCatalog from the given file. */ protected ConstructionKnowledgeCatalog(String fileName) throws IOException, FileNotFoundException { super(fileName); parseConstructions(getProperty("Constructions")); } /** * Return the instance of this singleton. */ public static ConstructionKnowledgeCatalog getInst() { if(instance == null) throw new RuntimeException("ConstructionKnowledgeCatalog was not initialized"); return instance; } /** * Initialize this singleton from the given file. */ public static void initialize(String fileName) throws FileNotFoundException, IOException { instance = new ConstructionKnowledgeCatalog(fileName); } /** * Does this construction exist in the current game? */ public boolean constructionExists(String constructionName) { return getConstructionTypes().contains(constructionName); } /** * Get the priority of this construction. */ public double getPriority(Construction construction) { return (new Double(getProperty(construction.getName() + ".priority", "1"))).doubleValue(); } /** * Checks if the construction can stand on the given square of land. * @param construction The name of the construction. * @param sq The square of land to test. * @param humans A List of Humans's who will construct the construction. * @return true if the construction can stand on this square, false * otherwise. If there is a human on the square that is not in the given * list, then the construction can not stand on this square. */ protected boolean canStandOn(String construction, SquareOfLand sq, List humans) { // if there's already a construction, we don't allow another one if(sq.getConstruction() != null) return false; if(!sq.isExplored()) return false; // if there is a human on the piece not in the list to work // on constructing this construction, we don't allow it to be build here if((sq.getHuman() != null) && !humans.contains(sq.getHuman())) return false; return canStandOnLandType(construction, sq.getLandType()); } /** * Checks if the construction can stand on the given squares of land. * @param construction The name of the construction. * @param squares A List of SquareOfLand's were the construction will * be build. * @param humans A List of Humans's who will construct the construction. * @return true if the construction can stand on the squares, false * otherwise. If there is a human on the squares that is not in the given * list, then the construction can not stand on these squares. */ protected boolean canStandOn(String construction, List squares, List humans) { Iterator it = squares.iterator(); while(it.hasNext()) { SquareOfLand sq = (SquareOfLand) it.next(); if(!canStandOn(construction, sq, humans)) return false; } return true; } /** * Checks if the construction can stand on the given landtype. */ public boolean canStandOnLandType(String construction, String landType) { List l = split(" ", getProperty(construction + ".constructing.lands", "")); return l.contains(landType); } /** * Get the speed at which this construction will be build. */ public double getConstructionSpeed(String constructionName) { return Double.parseDouble(getProperty(constructionName + ".constructing.speed", "4")); } /** * The shapes the given construction can be build in. * Returns a List of Strings according to the shape spec. * e.g. {"1x1:1", "2x2:1101", "3x2:111111101"} */ public List getConstructionShapes(String constructionName) { return split(" ", getProperty(constructionName + ".constructing.shapes", "1x1:1")); } /** * Return the squares used for this shape. */ public int countSquares(String shape) { int result = 0; try { List l = split(":", shape); String s = (String) l.get(1); for(int i = 0; i < s.length(); i++) if(s.charAt(i) == '1') result++; } catch(IndexOutOfBoundsException e) { throw new IllegalArgumentException("Malformed shapestring: " + shape); } return result; } /** * Get the squares marked in the shape string with the given square * as upper left corner. * Returns a list of SquareOfLands. * @exception IndexOutOfBoundsException If the given shapes extends out * of the game board. * @exception IllegalArgumentException If the shape string is malformed. */ protected List getSquares(SquareOfLand sq, String shape) { boolean parsingShape = true; List result = new ArrayList(); try { List l = split(":", shape); List l1 = split("x", (String) l.get(0)); String s = (String) l.get(1); int w = Integer.parseInt((String) l1.get(0)); int h = Integer.parseInt((String) l1.get(1)); parsingShape = false; for(int y = 0; y < h; y++) { for(int x = 0; x < w; x++) { if(s.charAt(y * w + x) == '1') { result.add(World.getInst().getGameBoard().getSquare(sq.getX() + x, sq.getY() + y)); } } } } catch(IndexOutOfBoundsException e) { if(parsingShape) throw new IllegalArgumentException("Malformed shapestring: " + shape); throw e; } return result; } /** * Build a construction. * @param constructionName The name of the construction type to build. * @param shape The shape of the construction to build, * e.g. "1x1:1", "2x2:1101", "3x2:111111101", ... * @param humans The humans who will build the construction. * @param sq The square of land in the top left of the shape, to position * the construction. * @exception IllegalPlacementException If it is impossible to build * the construction on the indicated place or you have assigned more * humans to the job than there are build squares for this construction. */ public void build(String constructionName, String shape, List humans, SquareOfLand sq) throws IllegalPlacementException { List squares; try { squares = getSquares(sq, shape); } catch(IndexOutOfBoundsException e) { throw new IllegalPlacementException("Sorry dude, you've got to build the " + constructionName + " completeley on the board."); } if(!canStandOn(constructionName, squares, humans)) throw new IllegalPlacementException("Sorry dude, you've got to build the " + constructionName + " somewhere else."); if(squares.size() < humans.size()) throw new IllegalPlacementException("What did I say! You can't build on less squares than you use humans"); instantiate(constructionName, squares); Iterator it1 = humans.iterator(); Iterator it2 = squares.iterator(); while(it1.hasNext()) { Human human = (Human) it1.next(); SquareOfLand square = (SquareOfLand) it2.next(); try { //System.err.println("Current human = " + square.getHuman() + ", setting there " + human); square.place(human); human.setAction("Constructing"); } catch(IllegalPlacementException e) { throw new RuntimeException("This was not supposed to happen Tim!"); } } } /** * Instantiate the given construction on the given squares. */ protected void instantiate(String constructionName, List squares) { Construction construction; try { // first try to dynamically load Class c = dlClassForName("constructions", constructionName); try { construction = (Construction) c.getConstructor(new Class[] {List.class}). newInstance(new Object[] {squares}); } catch(Exception e1) { throw new RuntimeException(constructionName + " does not have a proper constructor."); } } catch(ClassNotFoundException e) { construction = new SimpleConstruction(constructionName, squares); } } /** * The resources produced when constructing this construction. * @return A Map of (String, Double). */ public Map producesResourcesConstructing(String construction) { return makeStringDoubleMap(construction + ".constructing.producesResources", ""); } /** * The resources used for constructing this construction. * @return A Map of (String, Double). */ public Map usesResourcesConstructing(String construction) { return makeStringDoubleMap(construction + ".constructing.usesResources", ""); } /** * The landresources produced when constructing this construction. * @return A Map of (String, Double). */ public Map producesLandResourcesConstructing(String construction) { return makeStringDoubleMap(construction + ".constructing.producesLandResources", ""); } /** * The landresources used for constructing this construction. * @return A Map of (String, Double). */ public Map usesLandResourcesConstructing(String construction) { return makeStringDoubleMap(construction + ".constructing.usesLandResources", ""); } /** * Can this construction be build on the specified landtype? */ public boolean canBeBuildOn(String constructionName, String landType) { List l = split(" ", getProperty(constructionName + ".constructing.lands", "")); return l.contains(landType); } /** * A list with the names of the resources produced by a given construction. */ public List producesResourcesNames(String constructionName) { // Dit werkt return Arrays.asList((producesResources(constructionName).keySet()).toArray()); } /** * A map with as keys the resource and as value the amount the construction produces. */ public Map producesResources(String constructionName) { // Dit werkt return makeStringDoubleMap(constructionName + ".producesResources", ""); } /** * A list with the names of the resources used by a given construction. */ public List usesResourcesNames(String constructionName) { // Dit werkt return Arrays.asList((usesResources(constructionName).keySet()).toArray()); } /** * A map with as keys the resource and as value the amount the construction uses. */ public Map usesResources(String constructionName) { return makeStringDoubleMap(constructionName + ".usesResources", ""); } /** * A map with as keys the landresource and as value the amount the * construction uses. */ public Map usesLandResources(String constructionName) { return makeStringDoubleMap(constructionName + ".usesLandResources", ""); } /** * Is the given resource in the produce energy chain? */ public boolean isEnergyResource(String resourceName) { // hardcoded, could be done generic, but too much work... // other things first... return resourceName.equals("Energy") || resourceName.equals("Coals"); } /** * Parse the constructions-string. */ protected void parseConstructions(String cstring) { constructionTypes = split(" ", cstring); SystemMessage.message(constructionTypes.size() + " constructiontypes loaded"); } /** * Return the different types of constructions. */ public List getConstructionTypes() { return constructionTypes; } /** * Return infolist for constructions. */ public InfoList getConstructionsInfo() { InfoList list = new InfoList(); Iterator it = getConstructionTypes().iterator(); while(it.hasNext()) { String name = (String) it.next(); list.add(name, InfoList.STRING, name); } return list; } /** * The different types of constructions. */ private List constructionTypes; /** * Instance of the singleton. */ protected static ConstructionKnowledgeCatalog instance = null; }