/** ** Person.java ** ** Copyright 2011 by Sarah Wise, Mark Coletti, Andrew Crooks, and ** George Mason University. ** ** Licensed under the Academic Free License version 3.0 ** ** See the file "LICENSE" for more information ** ** $Id$ **/ package sim.app.geo.schellingpolygon; import java.util.ArrayList; import sim.engine.SimState; import sim.engine.Steppable; public class Person implements Steppable { String color; double preference; Polygon region; double personalThreshold = .5; int numMoves = 0; /** * Constructor function * @param c */ public Person(String c) { color = c; } /** * Moves the Person to the given Polygon * @param p - the Polygon to which the Person should move */ public void updateLocation(Polygon p) { // leave old tile, if previously was on a tile if (region != null) { region.residents.remove(this); region.soc = "UNOCCUPIED"; } // go to new tile region = p; region.residents.add(this); region.soc = color; numMoves++; // increment the number of times moved } /** * * @param poly the proposed location * @return whether the given Polygon is an acceptable location for the Person, * based on the Person's personalThreshold */ boolean acceptable(Polygon poly) { // decide if Person is unhappy with surroundings double unlike = 0, total = 0.; for (Polygon p : poly.neighbors) { if (p.soc.equals("UNOCCUPIED")) // empty spaces don't count { continue; } if (!p.soc.equals(color)) // is this neighbor an unlike neighbor? { unlike++; } total++; // total count of neighbors } double percentUnlike = unlike / Math.max(total, 1); // don't divide by 0! // if unhappy, return false if (percentUnlike >= personalThreshold) { return false; } else // if happy, return true { return true; } } /** * @param ps the list of Polygons open to the Person * @return the closest available Polygon that meets the Person's needs, if such * a Polygon exists. If no such Polygon exists, returns null. */ Polygon bestMove(ArrayList<Polygon> ps) { Polygon result = null; double bestDist = Double.MAX_VALUE; // go through all polygons and determine the best move to make for (Polygon p : ps) { if (!p.soc.equals("UNOCCUPIED")) { continue; // not available } else if (p.geometry.getCentroid().distance( region.geometry.getCentroid()) >= bestDist) // distance between centroids //else if( p.geometry.distance( region.geometry ) >= bestDist) // distance between region borders { continue; // we already have a better option } else if (!acceptable(p)) { continue; // not an acceptable neighborhood } else { // otherwise it's an acceptable region and the closest region yet result = p; bestDist = p.geometry.distance(region.geometry); } } return result; } /** * Determines whether the Person's current location is acceptable. If not, attempts * to move the Person to a better location. */ @Override public void step(SimState state) { if (!acceptable(region)) { // the current location is unacceptable // System.out.println("unacceptable!"); // try to find and move to a better location Polygon potentialNew = bestMove(((PolySchelling) state).polys); if (potentialNew != null) // a better location was found { updateLocation(potentialNew); } else // no better location was found. Stay in place. { // System.out.println("...but immobile"); } } } }