/* * Copyright 2015 S. Webber * * 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 org.oakgp.examples.ant; import org.oakgp.Assignments; import org.oakgp.node.Node; import org.oakgp.rank.fitness.FitnessFunction; /** Calculates the fitness of candidate solutions to navigate an artificial ant around a two-dimensional grid. */ class ArtificialAntFitnessFunction implements FitnessFunction { private static final int MAX_MOVES = 600; @Override public double evaluate(Node candidate) { MutableState state = new MutableState(GridReader.copyGrid()); evaluate(candidate, state); return calculateFitness(state); } /** Keeps evaluating the given candidate using the given state until either the maximum number of moves have been taken or all the food has been eaten. */ private void evaluate(Node candidate, MutableState state) { Assignments assignments = Assignments.createAssignments(state); int movesTaken = 0; while (movesTaken < MAX_MOVES && isRemainingFood(state)) { candidate.evaluate(assignments); // if last call to evaluate did not result in the state being updated // then exit now to avoid getting stuck in loop when evaluating candidates that do not do anything if (movesTaken == state.getMovesTaken()) { return; } movesTaken = state.getMovesTaken(); } } /** * Calculate fitness of the given state. * <p> * Any state where all the food has been eaten is better than any state where there is food remaining. The best solution is the one where all the food has * been eaten in the quickest time. */ private double calculateFitness(MutableState state) { if (isRemainingFood(state)) { return Integer.MAX_VALUE - state.getFoodEaten(); } else { return state.getMovesTaken(); } } /** Returns {@code true} if the given state contains cells with food that have not yet been visited. */ private boolean isRemainingFood(MutableState state) { return state.getFoodEaten() < GridReader.getNumberOfFoodCells(); } }