/******************************************************************************* * 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.step; import java.awt.Point; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Random; import com.sproutlife.Settings; import com.sproutlife.model.GameModel; import com.sproutlife.model.echosystem.Cell; import com.sproutlife.model.echosystem.Organism; import com.sproutlife.model.seed.BitPattern; import com.sproutlife.model.seed.Seed; import com.sproutlife.model.seed.SeedFactory; import com.sproutlife.model.seed.SeedFactory.SeedType; import com.sproutlife.model.seed.SeedSproutPattern; public class SproutStep extends Step { //LifeStep life; SeedType seedType; int seedBorder = 1; HashMap<Organism,ArrayList<Seed>> savedSeeds; public SproutStep(GameModel gameModel) { super(gameModel); } public void setSeedType(SeedType seedType) { this.seedType = seedType; } public void setSeedType(String seedTypeString) { for (SeedType st : SeedType.values()) { if (st.toString().equals(seedTypeString)) { setSeedType(st); return; } } } public SeedType getSeedType() { return seedType; } public void setSeedBorder(int seedBorder) { this.seedBorder = seedBorder; } public int getSeedBorder() { return seedBorder; } public int getChildEnergy(Organism org, int childNumber) { switch (childNumber) { case 1: return getSettings().getInt(Settings.CHILD_ONE_ENERGY); case 2: return getSettings().getInt(Settings.CHILD_TWO_ENERGY); case 3: return getSettings().getInt(Settings.CHILD_THREE_ENERGY); default: return getSettings().getInt(Settings.CHILD_THREE_ENERGY); } } public void perform() { this.setSeedType(getSettings().getString(Settings.SEED_TYPE)); for (Organism o : getEchosystem().getOrganisms()) { o.getAttributes().energy = o.getAttributes().energy +1; } if (getSettings().getBoolean(Settings.SPROUT_DELAYED_MODE)) { if (this.savedSeeds!=null) { sproutSeeds(this.savedSeeds); } savedSeeds = findSeeds(); } else { //simple way of doing things, makes it harder to display seeds; HashMap<Organism,ArrayList<Seed>> seeds = findSeeds(); sproutSeeds(seeds); } if (getEchosystem().getOrganisms().size()<12) { sproutRandomSeed(); } } private int seedDistSq(Seed s, Organism o) { return (s.getSproutCenter().x-o.x)*(s.getSproutCenter().x-o.x)+(s.getSproutCenter().y-o.y)*(s.getSproutCenter().y-o.y); } private int innerProduct(Seed s1, Seed s2, Organism o) { return (s1.getSproutCenter().x-o.x)*(s1.getSproutCenter().x-s2.getSproutCenter().x) - (s1.getSproutCenter().y-o.y)*(s1.getSproutCenter().y-s2.getSproutCenter().y); } private void sproutSeeds(HashMap<Organism,ArrayList<Seed>> seeds) { //Math.max(10,getEchosystem().getOrganisms().size()/10); for (Organism o: seeds.keySet()) { if(!o.isAlive()) { continue; } ArrayList<Seed> seedList = seeds.get(o); if (seedList.size()>1) { final Organism fo = o; Collections.sort(seedList,new Comparator<Seed>() { @Override public int compare(Seed s1, Seed s2) { //int d1 = (s1.getPosition().x-fo.x)*(s1.getPosition().x-fo.x)+(s1.getPosition().y-fo.y)*(s1.getPosition().y-fo.y); //int d2 = (s2.getPosition().x-fo.x)*(s2.getPosition().x-fo.x)+(s2.getPosition().y-fo.y)*(s2.getPosition().y-fo.y); int d1 = seedDistSq(s1, fo); int d2 = seedDistSq(s2, fo); //Sprout the seeds closer first, there might not be energy for all seeds to sprout. //Smaller organisms look better if (d1==d2) { int ip = innerProduct(s1,s2,fo); //s1.getPosition().x-fo.x)*(s1.getPosition().x-s2.getPosition().x) - (s1.getPosition().y-fo.y)*(s1.getPosition().y-s2.getPosition().y); return ip; } return d1-d2; } }); //int q = 1; Seed s1 = seedList.get(0); Seed s2 = seedList.get(1); if (seedDistSq(s1, fo)==seedDistSq(s2, fo)) { if (innerProduct(s1,s2,fo)==0) { continue; } } } for (Seed s : seedList) { Point seedOnPosition = s.getSeedOnPosition(); Cell c = getBoard().getCell(seedOnPosition); if (c==null) { //Should almost never happen, only if seeds overlapped. //continue; } int childEnergy; if (o.getChildren()!=null) { childEnergy = getChildEnergy(o, o.getChildren().size()+1); } else { childEnergy = getChildEnergy(o, 1); } /* if (o.getKind()==0) { Organism infector = o; for (int i =0;i<7;i++) { if (infector.bornFromInfected) { break; } else { if (infector.getParent()!=null) { infector= infector.getParent(); } } } if (!infector.bornFromInfected && infector.getParent()!=null) { continue; } } */ //if (o.getParent()==null || Math.abs(Math.abs(o.getParent().x-s.getPosition().x)-Math.abs(o.getParent().y-s.getPosition().y))>4) { if (o.getId()==0 || o.getAttributes().energy>=childEnergy) { sproutSeed(s, o); int childCount = o.getChildren().size()-1; o.getAttributes().energy = 0; if(childCount>=0&&getTime()>100&&childCount<20) { //sproutSeed() above may have failed getStats().childEnergy[childCount]+=o.getAge(); getStats().sproutNumber[childCount]++; } } //} } } } private HashMap<Organism,ArrayList<Seed>> findSeeds() { //Cell[][] gameBoard = board.getGameBoard(); HashMap<Organism,ArrayList<Seed>> seeds = new HashMap<Organism,ArrayList<Seed>>(); for (Organism o : getEchosystem().getOrganisms()) { for (Cell c : o.getCells()) { Seed s = checkAndMarkSeed(c); if (s!=null) { ArrayList<Seed> seedList = seeds.get(o); if (seedList == null) { seedList = new ArrayList<Seed>(); seeds.put(o,seedList); } seedList.add(s); } } } return seeds; } private Seed checkAndMarkSeed(Cell topLeftCell) { int border = getSeedBorder(); for (Seed s : SeedFactory.getSeedRotations(getSeedType())) { Point seedOnBit = s.getSeedOnBit(); int x = topLeftCell.x-seedOnBit.x; int y = topLeftCell.y-seedOnBit.y; if (x<0||y<0) { continue; } s.setPosition(x, y); s.setSeedBorder(border); s.setParentPosition(topLeftCell.getOrganism().getLocation()); if(checkAndMarkSeed(s)) { return s; } } return null; } private void sproutRandomSeed() { int x = (new Random()).nextInt(getBoard().getWidth()); int y = (new Random()).nextInt(getBoard().getHeight()); int border = getSeedBorder(); List<Seed> seedRotations = SeedFactory.getSeedRotations(getSeedType()); Seed s = seedRotations.get((new Random()).nextInt(seedRotations.size())); SeedSproutPattern pattern = s.getSeedSproutPattern(); final int seedWidth = pattern.getSeedPattern().getWidth(); final int seedHeight = pattern.getSeedPattern().getWidth(); final BitPattern currentSproutPattern = pattern.getSproutPattern(); SeedSproutPattern newPattern = new SeedSproutPattern() { { this.seedPattern = new BitPattern(new int[seedWidth][seedHeight]); this.sproutPattern = currentSproutPattern; this.sproutOffset = new Point(0,0); } }; s.setPosition(x, y); s.setParentPosition(new Point(120,120)); Seed randomSeed = new Seed(newPattern, s.getRotation()); randomSeed.setPosition(x, y); randomSeed.setSeedBorder(border); randomSeed.setParentPosition(new Point(x+1,y+1)); sproutSeed(randomSeed,null); } public boolean checkAndMarkSeed(Seed seed) { ArrayList<Cell> seedCells = new ArrayList<Cell>(); Organism seedOrg = null; int i = seed.getPosition().x; int j = seed.getPosition().y; int seedWidth = seed.getSeedWidth(); int seedHeight = seed.getSeedHeight(); int border = seed.getSeedBorder(); //Check seed bounds if( i+seedWidth>=getBoard().getWidth() || j+seedHeight>=getBoard().getHeight()) { return false; } //Check seed; for (int si=0;si<seedWidth;si++) { for (int sj=0;sj<seedHeight;sj++) { Cell c = getBoard().getCell(i+si,j+sj); if (seed.getSeedBit(si,sj)) { if (c==null) { return false; } //else if (seedOrg==null) { seedOrg = c.getOrganism(); } if (!c.getOrganism().equals(seedOrg)) { return false; } seedCells.add(c); } else { if (c!=null) { return false; } } } } //Check border for (int si=-border;si<seedWidth+border;si++) { for (int sj=-border;sj<seedHeight+border;sj++) { if(si<=-1 || sj<=-1 || si>=(seedWidth) || sj>=seedHeight) { if(i+si>=0 && j+sj>=0 && i+si<=getBoard().getWidth()-1 && j+sj<=getBoard().getHeight()-1) { if (getBoard().getCell(i+si,j+sj)!=null) { return false; } } } } } for (Cell c: seedCells) { c.setMarkedAsSeed(true); } return true; } public void sproutSeed(Seed seed, Organism seedOrg) { Point sproutPosition = seed.getSproutPosition(); Point sproutCenter = seed.getSproutCenter(); int seedX = seed.getPosition().x; int seedY = seed.getPosition().y; int sproutX = sproutPosition.x; int sproutY = sproutPosition.y; int newOrgX = sproutCenter.x; int newOrgY = sproutCenter.y; int seedWidth = seed.getSeedWidth(); int seedHeight = seed.getSeedHeight(); int sproutWidth = seed.getSproutWidth(); int sproutHeight = seed.getSproutHeight(); if (seedX < 0 || seedY < 0 || seedX + seedWidth > getBoard().getWidth() - 1 || seedY + seedHeight > getBoard().getHeight() - 1 || sproutX + sproutWidth > getBoard().getWidth() - 1 || sproutY + sproutHeight > getBoard().getHeight() - 1 || sproutX < 0 || sproutY < 0) { //Clear the seed flag from cells before returning null if (seedOrg!=null) { for (Cell c : seedOrg.getCells()) { c.setMarkedAsSeed(false); } } return; } Organism newOrg = getEchosystem().createOrganism(newOrgX, newOrgY, seedOrg, seed); //Remove old seed for (int x=0;x<seedWidth;x++) { for (int y=0; y<seedHeight;y++) { if (seed.getSeedBit(x, y)) { Cell rc = getBoard().getCell(seedX+x, seedY+y); getEchosystem().removeCell(rc); //getBoard().clearCell(seedX+x,seedY+y); } } } for (int si = 0;si<sproutWidth;si++) { for (int sj = 0;sj<sproutHeight;sj++) { int i = sproutX+si; int j = sproutY+sj; Cell c = getBoard().getCell(i, j); if (c!=null) { //Only happens when border improperly configured //and/or successively sprouted seeds overlap each other getEchosystem().removeCell(c); //getBoard().clearCell(i, j); } if (seed.getSproutBit(si, sj)) { Cell newC = getEchosystem().addCell(i,j,newOrg); } else { //Should be ok } } } } }