001 package aima.search.nqueens; 002 003 import java.util.HashSet; 004 import java.util.List; 005 import java.util.Random; 006 import java.util.Set; 007 008 import aima.basic.XYLocation; 009 import aima.search.framework.GoalTest; 010 import aima.search.informed.ga.FitnessFunction; 011 012 /** 013 * A class whose purpose is to evaluate the fitness of NQueen individuals 014 * and to provide utility methods for translating between an NQueensBoard 015 * representation and the String representation used by the GeneticAlgorithm. 016 */ 017 018 /** 019 * @author Ciaran O'Reilly 020 * 021 */ 022 public class NQueensFitnessFunction implements FitnessFunction, GoalTest { 023 024 private final NQueensGoalTest goalTest = new NQueensGoalTest(); 025 026 public NQueensFitnessFunction() { 027 028 } 029 030 // 031 // START - Interface FitnessFunction 032 public Double getValue(String individual) { 033 double fitness = 0; 034 035 NQueensBoard board = getBoardForIndividual(individual); 036 int boardSize = board.getSize(); 037 038 // Calculate the number of non-attacking pairs of queens (refer to AIMA 039 // page 117). 040 List<XYLocation> qPositions = board.getQueenPositions(); 041 for (int fromX = 0; fromX < (boardSize - 1); fromX++) { 042 for (int toX = fromX + 1; toX < boardSize; toX++) { 043 int fromY = qPositions.get(fromX).getYCoOrdinate(); 044 boolean nonAttackingPair = true; 045 // Check right beside 046 int toY = fromY; 047 if (board.queenExistsAt(new XYLocation(toX, toY))) { 048 nonAttackingPair = false; 049 } 050 // Check right and above 051 toY = fromY - (toX - fromX); 052 if (toY >= 0) { 053 if (board.queenExistsAt(new XYLocation(toX, toY))) { 054 nonAttackingPair = false; 055 } 056 } 057 // Check right and below 058 toY = fromY + (toX - fromX); 059 if (toY < boardSize) { 060 if (board.queenExistsAt(new XYLocation(toX, toY))) { 061 nonAttackingPair = false; 062 } 063 } 064 065 if (nonAttackingPair) { 066 fitness += 1.0; 067 } 068 } 069 } 070 071 return fitness; 072 } 073 074 // END - Interface FitnessFunction 075 // 076 077 // 078 // START - Interface GoalTest 079 public boolean isGoalState(Object state) { 080 return goalTest.isGoalState(getBoardForIndividual((String) state)); 081 } 082 083 // END - Interface GoalTest 084 // 085 086 public NQueensBoard getBoardForIndividual(String individual) { 087 int boardSize = individual.length(); 088 NQueensBoard board = new NQueensBoard(boardSize); 089 for (int i = 0; i < boardSize; i++) { 090 int pos = Character 091 .digit(individual.charAt(i), individual.length()); 092 board.addQueenAt(new XYLocation(i, pos)); 093 } 094 095 return board; 096 } 097 098 public String generateRandomIndividual(int boardSize) { 099 StringBuffer ind = new StringBuffer(); 100 101 assert (boardSize >= Character.MIN_RADIX && boardSize <= Character.MAX_RADIX); 102 103 for (int i = 0; i < boardSize; i++) { 104 ind.append(Character.forDigit(new Random().nextInt(boardSize), 105 boardSize)); 106 } 107 108 return ind.toString(); 109 } 110 111 public Set<Character> getFiniteAlphabetForBoardOfSize(int size) { 112 Set<Character> fab = new HashSet<Character>(); 113 114 assert (size >= Character.MIN_RADIX && size <= Character.MAX_RADIX); 115 116 for (int i = 0; i < size; i++) { 117 fab.add(Character.forDigit(i, size)); 118 } 119 120 return fab; 121 } 122 }