Skip to content

Commit

Permalink
Improve MonteCarlo simulations.
Browse files Browse the repository at this point in the history
- Add assumeSuccess and overrideOnCondition parameters.
- Use the user's Override On Condittion setting.
- Track the best and worse runs and log their results as well.
- Log the max values for durability, cp, quality, progress as well.
doxxx committed May 5, 2018
1 parent 9acc6ea commit c455d82
Showing 3 changed files with 131 additions and 29 deletions.
141 changes: 123 additions & 18 deletions app/js/ffxivcraftmodel.js
Original file line number Diff line number Diff line change
@@ -185,6 +185,14 @@ function State(synth, step, lastStep, action, durabilityState, cpState, bonusMax
this.effects = effects;
this.condition = condition;

// Internal state variables set after each step.
this.iqCnt = 0;
this.wwywCnt = 0;
this.control = 0;
this.qualityGain = 0;
this.bProgressGain = 0;
this.bQualityGain = 0;
this.success = 0;
}

State.prototype.clone = function () {
@@ -1127,15 +1135,24 @@ function MonteCarloStep(startState, action, assumeSuccess, verbose, debug, logOu
// wwywCnt = s.effects.countDowns[AllActions.whistle.shortName];
// }

// Add internal state variables for later output of best and worst cases
s.action = action.shortName;
s.iqCnt = iqCnt;
s.wwywCnt = wwywCnt;
s.control = r.control;
s.qualityGain = qualityGain;
s.bProgressGain = Math.floor(r.bProgressGain);
s.bQualityGain = Math.floor(r.bQualityGain);
s.success = success;

if (debug) {
logger.log('%2d %30s %5.0f %5.0f %8.0f %8.0f %5.0f %5.0f %5.0f %5.0f %5.0f %5.0f %5.0f %-10s %5.0f', s.step, action.name, s.durabilityState, s.cpState, s.qualityState, s.progressState, iqCnt, wwywCnt, r.control, qualityGain, Math.floor(r.bProgressGain), Math.floor(r.bQualityGain), s.wastedActions, s.condition, success);
logger.log('%2d %30s %5.0f %5.0f %8.0f %8.0f %5.0f %5.0f %5.0f %5.0f %5.0f %5.0f %5.0f %-10s %5.0f', s.step, action.name, s.durabilityState, s.cpState, s.qualityState, s.progressState, s.iqCnt, s.wwywCnt, s.control, s.qualityGain, s.bProgressGain, s.bQualityGain, s.wastedActions, s.condition, s.success);
}
else if (verbose) {
logger.log('%2d %30s %5.0f %5.0f %8.0f %8.0f %5.0f %5.0f %-10s %-5s', s.step, action.name, s.durabilityState, s.cpState, s.qualityState, s.progressState, iqCnt, wwywCnt, s.condition, success);
logger.log('%2d %30s %5.0f %5.0f %8.0f %8.0f %5.0f %5.0f %-10s %-5s', s.step, action.name, s.durabilityState, s.cpState, s.qualityState, s.progressState, s.iqCnt, s.wwywCnt, s.condition, s.success);
}

// Return final state
s.action = action.shortName;
return s;

}
@@ -1200,37 +1217,45 @@ function MonteCarloSequence(individual, startState, assumeSuccess, overrideOnCon

}

var states = [];

states.push(s);

for (i=0; i < individual.length; i++) {
var action = individual[i];

if (overrideOnCondition) {
// Manually re-add condition dependent action when conditions are met
if (s.condition == 'Excellent' && s.trickUses < maxConditionUses) {
if (s.condition === 'Excellent' && s.trickUses < maxConditionUses) {
if (onExcellentOnlyActions.length > 0) {
s = MonteCarloStep(s, onExcellentOnlyActions.shift(), assumeSuccess, verbose, debug, logOutput);

states.push(s);
}
else if (onGoodOrExcellentActions.length > 0) {
s = MonteCarloStep(s, onGoodOrExcellentActions.shift(), assumeSuccess, verbose, debug, logOutput);
states.push(s);
}
}
if (s.condition == 'Good' && s.trickUses < maxConditionUses) {
if (s.condition === 'Good' && s.trickUses < maxConditionUses) {
if (onGoodOnlyActions.length > 0) {
s = MonteCarloStep(s, onGoodOnlyActions.shift(), assumeSuccess, verbose, debug, logOutput);

states.push(s);
}
else if (onGoodOrExcellentActions.length > 0) {
s = MonteCarloStep(s, onGoodOrExcellentActions.shift(), assumeSuccess, verbose, debug, logOutput);
states.push(s);
}
}
if (s.condition == 'Poor' && s.trickUses < maxConditionUses) {
if (s.condition === 'Poor' && s.trickUses < maxConditionUses) {
if (onPoorOnlyActions.length > 0) {
s = MonteCarloStep(s, onPoorOnlyActions.shift(), assumeSuccess, verbose, debug, logOutput);

states.push(s);
}
}
}

s = MonteCarloStep(s, action, assumeSuccess, verbose, debug, logOutput);
states.push(s);
}

// Check for feasibility violations
@@ -1247,10 +1272,10 @@ function MonteCarloSequence(individual, startState, assumeSuccess, overrideOnCon
logger.log('Progress Check: %s, Durability Check: %s, CP Check: %s, Tricks Check: %s, Reliability Check: %s, Cross Class Skills: %d, Wasted Actions: %d', chk.progressOk, chk.durabilityOk, chk.cpOk, chk.trickOk, chk.reliabilityOk, crossClassActionCounter, s.wastedActions);
}

return s;
return states;
}

function MonteCarloSim(individual, synth, nRuns, verbose, debug, logOutput) {
function MonteCarloSim(individual, synth, nRuns, assumeSuccess, overrideOnCondition, verbose, debug, logOutput) {
verbose = verbose !== undefined ? verbose : false;
debug = debug !== undefined ? debug : false;
logOutput = logOutput !== undefined ? logOutput : null;
@@ -1259,13 +1284,26 @@ function MonteCarloSim(individual, synth, nRuns, verbose, debug, logOutput) {

var startState = NewStateFromSynth(synth);

var bestSequenceStates;
var worseSequenceStates;
var finalStateTracker = [];
for (var i=0; i < nRuns; i++) {
var runSynth = MonteCarloSequence(individual, startState, false, true, false, false, logOutput);
finalStateTracker[finalStateTracker.length] = runSynth;
//var states = MonteCarloSequence(individual, startState, false, true, false, false, logOutput);
var states = MonteCarloSequence(individual, startState, assumeSuccess, overrideOnCondition, false, false, logOutput);
var finalState = states[states.length-1];

if (!bestSequenceStates || finalState.qualityState > bestSequenceStates[bestSequenceStates.length-1].qualityState) {
bestSequenceStates = states;
}

if (!worseSequenceStates || finalState.qualityState < worseSequenceStates[worseSequenceStates.length-1].qualityState) {
worseSequenceStates = states;
}

finalStateTracker.push(finalState);

if (verbose) {
logger.log('%2d %-20s %5d %5d %8.1f %5.1f %5d', i, 'MonteCarlo', runSynth.durabilityState, runSynth.cpState, runSynth.qualityState, runSynth.progressState, runSynth.wastedActions);
logger.log('%2d %-20s %5d %5d %8.1f %5.1f %5d', i, 'MonteCarlo', finalState.durabilityState, finalState.cpState, finalState.qualityState, finalState.progressState, finalState.wastedActions);
}
}

@@ -1318,13 +1356,65 @@ function MonteCarloSim(individual, synth, nRuns, verbose, debug, logOutput) {

logger.log('%2s %-20s %5.0f %5.0f %8.1f %5.1f %5.1f', '##', 'Min Value: ', minDurability, minCp, minQuality, minProgress, minHqPercent);

var maxDurability = getMaxProperty(finalStateTracker, 'durabilityState');
var maxCp = getMaxProperty(finalStateTracker, 'cpState');
var maxQuality = getMaxProperty(finalStateTracker, 'qualityState');
var maxProgress = getMaxProperty(finalStateTracker, 'progressState');
var maxQualityPercent = Math.max(synth.recipe.maxQuality, maxQuality)/synth.recipe.maxQuality * 100;
var maxHqPercent = hqPercentFromQuality(maxQualityPercent);
var maxStats = {
durability: maxDurability,
cp: maxCp,
quality: maxQuality,
progress: maxProgress,
hqPercent: maxHqPercent
};

logger.log('%2s %-20s %5.0f %5.0f %8.1f %5.1f %5.1f', '##', 'Max Value: ', maxDurability, maxCp, maxQuality, maxProgress, maxHqPercent);

logger.log('\n%2s %-20s %5.1f %%', '##', 'Success Rate: ', successRate);

logger.log('');

logger.log("Monte Carlo Random Example");
logger.log("==========================");
// MonteCarloSequence(sim.sequence, sim.startState, false, settings.overrideOnCondition, false, true, logOutput);
MonteCarloSequence(individual, startState, assumeSuccess, overrideOnCondition, false, true, logOutput);

logger.log('');

logger.log("Monte Carlo Best Example");
logger.log("==========================");
logger.log('%-2s %30s %-5s %-5s %-8s %-8s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-10s %-5s', '#', 'Action', 'DUR', 'CP', 'QUA', 'PRG', 'IQ', 'WWYW', 'CTL', 'QINC', 'BPRG', 'BQUA', 'WAC', 'Cond', 'S/F');

for (var i = 0; i < bestSequenceStates.length; i++) {
var s = bestSequenceStates[i];
var action = AllActions[s.action];
var actionName = action ? action.name : '';
logger.log('%2d %30s %5.0f %5.0f %8.0f %8.0f %5.0f %5.0f %5.0f %5.0f %5.0f %5.0f %5.0f %-10s %5.0f', s.step, actionName, s.durabilityState, s.cpState, s.qualityState, s.progressState, s.iqCnt, s.wwywCnt, s.control, s.qualityGain, s.bProgressGain, s.bQualityGain, s.wastedActions, s.condition, s.success);
}

logger.log('');

logger.log("Monte Carlo Worst Example");
logger.log("==========================");
logger.log('%-2s %30s %-5s %-5s %-8s %-8s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-10s %-5s', '#', 'Action', 'DUR', 'CP', 'QUA', 'PRG', 'IQ', 'WWYW', 'CTL', 'QINC', 'BPRG', 'BQUA', 'WAC', 'Cond', 'S/F');

for (var i = 0; i < worseSequenceStates.length; i++) {
var s = worseSequenceStates[i];
var action = AllActions[s.action];
var actionName = action ? action.name : '';
logger.log('%2d %30s %5.0f %5.0f %8.0f %8.0f %5.0f %5.0f %5.0f %5.0f %5.0f %5.0f %5.0f %-10s %5.0f', s.step, actionName, s.durabilityState, s.cpState, s.qualityState, s.progressState, s.iqCnt, s.wwywCnt, s.control, s.qualityGain, s.bProgressGain, s.bQualityGain, s.wastedActions, s.condition, s.success);
}

logger.log('');

return {
successPercent: successRate,
average: avgStats,
median: mdnStats,
min: minStats
successPercent: successRate,
average: avgStats,
median: mdnStats,
min: minStats,
max: maxStats,
}
}

@@ -1443,6 +1533,21 @@ function getMinProperty(stateArray, propName) {
return minProperty;
}

function getMaxProperty(stateArray, propName) {
var maxProperty = null;
for (var i=0; i < stateArray.length; i++) {
if (maxProperty === null) {
maxProperty = stateArray[i][propName];
}
else {
if (maxProperty < stateArray[i][propName]) {
maxProperty = stateArray[i][propName];
}
}
}
return maxProperty;
}

function qualityFromHqPercent(hqPercent) {
var x = hqPercent;
return -5.6604E-6 * Math.pow(x, 4) + 0.0015369705 * Math.pow(x, 3) - 0.1426469573 * Math.pow(x, 2) + 5.6122722959 * x - 5.5950384565;
13 changes: 4 additions & 9 deletions app/js/simulationworker.js
Original file line number Diff line number Diff line change
@@ -103,21 +103,16 @@ function runMonteCarloSim(id, settings) {

logOutput.write('Seed: %d, Use Conditions: %s\n\n'.sprintf(sim.seed, sim.synth.useConditions));

logOutput.write("Monte Carlo Example\n");
logOutput.write("===================\n");
MonteCarloSequence(sim.sequence, sim.startState, false, settings.overrideOnCondition, false, true, logOutput);

logOutput.write("\n");

var monteCarloSimHeader = "Monte Carlo Result of " + settings.maxMontecarloRuns + " runs";
logOutput.write(monteCarloSimHeader + "\n");
logOutput.write("=".repeat(monteCarloSimHeader.length));
logOutput.write("\n");

var mcSimResult = MonteCarloSim(sim.sequence, sim.synth, settings.maxMontecarloRuns, false, settings.debug, logOutput);
var mcSimResult = MonteCarloSim(sim.sequence, sim.synth, settings.maxMontecarloRuns, false, settings.overrideOnCondition, false, settings.debug, logOutput);

// Don't use conditions for final state to avoid random results
var finalState = MonteCarloSequence(sim.sequence, sim.startStateNoConditions, true, false, false, false, logOutput);
// Don't use conditions for final state to avoid oscillating results in the simulation state UI
var states = MonteCarloSequence(sim.sequence, sim.startStateNoConditions, true, false, false, false, logOutput);
var finalState = states[states.length - 1];

var violations = finalState.checkViolations();

6 changes: 4 additions & 2 deletions app/js/solver/worker.js
Original file line number Diff line number Diff line change
@@ -188,7 +188,8 @@ Settings:\n\

logOutput.write('\n\n');

var heuristcState = MonteCarloSequence(sequence, NewStateFromSynth(synth), true, false, false, settings.debug, logOutput);
var states = MonteCarloSequence(sequence, NewStateFromSynth(synth), true, false, false, settings.debug, logOutput);
var heuristcState = states[states.length-1];

var chk = heuristcState.checkViolations();
var feasibility = chk.progressOk && chk.durabilityOk && chk.cpOk && chk.trickOk && chk.reliabilityOk;
@@ -295,7 +296,8 @@ function finish() {
function postProgress(gen, maxGen, best, synthNoConditions) {
var startState = NewStateFromSynth(synthNoConditions);

var currentState = MonteCarloSequence(best, startState, true, false, false, false);
var states = MonteCarloSequence(best, startState, true, false, false, false);
var currentState = states[states.length-1];
var violations = currentState.checkViolations();

self.postMessage({

0 comments on commit c455d82

Please sign in to comment.