/**********************************************************************
# Copyright (c) EWA Systems Inc. 1998 - 2005 All Rights Reserved
#               No part of this program may be photocopied, reproduced,
#               or translated to another programming language without
#               the prior written consent of EWA Systems.
**********************************************************************/

package com.ewasystems.opt.ga.test;

import com.ewasystems.opt.ga.GeneticAlleleSet;
import com.ewasystems.opt.ga.GeneticConfig;
import com.ewasystems.opt.ga.GeneticEngine;
import com.ewasystems.opt.ga.GeneticGene;
import com.ewasystems.opt.ga.GeneticProblem;
import com.ewasystems.opt.ga.GeneticRunTask;

/**
 * <p>Genetic Algorithm Test Case: PocketChange</p>
 * <p>Description: Minimize Coin Count for a Specified Change Value</p>
 * <p>Copyright: EWASystems Copyright (c) 1998 - 2005</p>
 * <p>Company: EWASystems</p>
 * @author Lincoln Evans-Beauchamp
 * @version 1.0
 */
public class PocketChange extends GeneticProblem
{
  /** The Target Change Value */
  protected final int change;

  /**
   * Problem Constructor
   * @param change The Target Change Value
   */
  public PocketChange(int change)
  {
    super("PocketChange", "Minimize Coin Count for a Specified Change Value");
    this.change = change;
  }

  /**
   * The Objective Function
   * @param gene The Genetic Gene to Test
   * @return double: The Genetic Gene's Fitness
   */
  public double f(GeneticGene gene)
  {
    int quarters = ((Integer)gene.getGeneValue(0)).intValue();
    int dimes = ((Integer)gene.getGeneValue(1)).intValue();
    int nickels = ((Integer)gene.getGeneValue(2)).intValue();
    int pennies = ((Integer)gene.getGeneValue(3)).intValue();
    int value = quarters*25 + dimes*10 + nickels*5 + pennies;
    double fitness = -1d*Math.abs(value - change);
    if (value == change)
      {fitness += 10000d - 5d*(quarters + dimes + nickels + pennies);}
    return fitness;
  }

  /**
   * Gets the Allele Set for the Problem
   * @return GeneticAlleleSet: The Allele Set
   */
  public GeneticAlleleSet getAlleleSet()
  {
    GeneticAlleleSet gas = new GeneticAlleleSet();
    gas.addContinuousAllele("Quarters", new Integer[] {new Integer(0), new Integer(1), new Integer(3)}, 1);
    gas.addContinuousAllele("Dimes", new Integer[] {new Integer(0), new Integer(1), new Integer(2)}, 1);
    gas.addContinuousAllele("Nickels", new Integer[] {new Integer(0), new Integer(1), new Integer(1)}, 1);
    gas.addContinuousAllele("Pennies", new Integer[] {new Integer(0), new Integer(1), new Integer(4)}, 1);
    return gas;
  }

  /**
   * Gets the Objective Type
   * @return int: The Objective Type
   */
  public int getObjectiveType()
    {return OBJECTIVE_TYPE_MAX;}

  /**
   * Main for Running the Problem
   * @param args Not Used
   */
  public static final void main(String[] args)
  {
    GeneticEngine ge = new GeneticEngine();
    GeneticConfig gc = ge.getDefaultConfig();
    gc.setMaxGenerations(10);
    gc.setPopulationSize(500);
    //gc.setShowGenerationResults(true);
    gc.setShowFinalReport(true);
    for (int i=1; i<100; i++)
    {
      GeneticRunTask grt = ge.createGeneticTask(new PocketChange(i), gc);
      GeneticGene seedGene = new GeneticGene(new Object[] {new Integer(3), new Integer(2), new Integer(0), new Integer(4)});
      grt.getPopulation(0).addPopulationGene(seedGene);
      grt.run();
    }
  }
}
