/* * Copyright (C) 2010 Markus Echterhoff <tam@edu.uni-klu.ac.at> * * This file is part of EvoPaint. * * EvoPaint is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with EvoPaint. If not, see <http://www.gnu.org/licenses/>. */ package evopaint.pixel.rulebased.targeting; import evopaint.Configuration; import evopaint.interfaces.IRandomNumberGenerator; import evopaint.pixel.rulebased.RuleBasedPixel; import evopaint.pixel.rulebased.interfaces.INamed; import evopaint.pixel.rulebased.targeting.qualifiers.ColorLikenessColorQualifier; import evopaint.pixel.rulebased.targeting.qualifiers.ColorLikenessMyColorQualifier; import evopaint.pixel.rulebased.targeting.qualifiers.EnergyQualifier; import evopaint.pixel.rulebased.targeting.qualifiers.ExistenceQualifier; import evopaint.util.mapping.RelativeCoordinate; import java.util.ArrayList; import java.util.List; /** * * @author Markus Echterhoff <tam@edu.uni-klu.ac.at> */ public abstract class QualifiedMetaTarget extends MetaTarget implements INamed { protected List<Qualifier> qualifiers; public QualifiedMetaTarget(List<RelativeCoordinate> directions, List<Qualifier> qualifiers) { super(directions); this.qualifiers = qualifiers; } public QualifiedMetaTarget(List<RelativeCoordinate> directions) { super(directions); } public QualifiedMetaTarget() { } public QualifiedMetaTarget(QualifiedMetaTarget qualifiedMetaTarget) { super(qualifiedMetaTarget); qualifiers = new ArrayList(qualifiedMetaTarget.qualifiers); } public QualifiedMetaTarget(int numDirections, IRandomNumberGenerator rng) { super(numDirections, rng); this.qualifiers = new ArrayList(); this.qualifiers.add(Qualifier.createRandom(rng)); } @Override public int countGenes() { int ret = super.countGenes(); for (Qualifier q : qualifiers) { ret += q.countGenes(); } ret += 1; // to remove a qualifier ret += 1; // to add a qualifier return ret; } @Override public void mutate(int mutatedGene, IRandomNumberGenerator rng) { int numGenesSuper = super.countGenes(); if (mutatedGene < numGenesSuper) { super.mutate(mutatedGene, rng); return; } mutatedGene -= numGenesSuper; for (int i = 0; i < qualifiers.size(); i++) { int numGenesQualifier = qualifiers.get(i).countGenes(); if (mutatedGene < numGenesQualifier) { Qualifier newQualifier = Qualifier.copy(qualifiers.get(i)); newQualifier.mutate(mutatedGene, rng); qualifiers.set(i, newQualifier); return; } mutatedGene -= numGenesQualifier; } if (mutatedGene == 0) { if (qualifiers.size() == 0) { return; } qualifiers.remove(rng.nextPositiveInt(qualifiers.size())); return; } mutatedGene -= 1; if (mutatedGene == 0) { qualifiers.add(Qualifier.createRandom(rng)); return; } mutatedGene -= 1; assert false; // we have an error in our mutatedGene calculation } public void mixWith(QualifiedMetaTarget theirTarget, float theirShare, IRandomNumberGenerator rng) { super.mixWith(theirTarget, theirShare, rng); // cache size() calls for maximum performance int ourSize = qualifiers.size(); int theirSize = theirTarget.qualifiers.size(); // now mix as many qualifiers as we have in common and add the rest depending // on share percentage // we have more qualifiers if (ourSize > theirSize) { int i = 0; while (i < theirSize) { Qualifier ourQualifier = qualifiers.get(i); Qualifier theirQualifier = theirTarget.qualifiers.get(i); if (ourQualifier.getType() == theirQualifier.getType()) { Qualifier newQualifier = Qualifier.copy(qualifiers.get(i)); newQualifier.mixWith(theirQualifier, theirShare, rng); qualifiers.set(i, newQualifier); } else { if (rng.nextFloat() < theirShare) { qualifiers.set(i, theirQualifier); } } i++; } int removed = 0; while (i < ourSize - removed) { if (rng.nextFloat() < theirShare) { qualifiers.remove(i); removed ++; } else { i++; } } } else { // they have more qualifiers or we have an equal number of conditions int i = 0; while (i < ourSize) { Qualifier ourQualifier = qualifiers.get(i); Qualifier theirQualifier = theirTarget.qualifiers.get(i); if (ourQualifier.getType() == theirQualifier.getType()) { Qualifier newQualifier = null; int type = ourQualifier.getType(); switch (type) { case Qualifier.COLOR_LIKENESS_COLOR: newQualifier = new ColorLikenessColorQualifier( (ColorLikenessColorQualifier)theirQualifier); break; case Qualifier.COLOR_LIKENESS_MY_COLOR: newQualifier = new ColorLikenessMyColorQualifier( (ColorLikenessMyColorQualifier)theirQualifier); break; case Qualifier.ENERGY: newQualifier = new EnergyQualifier( (EnergyQualifier)theirQualifier); break; case Qualifier.EXISTENCE: newQualifier = new ExistenceQualifier( (ExistenceQualifier)theirQualifier); default: assert (false); } newQualifier.mixWith(theirQualifier, theirShare, rng); qualifiers.set(i, newQualifier); } else { if (rng.nextFloat() < theirShare) { qualifiers.set(i, theirQualifier); } } i++; } while (i < theirSize) { if (rng.nextFloat() < theirShare) { qualifiers.add(theirTarget.qualifiers.get(i)); } i++; } } } public String getName() { return "qualified"; } public List<Qualifier> getQualifiers() { return qualifiers; } public void setQualifiers(List<Qualifier> qualifiers) { this.qualifiers = qualifiers; } @Override public String toString() { String ret = new String(); ret += "one of "; ret += super.toString(); return ret; } @Override public String toHTML() { String ret = new String(); ret += "one of "; ret += super.toHTML(); return ret; } public RelativeCoordinate getCandidate(RuleBasedPixel actor, Configuration configuration) { List<RelativeCoordinate> qualifyingDirections = new ArrayList(directions); for (Qualifier q : qualifiers) { qualifyingDirections = q.getCandidates(actor, qualifyingDirections, configuration); } if (qualifyingDirections.size() == 1) { return qualifyingDirections.get(0); } if (qualifyingDirections.size() == 0) { return null; } return qualifyingDirections.get(configuration.rng.nextPositiveInt(qualifyingDirections.size())); } }