/******************************************************************************* * Copyright (c) 2016 Alex Shapiro - github.com/shpralex * This program and the accompanying materials * are made available under the terms of the The MIT License (MIT) * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. *******************************************************************************/ package com.sproutlife.model.echosystem; import java.awt.Dimension; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Random; import com.sproutlife.model.GameClock; import com.sproutlife.model.seed.Seed; /** * The Echosystem keeps track of all our organisms. It manages the Board, * which knows which cells are neighbors. It has a reference to a clock which * lets us know how old rganisms are and when they were born. * * @author Alex Shapiro */ public class Echosystem { HashSet<Organism> organisms; HashSet<Organism> retiredOrganisms; Board board; int defaultOrgLifespan; int retirementTimeSpan; GameClock clock; public int typeCount = 0; public Echosystem(GameClock clock) { this.organisms = new HashSet<Organism>(); this.retiredOrganisms = new HashSet<Organism>(); this.board = new Board(); this.clock = clock; this.defaultOrgLifespan = 15; this.retirementTimeSpan = 1000; } public Collection<Organism> getOrganisms() { return organisms; } public Collection<Organism> getRetiredOrganisms() { return retiredOrganisms; } public Board getBoard() { return board; } public GameClock getClock() { return clock; } public int getTime() { return clock.getTime(); } /* * Convenience method. Maybe slow, and shouldn't be used often. Should be * replaced by custom iterator. * * @Return all the cells */ public ArrayList<Cell> getCells() { ArrayList<Cell> cellList = new ArrayList<Cell>(); for (Organism o : getOrganisms()) { cellList.addAll(o.getCells()); } return cellList; } public void resetCells() { ArrayList<Cell> cells = new ArrayList<Cell>(getCells()); for (Cell c : cells) { removeCell(c); } this.setDefaultOrgLifespan(15); } public boolean removeCell(Cell c) { return removeCell(c, true); } private boolean removeCell(Cell c, boolean updateBoard) { if (c == null) { return false; } boolean result = c.getOrganism().removeCell(c); if (updateBoard) { // We don't want to update the board if we just reset it. getBoard().removeCell(c); } return result; } public Cell addCell(int x, int y, Organism org) { // if (x==getBoard().getWidth()/2 && !liftBarrier) { // return null; // } Cell c = org.addCell(x, y); if (c != null) { getBoard().setCell(c); } return c; } /* * Add a cell that's been created but not yet added */ public void addCell(Cell c) { c.getOrganism().addCell(c); getBoard().setCell(c); } /* * Create a cell but don't add it */ public Cell createCell(int x, int y, ArrayList<Cell> parents) { return parents.get(0).getOrganism().createCell(x, y, parents); } public void removeCell(int x, int y) { Cell c = getBoard().getCell(x, y); if (c != null) { removeCell(c); } } public void setDefaultOrgLifespan(int orgLifespan) { this.defaultOrgLifespan = orgLifespan; } public int getDefaultOrgLifespan() { return defaultOrgLifespan; } public int getRetirementTimeSpan() { return retirementTimeSpan; } public void setRetirementTimeSpan(int retirementTimeSpan) { this.retirementTimeSpan = retirementTimeSpan; } public Organism createOrganism(int x, int y, Organism parent, Seed seed) { typeCount++; // Organism newOrg = new Organism(typeCount, getClock(), x, y, parent, seed); if (parent == null) { newOrg.setLifespan(getDefaultOrgLifespan());// +(new // Random()).nextInt(3)); } organisms.add(newOrg); return newOrg; } public void removeOrganism(Organism o) { for (Cell c : o.getCells()) { getBoard().removeCell(c); } organisms.remove(o); } /* * A retired organims is really dead, maybe the function should be renamed. * Retired organisms hang around in a separate list for statistics purposes. */ public void retireOrganism(Organism o) { for (Cell c : o.getCells()) { getBoard().removeCell(c); } o.setAlive(false); o.setTimeOfDeath(getTime()); organisms.remove(o); retiredOrganisms.add(o); } public void removeRetired(Organism o) { retiredOrganisms.remove(o); } public void updateBoard() { getBoard().resetBoard(); ArrayList<Cell> removeList = new ArrayList<Cell>(0); for (Organism o : getOrganisms()) { for (Cell current : o.getCells()) { if (current.x < 0 || current.x >= getBoard().getWidth() || current.y < 0 || current.y >= getBoard().getHeight()) { removeList.add(current); } else { getBoard().setCell(current); // gameBoard[current.x+1][current.y+1] = current; } } } for (Cell r : removeList) { removeCell(r, false); } pruneEmptyOrganisms(); } /* * Make sure the all cells on the board are contained within organisms, and * that all cells in organisms are on the board. * * @return if the board isn't consistent with organisms, return false */ public boolean validateBoard() { for (Organism o : getOrganisms()) { for (Cell current : o.getCells()) { if (getBoard().getCell(current.x, current.y) != current) { return false; } } } for (int i = 0; i < getBoard().getWidth(); i++) { for (int j = 0; j < getBoard().getHeight(); j++) { Cell c = getBoard().getCell(i, j); if (c != null && c.getOrganism().getCell(c.x, c.y) != c) { return false; } } } return true; } public void pruneEmptyOrganisms() { HashSet<Organism> pruneOrgs = new HashSet<Organism>(); pruneOrgs.addAll(getOrganisms()); for (Organism org : pruneOrgs) { if (org.getCells().size() == 0) { retireOrganism(org); //org.setAlive(false); //removeOrganism(org); } } } public void clearRetiredOrgs() { getRetiredOrganisms().clear(); } public void setBoardSize(Dimension d) { getBoard().setSize(d); updateBoard(); } }