/**
* Segment.java
*/
package rampancy_old.util.tree;
import java.util.Arrays;
import rampancy_old.util.*;
/**
* This is the class that represents a segment
* @author Matthew Chun-Lum
*
*/
public class Segment {
public byte type;
public short visits;
public short previousVisits;
public boolean hasBranched;
public Segment[] branches;
public byte[] availableBranches;
public double[] guessFactors;
public Segment(byte type, int numBranches) {
this.type = type;
this.previousVisits = 0;
visits = 0;
guessFactors = null;
hasBranched = false;
if(type == Segments.TERMINAL_SEGMENT) {
branches = null;
} else {
branches = new Segment[numBranches];
}
}
/**
* Updates the guess factor array
* @param guessFactor
*/
public void updateGuessFactors(double guessFactor, boolean isVirtual) {
int index = Segments.computeGuessFactorIndex(this, guessFactor);
double weight = (isVirtual ? 0.1 : 1.0);
guessFactors[index] = Util.rollingAvg(guessFactors[index], 1.0, Math.min(visits, Constants.STANDARD_ROLL_DEPTH), weight);
for(int i = 0; i < guessFactors.length; i++)
if(i != index)
guessFactors[i] = Util.rollingAvg(guessFactors[i], 1.0 / (Math.pow(index - i, 2) + 1.0), Math.min(visits, Constants.STANDARD_ROLL_DEPTH), weight);
}
/**
* @return a String description of the segment
*/
public String getDescription() {
return Segments.getSegmentDescription(type);
}
/**
* @return number of branches this segment may have
*/
public int getBranchCount() {
return branches.length;
}
/**
* create a new branch at the specified index
* @param branchIndex
*/
public void createBranch(int branchIndex, int[] profile) {
byte branchType = getBestBranchType(profile);
branches[branchIndex] = Segments.getNewSegmentOfType(branchType);
branches[branchIndex].visits = visits;
branches[branchIndex].previousVisits = visits;
branches[branchIndex].guessFactors = new double[guessFactors.length];
System.arraycopy(guessFactors, 0, branches[branchIndex].guessFactors, 0, guessFactors.length);
setAvailableBranches(branches[branchIndex], branchType);
}
/**
* Dives through the tree structure searching for the outermost leaf that satisfies
* the current state of the enemy.
* @param enemy
* @return a reference to segment containing the appropriate array of guess factors
*/
public Segment getSegment(EnemyState enemyState, int[] profile) {
if(!hasBranched && guessFactors != null) {
if(type != Segments.TERMINAL_SEGMENT && visits - previousVisits > Segments.DEFAULT_VISITS_BEFORE_BRANCH) {
hasBranched = true;
} else {
visits++;
return this;
}
}
int branchIndex = Segments.getBranchIndex(enemyState, type);
if(branches[branchIndex] == null)
createBranch(branchIndex, profile);
Segment branch = branches[branchIndex];
return branch.getSegment(enemyState, profile);
}
/**
* @return the number of times this segment has been visited
*/
public short getVisitCount() {
return visits;
}
/**
* Recursively counts the total number of branches (nodes) in the segment tree
* @return the total number of branches
*/
public int getTotalNumberOfBranches() {
int sum = 1;
if(hasBranched) {
for(int i = 0; i < branches.length; i++)
if(branches[i] != null)
sum += branches[i].getTotalNumberOfBranches();
}
return sum;
}
/**
* Recursively count the number of terminal branches
* @return the number of terminal branches
*/
public int getNumTerminalBranches() {
int sum = (type == Segments.TERMINAL_SEGMENT ? 1 : 0);
if(hasBranched) {
for(int i = 0; i < branches.length; i++)
if(branches[i] != null)
sum += branches[i].getNumTerminalBranches();
}
return sum;
}
// ------------------ Private -------------------- //
/*
* using the provided profile, determine which branch type to use
*/
private byte getBestBranchType(int[] profile) {
byte branchType = Segments.TERMINAL_SEGMENT;
int greatestVariation = -1;
if(availableBranches != null) {
for(byte i = 0; i < profile.length; i++) {
if(Arrays.binarySearch(availableBranches, i) >= 0) {
if(Math.abs(profile[i]) > greatestVariation) {
greatestVariation = Math.abs(profile[i]);
branchType = i;
}
}
}
}
return branchType;
}
/*
* copy the array of available branches, leaving out the current choice
*/
private void setAvailableBranches(Segment segment, byte ignoreType) {
if(ignoreType != Segments.TERMINAL_SEGMENT) {
segment.availableBranches = new byte[availableBranches.length - 1];
int newPos = 0;
for(int i = 0; i < availableBranches.length; i++) {
if(availableBranches[i] != ignoreType) {
segment.availableBranches[newPos++] = availableBranches[i];
}
}
}
}
}