package experiment;
import java.awt.event.KeyEvent;
import java.util.Random;
import convergence.Convergence;
import convergence.ModifiedBasicPEST;
import screens.Screen;
import screens.TestTwoCorrScreen;
import util.Globals;
/**
* Runs a basic JND condition.
* <p>
* This will assume that all L and R trials are supposed to be randomised and not
* dictated by any other means.
*
* @author Will
*
*/
public class BasicJNDCondition implements Condition {
// Default Experiment Parameters
protected double PEST_BASE = 0.7;
protected double PEST_DIFF = 0.6;
protected double PEST_STEP = 0.01;
protected int NUM_POINTS_LEFT = 500;
protected int NUM_POINTS_RIGHT = 500;
protected double ERR_LEFT = 0.0001;
protected double ERR_RIGHT = 0.0001;
protected double DOT_SIZE = 1;
protected double SCALING_VAL = 1;
protected int DOT_STYLE = 1;
protected int DOT_HUE = 1;
protected int KEY_R = KeyEvent.VK_M;
protected int KEY_L = KeyEvent.VK_Z;
protected int trialNum = 1;
// Condition is considered complete once trialNum > this number
protected int trialNumCompleteCap = Integer.MAX_VALUE;
protected boolean isDescending = false;
protected boolean isBaseOnLeft = false;
protected boolean isPickHigher = true;
protected boolean isAxisOn = true;
protected boolean isLabelsOn = true;
Screen currentScreen = null;
Convergence myConverge = null;
// using the global random generator
Random generator = Globals.GLOBAL_RANDOM;
public BasicJNDCondition(double base, double diff, boolean isConvAbove,
int pointsLeft, int pointsRight, double errLeft, double errRight, double step, double scaling, double dotSize) {
this.PEST_BASE = base;
this.PEST_DIFF = diff;
this.isDescending = isConvAbove;
this.NUM_POINTS_LEFT = pointsLeft;
this.NUM_POINTS_RIGHT = pointsRight;
this.ERR_LEFT = errLeft;
this.ERR_RIGHT = errRight;
this.PEST_STEP = step;
this.DOT_SIZE = dotSize;
this.SCALING_VAL = scaling;
//this.DOT_STYLE = dotStyle;
myConverge = new ModifiedBasicPEST(PEST_BASE, PEST_DIFF, isDescending, PEST_STEP);
setNextScreen();
}
public BasicJNDCondition(double base, double diff, boolean isConvAbove,
int pointsLeft, int pointsRight, double errLeft, double errRight, double step,
boolean isAxisOn, boolean isLabelsOn, double scalingVal, double dotSize, int dotStyle, int dotHue) {
this.PEST_BASE = base;
this.PEST_DIFF = diff;
this.isDescending = isConvAbove;
this.NUM_POINTS_LEFT = pointsLeft;
this.NUM_POINTS_RIGHT = pointsRight;
this.ERR_LEFT = errLeft;
this.ERR_RIGHT = errRight;
this.PEST_STEP = step;
this.DOT_SIZE = dotSize;
this.SCALING_VAL = scalingVal;
this.DOT_STYLE = dotStyle;
this.DOT_HUE = dotHue;
myConverge = new ModifiedBasicPEST(PEST_BASE, PEST_DIFF, isDescending, PEST_STEP);
this.isAxisOn = isAxisOn;
this.isLabelsOn = isLabelsOn;
setNextScreen();
}
public void setCompleteCap(int cap) {
if (cap < 1) {
return;
}
this.trialNumCompleteCap = cap;
}
protected void setNextScreen() {
isBaseOnLeft = generator.nextBoolean();
if (isBaseOnLeft) {
// base on left
currentScreen = new TestTwoCorrScreen(myConverge.getTrialCompare(), myConverge.getTrialParam(), NUM_POINTS_LEFT, ERR_LEFT, SCALING_VAL, DOT_SIZE, DOT_STYLE, DOT_HUE);
if (isBaseHigher() && isPickHigher) {
currentScreen.setCorrectKey(KEY_L);
} else if (isBaseHigher() && !isPickHigher) {
currentScreen.setCorrectKey(KEY_R);
} else if (!isBaseHigher() && isPickHigher) {
currentScreen.setCorrectKey(KEY_R);
} else {
currentScreen.setCorrectKey(KEY_R);
}
} else {
// base on right
currentScreen = new TestTwoCorrScreen(myConverge.getTrialParam(), myConverge.getTrialCompare(), NUM_POINTS_RIGHT, ERR_RIGHT, SCALING_VAL, DOT_SIZE, DOT_STYLE, DOT_HUE);
if (isBaseHigher() && isPickHigher) {
currentScreen.setCorrectKey(KEY_R);
} else if (isBaseHigher() && !isPickHigher) {
currentScreen.setCorrectKey(KEY_L);
} else if (!isBaseHigher() && isPickHigher) {
currentScreen.setCorrectKey(KEY_L);
} else {
currentScreen.setCorrectKey(KEY_L);
}
}
// TODO: figure out a better way to do screen option passing!
((TestTwoCorrScreen) currentScreen).setDrawAxis(isAxisOn);
((TestTwoCorrScreen) currentScreen).setDrawLabels(isLabelsOn);
}
private boolean isBaseHigher() {
return !isDescending;
}
public int getDotHue() {
return DOT_HUE;
}
public int getDotStyle() {
return DOT_STYLE;
}
public double getScalingVal() {
return SCALING_VAL;
}
public double getDotSize() {
return DOT_SIZE;
}
public int getNumPoints() {
return NUM_POINTS_LEFT;
}
public int getCurrentTrialNumber() {
return trialNum;
}
public double getWindowAverage() {
return myConverge.getWindowAverage();
}
public Screen getNextScreen() {
// TODO: Look into cloning instead... the current approach allows for future authors to
// accidentally write over the Screen!
// look into a better place to put this
setNextScreen();
return currentScreen;
}
public boolean isCompleted() {
return myConverge.isConverged() || trialNum > this.trialNumCompleteCap;
}
public boolean setTrialResponse(int keyPressed) {
this.trialNum++;
boolean isCorrect = currentScreen.getCorrectKey() == keyPressed;
myConverge.setTrialResponse(isCorrect);
// This really slows down the response
// Placing into getNextScreen() where the delay will be in the feedback
// setNextScreen();
return isCorrect;
}
public void setTrialCompleteCap(int completeCap) {
this.trialNumCompleteCap = completeCap;
}
public Convergence getConvergence() {
// TODO: return a clone, not the original!
return myConverge;
}
public boolean getIsDescending() {
return isDescending;
}
public boolean getIsBaseOnLeft() {
return isBaseOnLeft;
}
}