-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutil.js
158 lines (134 loc) · 4.2 KB
/
util.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/**
* @file Utility functions. Include this file before others.
* @author Michael Pascale
*/
/**
* Display an alert with a generic error message. Log details to the console.
* @param {*} msg
*/
function Fatal(msg) {
alert('An error has occured.\n\nIf you are a study participant, please leave the study and report this issue to the researcher.');
console.log(msg);
throw new Error('Execution Aborted.');
}
/**
* Convert a string representing seconds, minutes, or hours to milliseconds.
* @param {Number | String} str - String representing some amount of time with
* units or a raw number of milliseconds.
* @return {Number} - Number of milliseconds.
*/
function toMilliseconds(str) {
if (typeof str === 'number') return str;
if (typeof str === 'string') {
if (/^[\d.]+(ms)*$/.test(str)) return parseFloat(str);
if (/^[\d.]+(s|sec|secs)$/.test(str)) return parseFloat(str) * 1000;
if (/^[\d.]+(m|min|mins)$/.test(str)) return parseFloat(str) * 60000;
if (/^[\d.]+(h|hr|hrs)$/.test(str)) return parseFloat(str) * 3600000;
}
Fatal(`Cannot convert value "${str}" to milliseconds.`);
}
/**
* Get the coordinates of some vertical and horizontal fraction of a canvas.
* @param {Number} px
* @param {Number} py
* @param {HTMLCanvasElement} canvas
* @return {Number[]}
*/
function pct2px(px, py, canvas) {
return [px * canvas.width, py * canvas.height];
}
/**
* Get the global coordinates relative to a sprite.
* @param {Number} x - X-coordinate relative to sprite.
* @param {Number} y - Y-coordinate relative to sprite.
* @param {Sprite} sprite
* @return {Number[]}
*/
function relpx(x, y, sprite) {
return [sprite.dx + x, sprite.dy + y];
}
/**
* Pick an item from a distribution other than that given.
* @param {*} item - The value to exclude.
* @param {*[]} vals - List of values to choose from.
* @param {Number[]} dist - The probability of each value being chosen.
* @return {*}
*/
function pickAnother(item, vals, dist) {
let ret;
do {
ret = pickFromDist(vals, dist);
} while (ret.id == item.id);
return ret;
}
/**
* Pick an item from a distribution.
* @param {*[]} vals - List of values to choose from.
* @param {Number[]} dist - The probability of each value being chosen.
* @return {*}
*/
function pickFromDist(vals, dist) {
const cumulatives = new Array(dist.length);
const total = dist.reduce((sum, curr, i) => cumulatives[i] = sum + curr, 0);
const n = Math.random() * total;
return vals[cumulatives.findIndex(p => (p >= n))];
}
function makeDist(vals, prob) {
// prob is probability first element is picked.
const pOther = (1 - prob) / vals.length;
let dist = vals.map((x, i) => i === 0 ? prob : pOther);
return dist;
}
function norm(m, r, x = Math.random()) {
const e = 2.71828;
const pi = 3.14159;
const a = 1 / (r * Math.sqrt(2 * pi));
const b = -1 * ((x - m)*(x - m)) / (2 * r * r);
const c = Math.pow(e, b);
return a * c;
}
function skewedRandomTime(min, max) {
const t = [];
for (let i = 0; i <= max - min; i++)
t[i] = min + i;
return pickFromDist(t, t.map((x,i) => norm(0.2, 0.3, i/t.length)));
}
function range(min, max) {
const t = [];
for (let i = 0; i <= max - min; i++)
t[i] = min + i;
return t;
}
function noise() {
return Math.random() - 0.5;
}
// Class to generate non repeating "ids" for the confederates.
function ridgen() {
this.existing = new Set();
this.rig = function () {
let n;
do {
n = ('000' + Math.floor(Math.random() * 390 + 10)).slice(-3);
} while (this.existing.has(n));
return n;
};
}
self.rig = new ridgen();
function sum (list) {
return list.reduce((sum, curr) => sum + curr, 0);
}
/**
* Position the confederates in a half circle.
* @param {Confederate[]} confederates
* @param {Number} r
* @param {Number} x
* @param {Number} y
*/
function positionConfederates(confederates, r, x, y) {
// console.log('Confederates:', x, y);
confederates.forEach((c, i) => {
const angle =
(i + 1) * Math.PI / (confederates.length + 1) + Math.PI / 2;
c.setPosition(x - r * Math.sin(angle), y + r * Math.cos(angle));
});
}