/* CVS: $Id: Evolution.java,v 1.33 2001/03/19 10:29:31 gvijf Exp $ */ package evolution; import java.util.*; import evolution.events.*; import evolution.resources.*; /** * Represent evolution (time). * @stereotype singleton */ public class Evolution { /** * The clock as a seperate thread. */ class ClockThread extends Thread { public void run() { while (true) { try { sleep((long) (1000.0 * factor)); } catch (InterruptedException e) { } if(isRunning()) { //System.err.println(); tick(); } } } } /** * Initialize the instance of this singleton. */ public static void initialize() { instance = new Evolution(); } /** * Get the singleton instance. * Precondition: Evolution.initialize() must have been called. */ public static Evolution getInst() { return instance; } /** * Construct an Evolution object. * The new object will be in pause mode. */ protected Evolution() { clock = new ClockThread(); clock.start(); pause(); } /** * Pause the evolution. */ public void pause() { running = false; } /** * Resume the evolution. */ public void resume() { running = true; } /** * Register an Evolver. * Every time the clock ticks evolve() will be called on the Evolver. */ public synchronized void register(Evolver e) { if(e.producesEnergy()) energyProducers.add(e); else energyConsumers.add(e); } /** * Deregister an Evolver. */ public synchronized void deregister(Evolver e) { energyProducers.remove(e); energyConsumers.remove(e); } /** * Is evolution running? */ public boolean isRunning() { return running; } /** * Get the time factor. */ public double getTimeFactor() { return factor; } /** * Get the list of evolvers. */ public List getEvolverList() { energyProducers.addAll(energyConsumers); return energyProducers; } /** * Set the time factor. */ public void setTimeFactor(double factor) { this.factor = factor; } /** * Calculate the difference of two (String, Double) maps. * Returns a (String, Double) Map. */ protected Map difference(Map m1, Map m2) { Map result = new HashMap(); Iterator it = m1.keySet().iterator(); while(it.hasNext()) { String name = (String) it.next(); Double value = new Double(((Double) m1.get(name)).doubleValue() - ((Double) m2.get(name)).doubleValue()); result.put(name, value); } return result; } /** * This method is called on regular basis when running. */ protected synchronized void tick() { ResourceKnowledgeCatalog rKc = ResourceKnowledgeCatalog.getInst(); // step 0: // sort the producers and consumers according to their priority List energyP = new ArrayList(energyProducers); List energyC = new ArrayList(energyConsumers); Collections.sort(energyP, new PriorityComparator()); Collections.sort(energyC, new PriorityComparator()); // step 1: // reset all temporary resources rKc.resetTemporaries(); try { rKc.getResource("Energy").setValue(0); } catch(Exception e) { } // step 2: // create 2 maps, // * one with the current resource allocation: leftOvers // * one with the maximum resource production: maxProduction // these maps will be initialized with the current values // of the world resources Map leftOvers = rKc.getResourcesStringDoubleMap(); Map maxProduction = rKc.getResourcesStringDoubleMap(); //System.err.println("\ncurrent = " + leftOvers + " " + maxProduction); // step 3: // let the producers dummy produce the maximum possible and // so calculate the maximum energy production //System.err.println("We have " + energyP.size() + " producers"); Iterator producers = energyP.iterator(); while(producers.hasNext()) { Evolver e = (Evolver) producers.next(); e.maxEnergyProduction(maxProduction, leftOvers); } //System.err.println("maxProduction = " + leftOvers + " " + maxProduction); double maxEnergy = ((Double) maxProduction.get("Energy")).doubleValue(); //System.err.println("Maximum energy production = " + maxEnergy); // step 3b: // calculate the used resoruces for the producers // copy the leftOvers to world Map usedResources = difference(maxProduction, leftOvers); //System.err.println("Producers used to max = " + usedResources); //System.err.println("Setting world to = " + leftOvers); rKc.setResources(leftOvers); // step 4: // let the consumers consume (for 100%) Iterator consumers = energyC.iterator(); while(consumers.hasNext()) { Evolver e = (Evolver) consumers.next(); e.evolve(1); } //System.err.println("Consumers left = " + rKc.getResourcesStringDoubleMap()); // step 5: // see how much energy was needed double usedEnergy = maxEnergy - rKc.getResource("Energy").getValue(); //System.err.println("Energy used = " + usedEnergy); double productionPercentage; if((maxEnergy == 0) || (usedEnergy == 0)) productionPercentage = 0; else productionPercentage = 1 - (maxEnergy - usedEnergy) / maxEnergy; //System.err.println("Production percentage = " + productionPercentage); // step 6: // adjust the world resources so the producers can now evolve rKc.resetTemporaries(); try { rKc.getResource("Energy").setValue(0); } catch(Exception e) { } //rKc.addResources(usedResources, productionPercentage); //System.err.println("Added the needed for the producers = " + rKc.getResourcesStringDoubleMap()); // step 7: // let the producers evolve for productionPercentage percentage producers = energyP.iterator(); while(producers.hasNext()) { Evolver e = (Evolver) producers.next(); e.evolve(productionPercentage); } // step 8: // set the resources // the temporary resources have to be set, to reflect what // has been produced rKc.setTemporaries(maxProduction, productionPercentage); try { rKc.getResource("Max Energy").setValue(maxEnergy); } catch(Exception e) { } //System.err.println("Result = " + rKc.getResourcesStringDoubleMap()); EventManager.getInst().signalEvent(new ClockTickEvt()); } /** * For debugging. */ class LivingBeingTester implements Evolver { public LivingBeingTester(String name, int ttl) { this.name = name; this.ttl = ttl; Evolution.getInst().register(this); } public void evolve(double value) { System.out.println(name + ": " + (--ttl)); if(ttl <= 0) { Evolution.getInst().deregister(this); System.out.println(name + " is dead"); } } public double adjust(Map maximumProduction, Map leftOvers) { return 0; } public boolean producesEnergy() { return false; } public double maxEnergyProduction(Map m1, Map m2) { return 0; } public double getPriority() { return 0; } private String name; private int ttl; } /** * For debugging. */ protected void test(int ttl) { for(int i = 0; i < 5; i++) { new LivingBeingTester("Being" + i + "(" + ttl + ")", ttl); } } /** * For debugging. */ public static void main(String args[]) throws InterruptedException { Evolution.initialize(); Evolution.getInst().test(2); Evolution.getInst().test(4); Evolution.getInst().test(6); Evolution.getInst().test(8); Evolution.getInst().resume(); System.out.println("Started"); Thread.currentThread().sleep(8000); System.out.println("Stopped"); System.exit(0); } /** * Factor influences the speed of evolution. * Increasing the value of this factor, decreases the speed of the * evolution of the game */ private double factor = 0.8; /** * A list of evolvers that produce energy. */ private List energyProducers = new ArrayList(); /** * A list of evolvers that can't produce energy. */ private List energyConsumers = new ArrayList(); /** * The clock thread. */ private ClockThread clock; /** * Is the clock running? */ private boolean running = false; /** * The singleton instance. */ private static Evolution instance = null; }