Skip to content

Commit fb89ef3

Browse files
authored
Merge pull request #76 from Itangalo/1.3
1.3
2 parents b024bc0 + 5aa2b2d commit fb89ef3

31 files changed

Lines changed: 742 additions & 178 deletions

000-simulation.gs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
*/
1212

1313
// Initiate some global variables.
14-
var global = {}; // Further populated by buildInitialData().
14+
var BPTstatic = {}; // Further populated by buildInitialData().
1515
var modules = {}; // Populated by custom code.
1616
var module;
1717
var gameState = {};
18-
global.startTime = Date.now();
18+
BPTstatic.startTime = Date.now();
1919

2020
function simulate(iterations = false, mod = false) {
2121
// Set global default values.
@@ -35,7 +35,7 @@ function simulate(iterations = false, mod = false) {
3535
*/
3636
let results = []; // Variable used to save data from each game iteration.
3737
if (!iterations)
38-
iterations = global.defaults.iterations;
38+
iterations = BPTstatic.defaults.iterations;
3939
for (let iteration = 1; iteration <= iterations; iteration++) {
4040
/**
4141
* Set up each game.

003-defaults.gs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44

55
function setInitialDefaults() {
6-
global.defaults = {
6+
BPTstatic.defaults = {
77
module: 'example1',
88
iterations: 100,
99
logging : {
@@ -49,7 +49,7 @@ function setInitialDefaults() {
4949
},
5050
};
5151
// Apply some defaults right away.
52-
module = global.defaults.module;
52+
module = BPTstatic.defaults.module;
5353
for (let i of ['logging', 'statistics'])
54-
global[i] = global.defaults[i];
54+
BPTstatic[i] = BPTstatic.defaults[i];
5555
}

200-helpersGeneral.gs

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -298,14 +298,25 @@ function copy(object) {
298298
return JSON.parse(JSON.stringify(object));
299299
}
300300

301-
// Checks if an object/array is iterable.
302-
// Code from https://stackoverflow.com/questions/18884249/checking-whether-something-is-iterable
303-
function isIterable(obj) {
304-
// checks for null and undefined
305-
if (obj == null) {
306-
return false;
301+
/**
302+
* Stores an object in the cache, to use in future game iterations. Identified by 'key'.
303+
*/
304+
function setCache(key, value) {
305+
if (!BPTstatic.cache)
306+
BPTstatic.cache = {};
307+
BPTstatic.cache[key] = value;
308+
}
309+
310+
/**
311+
* Returns a cached object, identified by 'key', or undefined if it is not cached.
312+
* Cached objects are kept between game iterations.
313+
*/
314+
function getCache(key) {
315+
if (!BPTstatic.cache) {
316+
BPTstatic.cache = {};
317+
return undefined;
307318
}
308-
return typeof obj[Symbol.iterator] === 'function';
319+
return BPTstatic.cache[key];
309320
}
310321

311322
// Returns the agent with the matching id or false if none is found.
@@ -315,6 +326,36 @@ function getAgentById(id) {
315326
return new ObjectFilter({id: id}).findFirstInArray(gameState.agents);
316327
}
317328

329+
/**
330+
* Returns the first agent in the list of agents, and moves it last in the list.
331+
*/
332+
function getAndRotateFirstAgent() {
333+
let agent = gameState.agents[0];
334+
gameState.agents.shift();
335+
gameState.agents.push(agent);
336+
return agent;
337+
}
338+
339+
// Returns an array of tracked data for the given property. Adds zeroes when needed.
340+
function getTrackedData(property) {
341+
let output = [];
342+
for (let a of gameState.agents) {
343+
if (!a.tracking || !a.tracking[property])
344+
output.push({
345+
increaseCount: 0,
346+
increaseSum: 0,
347+
decreaseCount: 0,
348+
decreaseSum: 0,
349+
unchangedCount: 0,
350+
count: 0,
351+
sum: 0,
352+
});
353+
else
354+
output.push(a.tracking[property]);
355+
}
356+
return output;
357+
}
358+
318359
// Selects a and returns a random element from an array. If the array consists of
319360
// objects, 'property' can be set to a property name in order to use the property
320361
// values for weighting probability.
@@ -468,5 +509,5 @@ function callResolver(method) {
468509
return false;
469510
}
470511

471-
return modules[module].resolvers[type][method](...parseArguments(arguments, 1));
512+
return modules[module].resolvers[method](...parseArguments(arguments, 1));
472513
}

210-processResults.gs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ function processResults(results) {
3131
// Header row
3232
let message = 'DISTRIBUTION: average (percentile ';
3333
let values = [];
34-
for (let p of global.statistics.percentiles) {
34+
for (let p of BPTstatic.statistics.percentiles) {
3535
values.push(p);
3636
}
3737
message += values.join(' | ') + ')\r\n---\r\n';
@@ -40,7 +40,7 @@ function processResults(results) {
4040
message += i + ': ';
4141
message += average(sortedResults[i]).toFixed(2) + ' (';
4242
values = [];
43-
for (let p of global.statistics.percentiles) {
43+
for (let p of BPTstatic.statistics.percentiles) {
4444
values.push(percentile(sortedResults[i], p).toFixed(2));
4545
}
4646
message += values.join(' | ') + ') Positive at ';
@@ -67,7 +67,7 @@ function processResults(results) {
6767
output[2].push(getPositiveThreshold(sortedResults[i]));
6868
}
6969
// Percentiles
70-
for (let p of global.statistics.percentiles) {
70+
for (let p of BPTstatic.statistics.percentiles) {
7171
let line = ['percentile ' + p];
7272
for (let i in sortedResults) {
7373
line.push(percentile(sortedResults[i], p));

220-logging.gs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
* @param {string} type: The type of log message, used for restricting actual output.
1010
*/
1111
function log(message, type) {
12-
if (global.logging.categories[type]) {
13-
if (global.logging.showTimestamps)
14-
message += ' (time: ' + (Date.now() - global.startTime) + ')';
12+
if (BPTstatic.logging.categories[type]) {
13+
if (BPTstatic.logging.showTimestamps)
14+
message += ' (time: ' + (Date.now() - BPTstatic.startTime) + ')';
1515
Logger.log(message);
1616
}
1717
}

classes/100-Agent.gs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,32 @@ class Agent {
8181
}
8282
}
8383

84+
/**
85+
* Returns a randomly selected agent other than this agent.
86+
*
87+
* @param {ObjectFilter} filter: If used, any additional restrictions will be applied.
88+
*/
89+
getRandomOpponent(filter = false) {
90+
if (filter === false)
91+
filter = new ObjectFilter().addNotEqualsCondition({id: this.id});
92+
else
93+
filter.addNotEqualsCondition({id: this.id});
94+
95+
let candidates = filter.applyOnArray(gameState.agents);
96+
if (candidates.length == 0)
97+
throw('Tried to select a random opponent, but found no matching agents.');
98+
99+
return selectRandom(candidates);
100+
}
101+
102+
/**
103+
* Places the agent first in the list of agents.
104+
*/
105+
makeFirstAgent() {
106+
let a = new ObjectFilter({id: this.id}).removeFirstFromArray(gameState.agents);
107+
gameState.agents.unshift(a);
108+
}
109+
84110
/**
85111
* Used to call a strategy on behalf of the agent. Any arguments will be passed on
86112
* to the strategy method. First argument will always be the agent object.
@@ -99,6 +125,7 @@ class Agent {
99125
if (!modules[module].agentStrategies[this.strategy][method])
100126
throw('Method ' + method + ' does not exist in ' + this.strategy + '.');
101127

102-
return modules[module].agentStrategies[this.strategy][method](this, ...arguments);
128+
let args = parseArguments(arguments, 1);
129+
return modules[module].agentStrategies[this.strategy][method](this, ...args);
103130
}
104131
}

classes/110-Deck.gs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class Deck {
2020
*/
2121
constructor(deckData, cardDataArray = false) {
2222
// Add default settings, overwrite with provided data.
23-
Object.assign(this, applyDefaults(global.defaults.deck, deckData));
23+
Object.assign(this, applyDefaults(BPTstatic.defaults.deck, deckData));
2424
// Verify that an ID is present.
2525
Object.assign(this, deckData);
2626
if (this.id === undefined)

classes/120-Track.gs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
* - gridMovement: If true, possible movement is defined through connections on spaces. Defaults to false.
1515
* - symmetricConnections: If true, any connections between spaces are assumed to go both ways.
1616
* Only relevant if gridMovement is true. Defaults to true.
17+
* - cacheGraph: If true, the created map of connections between spaces is stored between game iterations.
18+
* Only use if the connections do not change within or between games. Defaults to false.
1719
*
1820
* @param {Array} spacesDataArray: An array of objects describing each space on the track.
1921
* See Space class for details.
@@ -23,7 +25,7 @@
2325
class Track {
2426
constructor(trackData, spacesDataArray = false, pawnsDataArray = false) {
2527
// Add default settings, overwrite with provided data.
26-
Object.assign(this, applyDefaults(global.defaults.track, trackData));
28+
Object.assign(this, applyDefaults(BPTstatic.defaults.track, trackData));
2729
// Verify that an ID is present.
2830
if (this.id === undefined)
2931
throw('Tracks must have an id property set.');
@@ -60,19 +62,29 @@ class Track {
6062
// Build a graph of how the spaces connect, if advanced movement is used.
6163
// Data used by the a-star algorithm, to find paths in the grid.
6264
if (this.gridMovement) {
63-
this.graph = [];
64-
for (let i = 0; i < this.spaces.length; i++)
65-
this.graph.push([]);
66-
for (let s of this.spaces) {
67-
for (let c of s.connectsTo) {
68-
let target = new ObjectFilter({id: c}).findFirstInArray(this.spaces);
69-
this.graph[s.index][target.index] = 1;
70-
if (this.symmetricConnections)
71-
this.graph[target.index][s.index] = 1;
65+
if (this.cacheGraph) {
66+
this.graph = getCache('track.' + this.id + '.grid');
67+
this.heuristic = getCache('track.' + this.id + '.heuristic');
68+
}
69+
else
70+
this.graph = false;
71+
if (!this.graph) {
72+
this.graph = [];
73+
for (let i = 0; i < this.spaces.length; i++)
74+
this.graph.push([]);
75+
for (let s of this.spaces) {
76+
for (let c of s.connectsTo) {
77+
let target = new ObjectFilter({id: c}).findFirstInArray(this.spaces);
78+
this.graph[s.index][target.index] = 1;
79+
if (this.symmetricConnections)
80+
this.graph[target.index][s.index] = 1;
81+
}
7282
}
83+
let row = Array(this.graph.length).fill(1);
84+
this.heuristic = Array(this.graph.length).fill(row);
85+
setCache('track.' + this.id + '.grid', this.graph);
86+
setCache('track.' + this.id + '.heuristic', this.heuristic);
7387
}
74-
let row = Array(this.graph.length).fill(1);
75-
this.heuristic = Array(this.graph.length).fill(row);
7688
this.pawnPaths = {};
7789
}
7890

@@ -138,7 +150,7 @@ class Track {
138150
if (this.assumePresent) {
139151
return new Pawn({id: pawnId}, this);
140152
}
141-
if (global.debugRunning)
153+
if (BPTstatic.debugRunning)
142154
return false;
143155
throw('Tried to get pawn ' + pawnId + ' but no such pawn exist on track + ' + this.id + '.');
144156
}

classes/130-Market.gs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
class Market {
3333
constructor(marketData, goodsDataArray = false) {
3434
// Add default settings, overwrite with provided data.
35-
Object.assign(this, applyDefaults(global.defaults.market, marketData));
35+
Object.assign(this, applyDefaults(BPTstatic.defaults.market, marketData));
3636
// Verify that an ID is present.
3737
if (this.id === undefined)
3838
throw('Markets must have an id property set.');
@@ -302,7 +302,7 @@ class Goods {
302302
if (!market instanceof Market)
303303
throw('Goods must be added to a proper market.');
304304
// Add default settings, overwrite with provided data.
305-
Object.assign(this, applyDefaults(global.defaults.goods, goodsData));
305+
Object.assign(this, applyDefaults(BPTstatic.defaults.goods, goodsData));
306306

307307
if (this.id === undefined)
308308
throw('Goods must have an id property set.');

classes/140-DiceRoll.gs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
class DiceRoll {
55
constructor(quantity = false, numberOfSides = false, customSides = false) {
66
// Add default settings, then override by any provided arguments.
7-
Object.assign(this, global.defaults.diceRoll);
7+
Object.assign(this, BPTstatic.defaults.diceRoll);
88
if (quantity) this.quantity = quantity;
99
if (numberOfSides) this.numberOfSides = numberOfSides;
1010
if (customSides) this.customSides = customSides;

0 commit comments

Comments
 (0)