/*$$ * Copyright (c) 1999, Trustees of the University of Chicago * All rights reserved. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the following * conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the University of Chicago nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *$$*/ import uchicago.src.sim.util.Random; //import cern.jet.random.Normal; //import cern.jet.random.Uniform; /** * The agent for the symbiosis simulation. This agent * * The source is annotated so see that for more info. * */ public class TaggedAgent { double tag; // my identifying tag double tolerance; // how `close' people must be in order for me to donate int skill; // the particular skill I have (type of food I gather) int numFoodTypes; // The number of different sorts of food double[] foodVals; // the amount of each type of food that I have double[] newFoodVals; // the amount of each type of food that I have received // this round (not to be used for donation in this // round) double maxReservoir; // maximum amount I can hold of any food type; double maxTol; // maximum tolerance I can have boolean born; int currentAge; public TaggedAgent(int numFoodTypes, double initialFood, double maxRes, double maxTol, int maxStartAge) { this.numFoodTypes = numFoodTypes; foodVals = new double[numFoodTypes]; newFoodVals = new double[numFoodTypes]; for (int i = 0; i < numFoodTypes; i++) { foodVals[i] = initialFood; newFoodVals[i] = 0; } maxReservoir = maxRes; this.maxTol = maxTol; tag = Random.uniform.nextDouble(); tolerance = Random.uniform.nextDouble() * maxTol; skill = Random.uniform.nextIntFromTo(0, numFoodTypes - 1); currentAge = Random.uniform.nextIntFromTo(0, maxStartAge); born = false; } // Just as the model needs get and set accessor methods in order for // its initial parameters to be displayed and thus subject to modification, // an agent (or any other object) can be probed through similar get and set // methods. // // Probing consists of clicking on an object in the display, causing that // object's current state to be displayed. What is displayed depends on // the various get and set methods implemented by the object. For example, // if an object has a setMetabolism and a getMetabolism method, a Metabolism // field will be displayed providing the current value of the metabolism // variable and allowing the user to change the value by entering a new value // and pressing enter. As of this release only number, String, and boolean // fields can be displayed. Of course a user can use the get and set methods // to turn a Vector, for example, into a String or whatever is appropriate. public boolean isBorn() { return born; } public void setBorn(boolean born) { this.born = born; } public void setTag(double tag) { this.tag = tag; } public void setTolerance(double tolerance) { this.tolerance = tolerance; } public void setSkill(int skill) { this.skill = skill; } public void setFood(int foodType, double val) { foodVals[foodType] = val; } public double getTag() { return tag; } public double getTolerance() { return tolerance; } public int getSkill() { return skill; } public double getFood(int foodType) { return foodVals[foodType]; } public double getFood() { double food = 0; for (int foodType = 0; foodType < numFoodTypes; foodType++) food += foodVals[foodType]; return food; } public int getCurrentAge() { return currentAge; } public void harvestFood(double amount) { foodVals[skill] += amount; if (foodVals[skill] > maxReservoir) foodVals[skill] = maxReservoir; } public void receiveDonation(int foodType, double amount) { newFoodVals[foodType] += amount; } public void donateFood(int foodType, double amount) { foodVals[foodType] -= amount; } public void consumeFood(double amount) { // first incorporate all the food that I received by donation into // my main food store, then consume the food I need for this time step for (int i = 0; i < numFoodTypes; i++) { foodVals[i] += newFoodVals[i]; if (foodVals[i] > maxReservoir) foodVals[i] = maxReservoir; newFoodVals[i] = 0; foodVals[i] -= amount; } } public boolean shouldReproduce(double threshold) { boolean shouldReproduce = true; for (int i = 0; i < numFoodTypes; i++) { if (foodVals[i] <= threshold) shouldReproduce = false; } return shouldReproduce; } public boolean reachedAge(int age) { return currentAge >= age; } public boolean isStarved(double threshold) { for (int i = 0; i < numFoodTypes; i++) { if (foodVals[i] < threshold) return true; } return false; } public boolean enoughFood(int type, double threshold) { return foodVals[type] > threshold; } public double excessFood(int type, double threshold) { double e = foodVals[type] - threshold; if (e > 0) return e; else return 0; } public boolean shouldDonate(double tag) { if (Math.abs(this.tag - tag) < tolerance) return true; else return false; } public void age() { currentAge++; } public void report() { System.out.println("My resources:"); System.out.println("Type\tAmount"); for (int i = 0; i < numFoodTypes; i++) System.out.println(i + "\t" + foodVals[i]); } public TaggedAgent giveBirth(double probMutation, double sdMut, double food, boolean withValMut, boolean withReproductionNoise, double noiseSd, int maxStartAge) { Random.createNormal(0.0, sdMut); Random.createUniform(); TaggedAgent agent = new TaggedAgent(numFoodTypes, food, maxReservoir, maxTol, maxStartAge); consumeFood(food); // food passed to offspring double tolerance = this.tolerance; double tag = this.tag; if (withValMut) { if (Random.uniform.nextDouble() < probMutation) { tolerance += Random.normal.nextDouble(); } if (Random.uniform.nextDouble() < probMutation) { tag += Random.normal.nextDouble(); } } if (withReproductionNoise) { tolerance += noiseSd * Random.normal.nextDouble(); tag += noiseSd * Random.normal.nextDouble(); } agent.setTolerance(bound(tolerance, 0, maxTol)); agent.setTag(bound(tag, 0, 1)); agent.setSkill(skill); agent.setBorn(true); return agent; } private double bound(double val, double min, double max) { if (val > max) return max; if (val < min) return min; return val; } }