-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmain.js
343 lines (314 loc) · 11.6 KB
/
main.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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
/**
*
display the delta for each stock
display a notice that the trade was successful
display total portfolio value
style # shares like price in table
only show stocks in the table that we've introduced so far
display note explaining what happened as a result of the last turn
don't let events repeat
highlight terms in info
come up with more terms
introduce more trading concepts
introduce stock personalities
You enter a lab. Professor Oak is standing over a table. There are two stocks on a table: BEER and LOVE. Your cousin Gary has been here already and taken DRUG, the third stock. Which stock do you want to take?
You encountered wild LOVE. LOVE wants to fight! BEER used confusion! BLUE used dividend! BLUE used transform! BLUE is now RED! DRUG used depression! BUBL used ponzi scheme! LOVE used split!
Gary is challenging your portfolio to a fight! Gary uses insider information! His stock prices go up 10%! BUBL used disruptive technology! Gary's stock is now obsolete! Critical hit! Gary counters by lobbying congress to pass SOPA! Booo, Gary.
*/
var page = 0, currentTurn = 0, money = 10000;
var stocks = {
'BEER': new stock('BEER', 20),
'BLUE': new stock('BLUE', 20),
'BUBL': new stock('BUBL', 20),
'DRUG': new stock('DRUG', 20),
'LOVE': new stock('LOVE', 20),
};
var turnEvent;
$(document).ready(function() {
$('td.cash + td').html(money);
var submitButton = null;
$('#controls').submit(function(e) {
if (submitButton == 'buy') {
buy();
}
else if (submitButton == 'sell') {
sell();
}
e.preventDefault();
}).on('keyup mouseup', function(e) {
submitButton = e.target.name;
});
$('#continue').submit(function(e) {
if (page == 'congrats') {
page = 'game';
$.get('index.html', function(data) {
$('#content').html($(data).find('#content'));
drawAmounts();
});
drawAmounts();
return false;
}
else if (page == 'game') {
currentTurn++;
turn();
drawAmounts();
if (currentTurn == 5) {
$.get('congrats.html', function(data) {
$('#content').html($(data).find('#content'));
drawAmounts();
$('#controlWrapper, #continue').hide();
});
}
return false;
}
else {
page++;
if (page == 4) {
page = 'congrats';
}
$.get('training_'+ page +'.html', function(data) {
$('#content').html($(data).find('#content'));
if (page == 2) {
$('#stock').append('<option value="LOVE">LOVE</option>');
$('#controlWrapper').show();
}
else if (page == 3) {
stocks.LOVE.changeValue(stocks.LOVE.value + 2);
$('#stock option[value="BEER"]').after('<option value="BUBL">BUBL</option>');
}
else if (page == 'congrats') {
stocks.BUBL.changeValue(stocks.BUBL.value + 1);
$('#stock option[value="BEER"]').after('<option value="BLUE">BLUE</option>');
$('#stock option[value="BUBL"]').after('<option value="DRUG">DRUG</option>');
}
drawAmounts();
});
return false;
}
e.preventDefault();
});
$('#continue').submit();
stocks['BEER'].buy(money / stocks['BEER'].value);
drawAmounts();
});
// STOCKS ---------------------------------------------------------------------
function stock(name, value) {
this.amount = 0;
this.name = name;
this.value = value;
this.allValues = [value];
this.changeValue = function(newValue) {
this.allValues.push(newValue);
this.value = newValue;
}
this.buy = function(amount) {
var cost = amount * this.value;
if (cost <= money) {
money -= cost;
this.amount += amount;
$('td.cash + td').html(money);
drawAmounts();
return true;
}
return Math.floor(money / this.value);
}
this.sell = function(amount) {
if (amount <= this.amount) {
this.amount -= amount;
money += amount * this.value;
$('td.cash + td').html(money);
drawAmounts();
return true;
}
return this.amount;
}
}
function buy() {
var values = validate();
if (values) {
var v = stocks[values.name].buy(values.amount);
if (v !== true) {
alert('You only have enough money to buy '+ v +' share'+ (v == 1 ? '' : 's') +'.');
}
}
}
function sell() {
var values = validate();
if (values) {
var v = stocks[values.name].sell(values.amount);
if (v !== true) {
alert('You only have '+ v +' share'+ (v == 1 ? '' : 's') +' to sell.');
}
}
}
function validate() {
var val = parseInt($('#amount').val());
if (val == NaN || val < 1) {
alert('The number of shares of stock you want to trade must be a positive integer.');
$('#amount').addClass('error');
return false;
}
else {
$('#amount').removeClass('error');
}
var name = $('#stock').val();
if (!stocks[name]) {
$('#stock').addClass('error');
return false;
}
else {
$('#stock').removeClass('error');
}
return {'name': name, 'amount': val};
}
function drawAmounts() {
var $tbody = $('#stocks tbody');
$tbody.empty();
for (name in stocks) {
if (stocks.hasOwnProperty(name))
$tbody.append('<tr><td class="stock">'+ name +'</td><td class="value">'+ stocks[name].value +'</td><td class="amount">'+ stocks[name].amount +'</td></tr>');
}
$tbody.append('<tr><td class="stock cash">Cash</td><td class="value">'+ money +'</td><td class="amount"></td></tr>');
}
// UTILITIES ------------------------------------------------------------------
function getRandBetween(lo, hi) {
return parseInt(Math.floor(Math.random()*(hi-lo+1))+lo);
}
Array.prototype.remove = function(item) {
var i = $.inArray(item, this);
if (i === undefined || i < 0) return undefined;
return this.splice(i, 1);
};
Array.prototype.getRandomElement = function() {
if (this.length == 0)
return undefined;
var i = getRandBetween(0, this.length-1);
return this[i];
}
Object.prototype.keys = function(){
var keys = [];
for (var key in this) {
if (this.hasOwnProperty(key))
keys.push(key);
}
return keys;
}
// POST-TRAINING --------------------------------------------------------------
function event(description, delta, note, stockName) {
this.description = description;
this.origStockName = stockName;
this.stockName = function() {
if (this.origStockName) {
return this.origStockName;
}
return stocks.keys().getRandomElement();
};
this.deltaFunc = delta;
this.delta = 0;
this.getDelta = function() {
this.delta = this.deltaFunc();
return this.delta;
};
this.note = note;
}
function turn() {
calculateNewPrices();
turnEvent = eventTypes.getRandomElement();
$('.info').html(turnEvent.description());
drawAmounts();
}
function calculateNewPrices() {
for (stock in stocks) {
if (stocks.hasOwnProperty(stock)) {
var stockValue = stocks[stock].value;
if (turnEvent && stock == turnEvent.stockName()) {
stocks[stock].changeValue(stockValue + turnEvent.getDelta());
}
else {
stocks[stock].changeValue(stockValue + getRandBetween(-.1*stockValue, .1*stockValue));
}
}
}
}
var eventTypes = [
new event(function() {
return this.stockName() + ' is releasing their quarterly earnings report tomorrow. Wall street analysts think they will hit their predictions, but you can never be sure.';
}, function() {
var stockPercent = stocks[this.stockName()].value * 0.1;
return getRandBetween(-stockPercent*.5, stockPercent*1.5);
}, function() {
if (this.delta < 0) {
return this.stockName() + ' missed their earnings predictions. Stock price fell by ' + this.delta + '%.';
}
else if (this.delta > 0) {
return this.stockName() + ' exceeded their earnings predictions. Stock price rose by ' + this.delta + '%.';
}
else {
return this.stockName() + ' exactly hit their earnings predictions. Stock price remained the same.';
}
}, null),
new event(function() {
return this.stockName() + ' is holding a surprise press release tomorrow. The news could be good or bad.';
}, function() {
var stockPercent = stocks[this.stockName()].value * 0.15;
return getRandBetween(-stockPercent, stockPercent);
}, function() {
if (this.delta < 0) {
return 'One of ' + this.stockName() + '\'s key executives must resign due to health reasons. Stock price fell by ' + this.delta + '%.';
}
else if (this.delta > 0) {
return this.stockName() + ' unveiled a new product for a rapidly growing market. Stock price rose by ' + this.delta + '%.';
}
else {
return this.stockName() + ' announced they will sponsor PennApps in the fall of 2012. Wall Street is unsure how it will play out. Stock price remained the same.';
}
}, null),
new event(function() {
return this.stockName() + '\'s largest competitor just went bankrupt. Generally, analysts see situations like this as an opportunity to gain market share. However, it may also be seen as a sign of a weak or struggling industry.';
}, function() {
var stockPercent = stocks[this.stockName()].value * 0.1;
return getRandBetween(-stockPercent, stockPercent*1.5);
}, function() {
if (this.delta < 0) {
return 'A large number of analysts think ' + this.stockName() + 'may be the next to file for Chapter 11. Stock price fell by ' + this.delta + '%.';
}
else if (this.delta > 0) {
return 'A large number of analysts think ' + this.stockName() + ' is strategically poised to capture market share from its bankrupt competitor. Stock price rose by ' + this.delta + '%.';
}
else {
return 'Analysts\'s opinions were split evenly on the news. ' + this.stockName() + '\'s stock price remained the same.';
}
}, null),
new event(function() {
return 'Rumors have spread that ' + this.stockName() + '\'s CFO cooked the books. If these allegations prove true, they could be devastating.';
}, function() {
var stockPercent = stocks[this.stockName()].value * 0.1;
return getRandBetween(-stockPercent*2.5, stockPercent);
}, function() {
if (this.delta < 0) {
return this.stockName() + '\'s CFO was indicted by the SEC. Stock price fell by ' + this.delta + '%.';
}
else if (this.delta > 0) {
return 'The rumors turned out to be false. ' + this.stockName() + '\'s stock price rose by ' + this.delta + '%.';
}
else {
return 'The issue was dwarfed by an even larger scandal at Halliburton. ' + this.stockName() + '\'s stock price remained the same.';
}
}, null),
new event(function() {
return 'China\'s political leaders are meeting to determine monetary policy. ' + this.stockName() + ' buys key supplies from China. If the Yuan strengethens, ' + this.stockName() + ' will have to pay more to manufacture its products.';
}, function() {
var stockPercent = stocks[this.stockName()].value * 0.1;
return getRandBetween(-stockPercent*2, stockPercent);
}, function() {
if (this.delta < 0) {
return 'Due to U.S. pressure, China allowed its currency to partially elevate. ' + this.stockName() + '\'s stock price fell by ' + this.delta + '%.';
}
else if (this.delta > 0) {
return 'The Chinese government kept the Yuan pegged to the dollar. In response, ' + this.stockName() + '\'s stock price rose by ' + this.delta + '%.';
}
else {
return 'The Chinese government maintained the current exchange rate, but indicated they\'d be willing to change it in the future. ' + this.stockName() + '\'s stock price remained the same.';
}
}, null),
];