forked from magwo/elevatorsaga
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fitness.js
101 lines (85 loc) · 3.43 KB
/
fitness.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
var requireNothing = function() {
return {
description: "No requirement",
evaluate: function() { return null; }
};
};
var fitnessChallenges = [
{options: {description: "Small scenario", floorCount: 4, elevatorCount: 2, spawnRate: 0.6}, condition: requireNothing()}
,{options: {description: "Medium scenario", floorCount: 6, elevatorCount: 3, spawnRate: 1.5, elevatorCapacities: [5]}, condition: requireNothing()}
,{options: {description: "Large scenario", floorCount: 18, elevatorCount: 6, spawnRate: 1.9, elevatorCapacities: [8]}, condition: requireNothing()}
]
// Simulation without visualisation
function calculateFitness(challenge, codeObj, stepSize, stepsToSimulate) {
var controller = createWorldController(stepSize);
var result = {};
var worldCreator = createWorldCreator();
var world = worldCreator.createWorld(challenge.options);
var frameRequester = createFrameRequester(stepSize);
controller.on("usercode_error", function(e) {
result.error = e;
});
world.on("stats_changed", function() {
result.transportedPerSec = world.transportedPerSec;
result.avgWaitTime = world.avgWaitTime;
result.transportedCount = world.transportedCounter;
});
controller.start(world, codeObj, frameRequester.register, true);
for(var stepCount=0; stepCount < stepsToSimulate && !controller.isPaused; stepCount++) {
frameRequester.trigger();
}
return result;
};
function makeAverageResult(results) {
var averagedResult = {};
_.forOwn(results[0].result, function(value, resultProperty) {
var sum = _.sum(_.pluck(_.pluck(results, "result"), resultProperty));
averagedResult[resultProperty] = sum / results.length;
});
return { options: results[0].options, result: averagedResult };
};
function doFitnessSuite(codeStr, runCount) {
try {
var codeObj = getCodeObjFromCode(codeStr);
} catch(e) {
return {error: "" + e};
}
console.log("Fitness testing code", codeObj);
var error = null;
var testruns = [];
_.times(runCount, function() {
var results = _.map(fitnessChallenges, function(challenge) {
var fitness = calculateFitness(challenge, codeObj, 1000.0/60.0, 12000);
if(fitness.error) { error = fitness.error; return };
return { options: challenge.options, result: fitness }
});
if(error) { return; }
testruns.push(results);
});
if(error) {
return { error: "" + error }
}
// Now do averaging over all properties for each challenge's test runs
var averagedResults = _.map(_.range(testruns[0].length), function(n) { return makeAverageResult(_.pluck(testruns, n)) });
return averagedResults;
}
function fitnessSuite(codeStr, preferWorker, callback) {
if(!!Worker && preferWorker) {
// Web workers are available, neat.
try {
var w = new Worker("fitnessworker.js");
w.postMessage(codeStr);
w.onmessage = function(msg) {
console.log("Got message from fitness worker", msg);
var results = msg.data;
callback(results);
};
return;
} catch(e) {
console.log("Fitness worker creation failed, falling back to normal", e);
}
}
// Fall back do synch calculation without web worker
var results = doFitnessSuite(codeStr, 2);
callback(results);
};