/* * polycasso - Cubism Artwork generator * Copyright 2009-2017 MeBigFatGuy.com * Copyright 2009-2017 Dave Brosius * Inspired by work by Roger Alsing * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and limitations * under the License. */ package com.mebigfatguy.polycasso; import java.util.EnumMap; import java.util.Map; import java.util.Random; /** * a class to keep track of success statistics by improvement type, in order to further tune what * improvement types to try in the future. It modifies a purely random selection criteria to one that * is tuned by performance. */ public class ImprovementTypeStats { private static final int MAX_FAILURE_RUN = 50; private static class Stats { public int successes = 1; public int totals = 1; public double pct = 1.0; @Override public String toString() { return successes + "/" + totals + " [" + pct + "]"; } } private Map<ImprovementType, Stats> typeStats = new EnumMap<ImprovementType, Stats>(ImprovementType.class); private Random r = new Random(); private int failureRun; /** * creates an initial state of statistics */ public ImprovementTypeStats() { initStats(); } /** * increment a type's statistics whether success or fail * * @param type the improvement type that is to be updated * @param successful if the improvement was successful */ public void typeWasSuccessful(ImprovementType type, boolean successful) { Stats stats = typeStats.get(type); if (successful) { stats.successes++; } stats.totals++; failureRun = successful ? 0 : failureRun + 1; if (failureRun > MAX_FAILURE_RUN) { if (Polycasso.DEBUG){ System.out.println("** Stats at time of failure run **"); System.out.println(this); System.out.println("**********************************"); } initStats(); } else { stats.pct = ((double)stats.successes) / ((double) stats.totals); } } /** * returns a random improvement type that is influenced by how successful the types * have been in the past. * * @return the improvement type to try */ public ImprovementType getRandomImprovementType() { double pct = r.nextDouble(); double totalPct = 0.0; for (Stats stat : typeStats.values()) { totalPct += stat.pct; } for (Map.Entry<ImprovementType, Stats> entry : typeStats.entrySet()) { Stats stat = entry.getValue(); double typePct = stat.pct / totalPct; if (pct <= typePct) return entry.getKey(); pct -= typePct; } return ImprovementType.CompleteChange; } /** * builds a string of all the different types success statistics * * @return a statistics string */ @Override public String toString() { StringBuilder sb = new StringBuilder(100); for (Map.Entry<ImprovementType, Stats> entry : typeStats.entrySet()) { Stats stat = entry.getValue(); sb.append(" ").append(entry.getKey().name()).append("% = ").append(stat.pct * 100); } return sb.toString(); } /** * sets the stats to an initial state */ private void initStats() { ImprovementType[] values = ImprovementType.values(); for (ImprovementType type : values) { typeStats.put(type, new Stats()); } failureRun = 0; } }