package strategies;

import individuals.GAIndividual;

public class HillClimbing {
	/** The length of the genotype of the individuals **/
	private int m_GenotypeLength;
	/** The number of single optimization steps to be evaluated **/
	private int m_OptimizationSteps;
	/** The number of times the experiment is repeated **/
	private int m_MultiRuns;
	/** Number of steps needed to reach best result **/
	private int m_OptimizationStepsNeeded = 0;
	/** Current best individual **/
	private GAIndividual m_Best;

	/**
	 * This constructor sets up HillClimber
	 * 
	 * @param genotypeLength
	 *            The length of the genotype of the individuals
	 * @param optimizationSteps
	 *            The number of single optimization steps to be evaluated
	 *            (adjust as necessary)
	 * @param multiRuns
	 *            The number of times the experiment is repeated (at least 10)
	 */
	public HillClimbing(int genotypeLength, int optimizationSteps, int multiRuns) {
		assert multiRuns > 9;
		this.m_GenotypeLength = genotypeLength;
		this.m_OptimizationSteps = optimizationSteps;
		this.m_MultiRuns = multiRuns;
	}

	/**
	 * This method will initialize the HillClimber
	 */
	public void initialize() {
		m_Best = new GAIndividual(m_GenotypeLength);
		m_OptimizationStepsNeeded = 0;
	}

	/**
	 * This method will optimize the defaultEvaulateAsMiniBits Problem. Use
	 * m_FitnessCallsNeeded to return the number of FitnessCalls (e.g., calling
	 * evaluateAsMaxiBits()) needed to find the optimum. The optimization should
	 * terminate after m_FitnessCalls.
	 */
	public void optimize() {
		// nur mutieren oder auch crossover?

		// TODO implement this
		// use GAIndividual.evaluateAsMaxiBits() to evaluate the fitness of an
		// individual and call it m_OptimizationSteps times before terminating
		for (int i = 0; i < m_OptimizationSteps; i++) {
			GAIndividual clone = (GAIndividual) m_Best.clone();
			clone.mutate();
			m_Best = clone.evaluateAsMaxiBits() > m_Best.evaluateAsMaxiBits() ? clone
					: m_Best;
			m_OptimizationStepsNeeded++;
			if (m_Best.evaluateAsMaxiBits() == m_GenotypeLength) {
				break;
			}
		}
	}

	/**
	 * This main method will start a simple hill climber. No arguments
	 * necessary.
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO: parameters for the HillClimber, adjust these values as
		// necessary
		int genotypeLength = 10;
		int optimizationSteps = 100000;
		int multiRuns = 100;
		HillClimbing program = new HillClimbing(genotypeLength,
				optimizationSteps, multiRuns);
		int TmpMeanCalls = 0, TmpMeanFitness = 0;
		// perform repeated optimization
		for (int i = 0; i < program.m_MultiRuns; i++) {
			program.initialize();
			program.optimize();
			TmpMeanCalls += program.m_OptimizationStepsNeeded;
			TmpMeanFitness += program.m_Best.evaluateAsMaxiBits();

		}
		TmpMeanCalls = TmpMeanCalls / program.m_MultiRuns;
		TmpMeanFitness = TmpMeanFitness / program.m_MultiRuns;
		System.out.println("(" + program.m_MultiRuns + "/"
				+ program.m_OptimizationSteps + ") Mean Fitness : "
				+ TmpMeanFitness + " Mean Calls needed: " + TmpMeanCalls);
	}
}
