/* CVS: $Id: Human.java,v 1.48 2001/03/18 12:26:41 gvijf Exp $ */ package evolution; import java.util.*; import evolution.actions.*; import evolution.resources.*; import evolution.lands.*; import evolution.events.*; /** * Class of humans. */ public class Human implements Evolver { /** * Create a new human. */ public Human(SquareOfLand sq) throws IllegalPlacementException { sq._place(this); setAction(ActionKnowledgeCatalog.getInst().getDefaultActionType()); try { setVisionRange(EvolutionKnowledgeCatalog.getInst().getDefaultVisionRange()); } catch (InvalidVisionRangeException exc) { // can not happen, this would mean there is an error in our config file throw new RuntimeException("Invalid default vision range for a human"); } Evolution.getInst().register(this); EventManager.getInst().signalEvent(new SquareChangedEvt(sq)); } /** * Set the vision range for this human. * @exception InvalidVisionRangeException If the vision range is negative. */ public void setVisionRange(int range) throws InvalidVisionRangeException { if (range < 0) throw new InvalidVisionRangeException("Hey you! I can't see inside myself"); visionRange = range; } /** * Return the vision range for this human. */ public int getVisionRange() { return visionRange; } /** * Let this human perform the given action from now on. * Precondition: the action must be a valid action name. */ public void setAction(String actionName) { // if we stand on unexplored land we may only change // to an allowed action on unexplored land if(ActionKnowledgeCatalog.getInst().mustBeExplored(actionName) && !getSquareOfLand().isExplored()) { SystemMessage.message("Master, " + actionName + " is not allowed here!"); return; } setAction(ActionKnowledgeCatalog.getInst().instantiate(actionName)); EventManager.getInst().signalEvent( new SquareChangedEvt(getSquareOfLand())); } /** * Does this evolver produce energy? */ public boolean producesEnergy() { return false; } /** * How much energy will this evolver produce in this step. */ public double maxEnergyProduction(Map m1, Map m2) { return 0; } /** * The evolution for the human when Evolution ticks time. */ public void evolve(double value) { SquareOfLand oldSq = getSquareOfLand(); energyBufferChanged = false; //System.err.println("Human.evolve(): " + getState()); boolean wasPerforming = isPerforming(); setPerforming(true); try { if(!energyBufferFull()) increaseEnergyBuffer(); // can throw NotEnougResourcesException evolve(getAction()); } catch(NotEnoughResourcesException e) { //System.err.println("NotEnoughResources"); // not enough resources to increase energy buffer if(getAction().isEnergyBufferAction()) { evolve(getAction()); try { increaseEnergyBuffer(); } catch(NotEnoughResourcesException e2) { // do nothing } } else { setPerforming(false); evolve(ActionKnowledgeCatalog.getInst().getDefaultAction()); } } setTimeToLive(getTimeToLive() - 1); if((isPerforming() != wasPerforming) || energyBufferChanged) EventManager.getInst().signalEvent( new SquareChangedEvt(getSquareOfLand())); transformLand(oldSq); } /** * If the current action also transforms land, then do that. */ protected void transformLand(SquareOfLand sq) { Object[] r = ActionKnowledgeCatalog.getInst().transformsLand(sq, getAction().getName()); if(!((Boolean) r[0]).booleanValue()) return; String toLand = (String) r[1]; String detLandResource = (String) r[2]; double value = ((Double) r[3]).doubleValue(); boolean lte = ((Boolean) r[4]).booleanValue(); boolean gte = ((Boolean) r[5]).booleanValue(); try { if( (lte && (sq.getLandResource(detLandResource).getValue() <= value)) || (gte && (sq.getLandResource(detLandResource).getValue() >= value)) || (sq.getLandResource(detLandResource).getValue() == value) ) sq.setLandType(toLand); } catch(NullPointerException e) { } } /** * Evolve by doing the given action. */ protected void evolve(Action action) { //System.err.println("Human.evolve(" + action.getName() + ")"); try { action.perform(this); //System.err.println("ok => normal perform done"); } catch (NotEnoughResourcesException e) { if(action.isEnergyBufferAction()) { try { action.performEnergyBuffer(getSquareOfLand(), this); //hunting en fishing kunnen nooit NotEnoughResourcesException tegen komen //daarvoor hebben we ook de speciale methode performEnergyBuffer gedefinieerd } catch (IllegalLandTypeException ex) { SquareOfLand newsquare = action.findSquare(getSquareOfLand(), getVisionRange()); if(newsquare != getSquareOfLand()) { try { newsquare.place(this); } catch (IllegalPlacementException excep) { //can't happen } try { action.performEnergyBuffer(newsquare, this); } catch (IllegalLandTypeException excep) { //can't happen } } else { setPerforming(false); evolve(ActionKnowledgeCatalog.getInst().getDefaultAction()); } } } else { setPerforming(false); evolve(ActionKnowledgeCatalog.getInst().getDefaultAction()); //try { //ActionKnowledgeCatalog.getInst().getDefaultAction().perform(this); //} catch(Exception ee) {} } } catch (IllegalLandTypeException e) { //System.err.println("IllegalLandType"); findSquare(action); } catch (NotEnoughLandResourcesException e) { //System.err.println("NotEnoughLandResources"); findSquare(action); } } /** * Find some squares to do the given action on. */ protected void findSquare(Action action) { SquareOfLand newsquare = action.findSquare(getSquareOfLand(), getVisionRange()); if(newsquare != getSquareOfLand()) { try { newsquare.place(this); } catch (IllegalPlacementException ex) { //can't happen } try { action.perform(this); } catch (NotEnoughResourcesException ex) { //can't happen //in de methode perform wordt eerst NotEnougResourcesException gegooid //daarna pas IllegalLandTypeException } catch (IllegalLandTypeException ex) { //can't happen } catch (NotEnoughLandResourcesException ex) { //can't happen //deze uitzondering wordt alleen gegooid als de landresources nul zijn //en als onze findsquare methode een andere square teruggeeft, gaan //daarvan de resources nooit nul zijn } } else { setPerforming(false); evolve(ActionKnowledgeCatalog.getInst().getDefaultAction()); } } /** * Set the action for this human. */ protected void setAction(Action a) { action = a; } /** * Get the action for this human. */ public Action getAction() { return action; } /** * Returns the priority of this evolver. */ public double getPriority() { // FIXME: quick hack to give dying humans precedence: multiply // their priority by 2 double mul = 1; if(!energyBufferFull()) mul = 2; return mul * ActionKnowledgeCatalog.getInst().getPriority(getAction()); } /** * Get the state of this human. * Returns null if the human has no associated action. * Returns the action name, if he's performing the action and * "Not" + the action name if he's unable to perform the action. */ public String getState() { if(getAction() == null) return null; if(!isPerforming()) return "Not" + getAction().getName(); return getAction().getName(); } /** * Get the energy buffer state. * Returns "E" + the percentage the buffer is filled. * Possible return values: E0 .. E90. */ public String getEnergyBufferState() { if(energyBufferFull()) return null; return "E" + ((int) (getEnergyBuffer() / 10) * 10); } /** * Let this human die. */ public void die() { Evolution.getInst().deregister(this); SquareOfLand sq = getSquareOfLand(); sq._setHuman(null); // do NOT set the square to null -> event could be fired //setSquareOfLand(null); EventManager.getInst().signalEvent(new SquareChangedEvt(sq)); EventManager.getInst().signalEvent(new HumanDiedEvt(this)); } /** * Set the time to live. */ public void setTimeToLive(long time) { timeToLive = time; if(timeToLive <= 0) die(); } /** * Get the time to live. */ public long getTimeToLive() { return timeToLive; } /** * Get the square of land this human stands on. */ public SquareOfLand getSquareOfLand() { return square; } /** * Set the square of land this human stands on. * This is not supposed to be used, except by SquareOfLand. */ public void setSquareOfLand(SquareOfLand square) { this.square = square; } /** * Create an infolist with information about this human. */ public InfoList getInfo() { InfoList result = new InfoList(); result.add("Time to live", InfoList.VALUE, getTimeToLive()); result.add("Energy buffer", InfoList.PERCENTAGE, getEnergyBuffer()); result.add("Vision range", InfoList.VALUE, getVisionRange()); if(getAction() != null) result.add("Action", InfoList.STRING, getAction().getName()); return result; } /** * Returns the energybuffer of this human */ public double getEnergyBuffer() { return energyBuffer; } /** * Set the energybuffer of this human * @exception EmptyEnergyBufferException If the energybuffer of this human * is empty. */ protected void setEnergyBuffer(double value) throws EmptyEnergyBufferException { if(value > maxEnergyBuffer) value = maxEnergyBuffer; if(value < minEnergyBuffer) { energyBuffer = minEnergyBuffer; energyBufferChanged = true; throw new EmptyEnergyBufferException(); } if(energyBuffer != value) energyBufferChanged = true; energyBuffer = value; } /** * Checks whether the energybuffer of this human is full (100%) */ public boolean energyBufferFull() { return getEnergyBuffer() >= maxEnergyBuffer; } /** * Checks whether the energybuffer of this human is empty */ public boolean energyBufferEmpty() { return getEnergyBuffer() <= minEnergyBuffer; } /** * Increases the energybuffer of this human. */ protected void increaseEnergyBuffer() throws NotEnoughResourcesException { //System.err.println("EnergyBuffer = " + getEnergyBuffer()); try { //System.err.println("Trying to fill energy buffer"); double food = World.getInst().getResource("Food").getValue(); double foodneeded = (maxEnergyBuffer - getEnergyBuffer())/10; World.getInst().getResource("Food").modValue(-foodneeded); // throws NotEnoughResourcesException setEnergyBuffer(getEnergyBuffer() + food*10); } catch(NoSuchResourceException e) { } catch(EmptyEnergyBufferException e) { // can't happen } } /** * Decreases the energybuffer of this human with the given value. */ public void decreaseEnergyBuffer(double value) throws EmptyEnergyBufferException{ setEnergyBuffer(getEnergyBuffer() - value); } /** * Mark the human as capable or incapable of performing its assigned * action. */ protected void setPerforming(boolean performing) { this.performing = performing; } /** * Is the human capable of performing its assigned task? */ public boolean isPerforming() { return performing; } /** * The action this human is currently assigned. * @supplierCardinality 1 */ private Action action; /** * Is the human capable of performing its assigned task? */ private boolean performing = true; /** * Did we change the energy buffer during evolve? * Used to fire a SquareChangedEvt so the energy buffer will * be drawn correct. */ protected boolean energyBufferChanged = false; /** * The vision range of this human. */ private int visionRange; /** * The time to live of this human. */ private long timeToLive = 80; /** * The square this human is standing on. */ private SquareOfLand square; /** * The energy buffer of this human. */ private double energyBuffer = maxEnergyBuffer; /** * Maximum energy buffer value (100%). */ protected static final int maxEnergyBuffer = 100; /** * Minimum energy buffer value (0%). */ protected static final int minEnergyBuffer = 0; }