import java.util.*;
 
/********************************************************************* 
 * The Pool class holds all of our Candidates for an election. 
 * After an election, the pool runs one cycle of a Genetic Algorithm
 * to alter and update the candidate population.
 ********************************************************************/ 
public class Pool extends Vector { 
    static int NUMFISH = 50; 
    static double MUTANTRATE = .01; 
    public int policies, positions;
    public District parent;

    // the constructor takes in a parent District
    public Pool(District parent) {
	this.parent = parent;
	policies = parent.policies;
	positions = parent.positions;
    }
 
    // Genetic Algorithm for candidate updating
    public void Adapt() {

	// Candidates genetically try to steal parts of winning platforms 
	if (size() > 0) { 
	    int[][] fishpond = new int[NUMFISH][policies]; 
	    
	    // Selection (creating the fishpond)
	    for (int i=0; i<NUMFISH; i++) { 
		int first = Math.abs(Utilities.rand.nextInt() % size()+1); 
		int second = Math.abs(Utilities.rand.nextInt() % size()+1); 
		if (first == size() || second == size()) 
		    System.arraycopy(parent.CurrentRep.ideology, 0, 
				     fishpond[i], 0, policies); 
		else { 
		    Candidate tempCand = (Candidate)elementAt(first); 
		    Candidate tempCand2 = (Candidate)elementAt(second); 
		    if (tempCand.votesReceived > tempCand2.votesReceived) {
			System.arraycopy(tempCand.ideology, 0, 
					 fishpond[i], 0, policies); 
		    } 
		    else 
			System.arraycopy(tempCand2.ideology, 0, 
					 fishpond[i], 0, policies); 
		} 
		
		// Mutation (errors in writing)
		for (int j=0; j<policies; j++) { 
		    if (Utilities.rand.nextDouble() < MUTANTRATE) { 
			fishpond[i][j] = Math.abs(Utilities.rand.nextInt()
						  % positions); 
		    } 
		} 
	    } 
	    
	    // Poorest Candidates drop out 
	    int Poolsize = size(); 
	    
	    for (int i=0; i<size(); i++) { 
		Candidate tempCand = (Candidate)elementAt(i);
		if (tempCand.votesReceived < 
		    ((parent.size()-parent.CurrentRep.votesReceived)
		     / (Poolsize+1))) { 
		    Voter tempVoter = (Voter)parent.elementAt(tempCand.VoterID); 
		    tempVoter.isCandidate = false; 
		    removeElementAt(i); 
		    i--;
		} 
	    } 
	    
	    // Crossover (fishing for new positions)
	    for (int i=0; i<size(); i++) { 
		int mentor = Math.abs(Utilities.rand.nextInt() % NUMFISH); 
		Candidate tempCand = (Candidate)elementAt(i);
		tempCand.Crossover(fishpond[mentor]); 
	    }	     
	} 
    } 
} 
