mirror of
https://github.com/wassname/cardsforscience.git
synced 2026-09-11 12:00:40 +08:00
Simulated rules so they are winnable, added win and lose
This commit is contained in:
+1
-1
@@ -49,7 +49,7 @@ var analytics = module.exports =
|
||||
ga('create', Helpers.analytics,'auto');
|
||||
ga('set', { 'appName': 'Cards For Science', 'appId': '', 'appVersion': '0.6' });
|
||||
ga('set', 'anonymizeIp', true);
|
||||
ga('send','pageview');
|
||||
// ga('send','pageview');// angulartics
|
||||
}
|
||||
|
||||
|
||||
|
||||
+111
-78
@@ -7,13 +7,14 @@
|
||||
var jquery = require("jquery");
|
||||
var jqueryUi = require("jquery-ui");
|
||||
var jqueryUiTouchPunch = require("jquery-ui-touch-punch");
|
||||
var jqueryCookie = require("js-cookie");
|
||||
var jsCookie = require("js-cookie");
|
||||
|
||||
var angular = require("angular");
|
||||
var angularDragdrop = require("angular-dragdrop");
|
||||
var angularAnimate = require("angular-animate");
|
||||
var angulartics = require('angulartics');
|
||||
var angularticsGoogleAnalytics = require('angulartics-google-analytics');
|
||||
var ngAlertify = require("alertify.js/dist/js/ngAlertify.js");
|
||||
|
||||
//app
|
||||
var ObjectStorage = require("js/storage");
|
||||
@@ -22,11 +23,12 @@ var GameObjects = require("js/gameobjects");
|
||||
var analytics = require("js/analytics");
|
||||
var Game = require("js/game");
|
||||
var Rules = require("js/rules.js");
|
||||
var UI = require("js/ui.js");
|
||||
|
||||
var app = (function (Helpers,analytics,Game,Rules) {
|
||||
Helpers.validateSaveVersion();
|
||||
|
||||
var app = angular.module('cardsForScience', ['ngDragDrop','ngAnimate','angulartics', angularticsGoogleAnalytics]);
|
||||
var app = angular.module('cardsForScience', ['ngDragDrop','ngAnimate','angulartics', angularticsGoogleAnalytics,"ngAlertify"]);
|
||||
|
||||
// config
|
||||
app.config(function ($analyticsProvider) {
|
||||
@@ -160,7 +162,7 @@ var app = (function (Helpers,analytics,Game,Rules) {
|
||||
game.lab = lab;
|
||||
game.allObjects.lab = lab;
|
||||
var promise = game.load($http, $q);
|
||||
game.init();
|
||||
game.reset();
|
||||
// return promise;
|
||||
return game;
|
||||
};
|
||||
@@ -259,8 +261,8 @@ var app = (function (Helpers,analytics,Game,Rules) {
|
||||
function TableController($scope, game, lab, $filter) {
|
||||
var vm = this;
|
||||
vm.cards = detector.cards;
|
||||
vm.rule = '';
|
||||
vm.hints = [];
|
||||
vm.ruleInfo = game.ruleInfo;
|
||||
vm.hints = game.hints;
|
||||
vm.limit = -12;
|
||||
vm.hintCost = 10;
|
||||
vm.ruleCost = 300;
|
||||
@@ -279,8 +281,10 @@ var app = (function (Helpers,analytics,Game,Rules) {
|
||||
var result = game.onDrop(event, ui, game);
|
||||
};
|
||||
vm.revealRule = function () {
|
||||
vm.rule = game.rule.describe();
|
||||
lab.state.score -= vm.ruleCost;
|
||||
if (vm.ruleInfo.length===0){
|
||||
vm.ruleInfo.push(game.rule.describe());
|
||||
lab.state.score -= vm.ruleCost;
|
||||
};
|
||||
};
|
||||
vm.revealHint = function () {
|
||||
var hint = game.rule.nextHint();
|
||||
@@ -294,61 +298,17 @@ var app = (function (Helpers,analytics,Game,Rules) {
|
||||
app.controller('TableController', TableController);
|
||||
|
||||
|
||||
function LabController($interval, game, lab) {
|
||||
// todo give workers instead of game
|
||||
var vm = this;
|
||||
vm.lab = lab;
|
||||
vm.showDetectorInfo = function () {
|
||||
if (!vm._detectorInfo) {
|
||||
vm._detectorInfo = Helpers.loadFile('html/detector.html');
|
||||
}
|
||||
UI.showModal('Detector', vm._detectorInfo);
|
||||
};
|
||||
};
|
||||
LabController.$inject = ['$interval', 'game', 'lab'];
|
||||
app.controller('LabController', LabController);
|
||||
|
||||
|
||||
function RulesController($scope, game, lab) {
|
||||
function RulesController($scope, game, lab,$analytics,alertify) {
|
||||
var vm = this;
|
||||
// present just a few hypothesis
|
||||
var rules = Rules.rules.map(function (r) {
|
||||
return angular.copy(r);
|
||||
|
||||
// emit event track (with category and label properties for GA)
|
||||
$analytics.eventTrack('rule', {
|
||||
category: 'rule', label: game.rule.describe()
|
||||
});
|
||||
rules = _.sampleSize(rules, 2);
|
||||
if (!_.find(rules, {
|
||||
description: game.rule.description
|
||||
})) {
|
||||
var rule = angular.copy(game.rule);
|
||||
rule.setOptions({}); // reset the value of this copy to not give away;
|
||||
rules.push(rule);
|
||||
} else {
|
||||
rules.push(angular.copy(_.sample(Rules.rules)));
|
||||
}
|
||||
vm.rules = _.shuffle(rules);
|
||||
|
||||
// or present them without options?
|
||||
var rules2 = Rules.rules.map(function (r) {
|
||||
var rule = angular.copy(r);
|
||||
rule.randomize();
|
||||
return rule;
|
||||
});
|
||||
rules2 = _.sampleSize(rules, 4);
|
||||
|
||||
// add the real rule and a couple of variations
|
||||
var rule = angular.copy(game.rule);
|
||||
rules2.push(rule);
|
||||
var rule = angular.copy(game.rule);
|
||||
rule.randomize();
|
||||
rules2.push(rule);
|
||||
var rule = angular.copy(game.rule);
|
||||
rule.randomize();
|
||||
rules2.push(rule);
|
||||
|
||||
// clean and add to controller
|
||||
rules2 = _.uniq(rules2);
|
||||
rules2 = _.shuffle(rules2);
|
||||
vm.rules2 = rules2;
|
||||
vm.hypotheses = game.hypotheses;
|
||||
|
||||
vm.upgrades = game.upgrades;
|
||||
vm.isVisible = function (upgrade) {
|
||||
@@ -357,15 +317,10 @@ var app = (function (Helpers,analytics,Game,Rules) {
|
||||
vm.isAvailable = function (upgrade) {
|
||||
return upgrade.isAvailable(lab, game.allObjects);
|
||||
};
|
||||
vm.upgrade = function (upgrade) {
|
||||
if (upgrade.buy(lab, game.allObjects)) {
|
||||
UI.showUpdateValue("#update-funding", upgrade.cost);
|
||||
}
|
||||
};
|
||||
/** return a class based on none right or wrong guessed **/
|
||||
vm.isGuessed = function(rule){
|
||||
if (rule.state.guessed===true) return 'bg-success';
|
||||
else if (rule.state.guessed===false) return 'bg-danger';
|
||||
if (rule.guessed===true) return 'bg-success';
|
||||
else if (rule.guessed===false) return 'bg-danger';
|
||||
else return '';
|
||||
|
||||
};
|
||||
@@ -377,17 +332,47 @@ var app = (function (Helpers,analytics,Game,Rules) {
|
||||
if (sameRule && sameOpts) {
|
||||
// right!
|
||||
lab.state.score += 200;
|
||||
lab.state.rulesGuessed.push({
|
||||
key: game.rule.key,
|
||||
options: game.rule.options,
|
||||
description: game.rule.describe(),
|
||||
});
|
||||
if (!rule.state) rule.state={};
|
||||
rule.state.guessed=true;
|
||||
rule.guessed=true;
|
||||
|
||||
alertify.alert(
|
||||
'You have won using inductive logic! <p> <p> Play again?',
|
||||
function(event){
|
||||
event.preventDefault();
|
||||
// ObjectStorage.clear();
|
||||
// $window.location.reload(true); /// reloads are better for ads?
|
||||
game.reset();
|
||||
// since this confirmation was away from the dom we need to
|
||||
// manually refresh
|
||||
$scope.$apply();
|
||||
},function(){}
|
||||
);
|
||||
} else {
|
||||
lab.state.score -= 200;
|
||||
rule.state.guessed=false;
|
||||
rule.guessed=false;
|
||||
lab.state.rulesFailed.push({
|
||||
key: rule.key,
|
||||
options: rule.options,
|
||||
description: rule.describe(),
|
||||
});
|
||||
}
|
||||
|
||||
console.log('guess', arguments);
|
||||
|
||||
|
||||
// vm.winDialouge = function () {
|
||||
// if (!vm._winDialouge) {
|
||||
// vm._winDialouge = Helpers.loadFile('html/win.html');
|
||||
// }
|
||||
// UI.showModal('Win', vm._winDialouge);
|
||||
// };
|
||||
};
|
||||
};
|
||||
RulesController.$inject = ['$scope', 'game', 'lab'];
|
||||
RulesController.$inject = ['$scope', 'game', 'lab','$analytics','alertify'];
|
||||
app.controller('RulesController', RulesController);
|
||||
|
||||
function AchievementsController($scope, game, lab) {
|
||||
@@ -402,35 +387,83 @@ var app = (function (Helpers,analytics,Game,Rules) {
|
||||
AchievementsController.$inject = ['$scope', 'game', 'lab'];
|
||||
app.controller('AchievementsController', AchievementsController);
|
||||
|
||||
function SaveController($scope, $interval, $window, game, lab) {
|
||||
function SaveController($scope, $interval, $window, alertify, game, lab) {
|
||||
var vm = this;
|
||||
game.lastSaved = new Date().getTime();
|
||||
vm.lastSaved = game.lastSaved;
|
||||
;
|
||||
|
||||
vm.saveNow = function () {
|
||||
var saveTime = new Date().getTime();
|
||||
lab.state.time += saveTime - game.lastSaved;
|
||||
game.save();
|
||||
game.lastSaved = saveTime;
|
||||
vm.lastSaved = game.lastSaved;
|
||||
|
||||
// if (lab.state.score<0){
|
||||
// alertify.alert(
|
||||
// 'Your score is below zero, so you lost :( Want to try a different rule?',
|
||||
// function(event){
|
||||
// event.preventDefault();
|
||||
// // ObjectStorage.clear();
|
||||
// // $window.location.reload(true); /// reloads are better for ads?
|
||||
// game.reset();
|
||||
// // since this confirmation was away from the dom we need to
|
||||
// // manually refresh
|
||||
// $scope.$apply();
|
||||
// },function(){}
|
||||
// );
|
||||
// }
|
||||
|
||||
};
|
||||
vm.restart = function () {
|
||||
if ($window.confirm(
|
||||
'Do you really want to restart the game? All progress will be lost.'
|
||||
)) {
|
||||
ObjectStorage.clear();
|
||||
$window.location.reload(true);
|
||||
}
|
||||
console.log('restart');
|
||||
alertify.confirm(
|
||||
'Do you really want to restart the game? All progress will be lost.',
|
||||
function(event){
|
||||
event.preventDefault();
|
||||
// ObjectStorage.clear();
|
||||
// $window.location.reload(true); /// reloads are better for ads?
|
||||
game.reset();
|
||||
// since this confirmation was away from the dom we need to
|
||||
// manually refresh
|
||||
$scope.$apply();
|
||||
},function(){}
|
||||
);
|
||||
};
|
||||
$interval(vm.saveNow, 10000);
|
||||
};
|
||||
SaveController.$inject = ['$scope', '$interval', '$window', 'game', 'lab'];
|
||||
SaveController.$inject = ['$scope', '$interval', '$window', 'alertify', 'game', 'lab'];
|
||||
app.controller('SaveController', SaveController);
|
||||
|
||||
function StatsController($scope, lab) {
|
||||
function StatsController($scope, lab,game,alertify) {
|
||||
var vm = this;
|
||||
vm.lab = lab;
|
||||
vm.lost=false;
|
||||
|
||||
|
||||
$scope.$watch('lc.lab.state.score', function (newValue, oldValue) {
|
||||
if (newValue<0&&!vm.lost){
|
||||
vm.lost=true;
|
||||
alertify.alert(
|
||||
'<p>You lost :( <p> Play again? <p><p>P.S. The rule was: <p>"'+game.rule.describe()+'"',
|
||||
function(event){
|
||||
event.preventDefault();
|
||||
// ObjectStorage.clear();
|
||||
// $window.location.reload(true); /// reloads are better for ads?
|
||||
game.reset();
|
||||
// since this confirmation was away from the dom we need to
|
||||
// manually refresh
|
||||
$scope.$apply();
|
||||
vm.lost=false;
|
||||
|
||||
},function(){}
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
};
|
||||
StatsController.$inject = ['$scope', 'lab'];
|
||||
StatsController.$inject = ['$scope', 'lab','game','alertify'];
|
||||
app.controller('StatsController', StatsController);
|
||||
|
||||
analytics.init();
|
||||
|
||||
+96
-68
@@ -7,6 +7,7 @@ var GameObjects = require("js/gameobjects.js");
|
||||
var Rules = require("js/rules.js");
|
||||
var cards = require("json/cards.json");
|
||||
var achievements = require("json/achievements.json");
|
||||
var ruleSimulations = require("json/simulations.json");
|
||||
|
||||
var Game = module.exports =(function (Helpers, GameObjects, ObjectStorage,Rules,cards,achievements) {
|
||||
'use strict';
|
||||
@@ -21,11 +22,13 @@ var Game = module.exports =(function (Helpers, GameObjects, ObjectStorage,Rules,
|
||||
// lab: this.lab
|
||||
};
|
||||
this.loaded = false;
|
||||
this.rules = Rules.rules;
|
||||
this.rule=undefined;
|
||||
|
||||
this.hypotheses = [];
|
||||
this.lastCards= [];
|
||||
this.hints=[];
|
||||
this.ruleInfo=[];
|
||||
this.incorrectCards= [];
|
||||
this.rule=undefined;
|
||||
this.rules=Rules.rules;
|
||||
this.Rule=Rules.Rule;
|
||||
};
|
||||
@@ -36,56 +39,9 @@ var Game = module.exports =(function (Helpers, GameObjects, ObjectStorage,Rules,
|
||||
return;
|
||||
}
|
||||
|
||||
// I know synchronous requests are bad as they will block the browser.
|
||||
// However, I don't see any other reasonable way to do this in order to
|
||||
// make it work with Angular. If you know a way, let me know, and I'll
|
||||
// give you a beer. - Kevin
|
||||
this.cards = cards; //Helpers.loadFile('json/cards.json');
|
||||
this.achievements = require("json/achievements.json"); //Helpers.loadFile('./json/achievements.json');
|
||||
|
||||
// function successCallback(response) {
|
||||
// return angular.fromJson(response.data);
|
||||
// }
|
||||
//
|
||||
// function errorCallback(response) {
|
||||
// return console.error('Could not get url', response.statusText, response);
|
||||
// }
|
||||
// return $q.all(
|
||||
// $http.get('json/cards.json', {
|
||||
// transformResponse: angular.fromJson
|
||||
// })
|
||||
// .then(function (response) {
|
||||
// return self.cards = response.data;
|
||||
// }),
|
||||
// $http.get('json/workers.json', {
|
||||
// transformResponse: angular.fromJson
|
||||
// })
|
||||
// .then(function (response) {
|
||||
// return self.workers = response.data;
|
||||
// }),
|
||||
// $http.get('json/upgrades.json', {
|
||||
// transformResponse: angular.fromJson
|
||||
// })
|
||||
// .then(
|
||||
// function (response) {
|
||||
// return self.upgrades = response.data;
|
||||
// }),
|
||||
// $http.get('json/achievements.json', {
|
||||
// transformResponse: angular.fromJson
|
||||
// })
|
||||
// .then(
|
||||
// function (response) {
|
||||
// return self.achievements = response.data;
|
||||
// }),
|
||||
// $http.get('json/keywords.json', {
|
||||
// transformResponse: angular.fromJson
|
||||
// })
|
||||
// .then(
|
||||
// function (response) {
|
||||
// return self.keywords = response.data;
|
||||
// })
|
||||
// ).then(function () {
|
||||
|
||||
// Turn JSON files into actual game objects and fill map of all objects
|
||||
var makeGameObject = function (type, object) {
|
||||
// It's okay to define this function here since load is only called
|
||||
@@ -102,54 +58,126 @@ var Game = module.exports =(function (Helpers, GameObjects, ObjectStorage,Rules,
|
||||
function (a) {
|
||||
return makeGameObject(GameObjects.Achievement, a);
|
||||
});
|
||||
// Load states from local store
|
||||
for (var key in self.allObjects) {
|
||||
var o = self.allObjects[key];
|
||||
o.loadState(ObjectStorage.load(key));
|
||||
}
|
||||
|
||||
|
||||
// put cards in extended array with utility methods
|
||||
self.Card = new GameObjects.Cards();
|
||||
self.Card.push.apply(self.Card, self.cards);
|
||||
self.cards = self.Card;
|
||||
|
||||
// add rules to load and save states
|
||||
self.rules.map(function(o){
|
||||
self.allObjects[o.key] = o;
|
||||
});
|
||||
|
||||
// TODO save and load lastCards and incorrectCards
|
||||
|
||||
// Load states from local store
|
||||
for (var key in self.allObjects) {
|
||||
var o = self.allObjects[key];
|
||||
o.loadState(ObjectStorage.load(key));
|
||||
}
|
||||
|
||||
self.loaded = true;
|
||||
return self;
|
||||
};
|
||||
|
||||
Game.prototype.init = function () {
|
||||
Game.prototype.reset = function () {
|
||||
// setup game
|
||||
this.rule = _.sample(Rules.rules);
|
||||
this.rule.randomize();
|
||||
this.rule = this.newRule();
|
||||
|
||||
// check if we have any cards in hand
|
||||
// var totalElements = _(self.cards).map('state.amount').sum();
|
||||
// if (totalElements<1) self.dealHand();
|
||||
this.dealHand();
|
||||
|
||||
// deal first card
|
||||
// TODO make sure these follow rule
|
||||
|
||||
// deal new initial cards
|
||||
this.lastCards.splice(0,this.lastCards.length);
|
||||
this.lastCards.push.apply(this.lastCards,_.sampleSize(this.cards,3));
|
||||
for (var i = 0; i < this.lastCards.length; i++) {
|
||||
this.incorrectCards[i]=[];
|
||||
}
|
||||
|
||||
this.ruleInfo.splice(0,this.ruleInfo.length);
|
||||
this.hints.splice(0,this.hints.length);
|
||||
|
||||
// empty incorrect cards
|
||||
this.incorrectCards.splice(0,this.incorrectCards.length);
|
||||
this.incorrectCards.push([]);
|
||||
this.incorrectCards.push([]);
|
||||
this.incorrectCards.push([]);
|
||||
|
||||
// reset score
|
||||
this.lab.state.score = 200;
|
||||
return self;
|
||||
|
||||
// new set of hypothes
|
||||
this.hypotheses=this.genHypotheses();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Game.prototype.genHypotheses = function () {
|
||||
// get some hypotheses
|
||||
var hypo=[];
|
||||
|
||||
// a random 2, 2 variations of each
|
||||
for (var i = 0; i < 3; i++) {
|
||||
var rule = _.sample(this.rules);
|
||||
rule = angular.copy(rule);
|
||||
rule.randomize();
|
||||
hypo.push(rule);
|
||||
rule = angular.copy(rule);
|
||||
rule.randomize();
|
||||
hypo.push(rule);
|
||||
}
|
||||
|
||||
// add the real rule
|
||||
var rule = angular.copy(this.rule);
|
||||
hypo.push(rule);
|
||||
|
||||
// and a variation of the real rule
|
||||
var rule = angular.copy(this.rule);
|
||||
rule.randomize();
|
||||
hypo.push(rule);
|
||||
|
||||
// clean and remember
|
||||
hypo = _.uniq(hypo);
|
||||
hypo = _.shuffle(hypo);
|
||||
|
||||
// empty old ones
|
||||
this.hypotheses.splice(0,this.hypotheses.length);
|
||||
// put in new ones
|
||||
for (var i = 0; i < hypo.length; i++) {
|
||||
this.hypotheses.push(hypo[i]);
|
||||
}
|
||||
return this.hypotheses;
|
||||
};
|
||||
|
||||
Game.prototype.newRule = function () {
|
||||
var okRules = _.filter(ruleSimulations,function(s){
|
||||
return s.ratioRight>0.1&&s.ratioRight<0.6;
|
||||
});
|
||||
// choose and ok rule
|
||||
var ruleConfig = _.sample(okRules);
|
||||
// now find the rule and set these options
|
||||
var rule = _.find(this.rules,{key:ruleConfig.key});
|
||||
var options = ruleConfig.options;
|
||||
if (typeof options==="string") options = JSON.parse(options);
|
||||
rule.setOptions(options);
|
||||
return this.rule = rule;
|
||||
};
|
||||
|
||||
Game.prototype.dealHand = function (n) {
|
||||
n=n||12;
|
||||
var hand=_.sampleSize(this.cards,n);
|
||||
|
||||
var sample=_.sampleSize(this.cards,n);
|
||||
|
||||
// empty all cards
|
||||
this.cards.map(function(card){
|
||||
card.state.amount=0;
|
||||
});
|
||||
for (var i = 0; i < hand.length; i++) {
|
||||
var card = hand[i];
|
||||
// now increase the value of our sample
|
||||
for (var i = 0; i < sample.length; i++) {
|
||||
var card = sample[i];
|
||||
this.cards.get(card.key).state.amount++;
|
||||
}
|
||||
|
||||
};
|
||||
Game.prototype.onClick = function (event, ui) {
|
||||
var self=this;
|
||||
|
||||
+1
-106
@@ -29,7 +29,7 @@ var GameObjects = module.exports = (function () {
|
||||
}
|
||||
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
|
||||
s4() + '-' + s4() + s4() + s4();
|
||||
}
|
||||
};
|
||||
|
||||
/** @class Lab
|
||||
*/
|
||||
@@ -254,109 +254,6 @@ var GameObjects = module.exports = (function () {
|
||||
return this.state.amount -= 1;
|
||||
};
|
||||
|
||||
/** @class Worker
|
||||
* Implement an auto-clicker in the game.
|
||||
*/
|
||||
var Worker = function (obj) {
|
||||
GameObject.apply(this, [obj]);
|
||||
this.state.hired = 0;
|
||||
};
|
||||
|
||||
Worker.prototype = Object.create(GameObject.prototype);
|
||||
|
||||
Worker.prototype.constructor = Worker;
|
||||
|
||||
Worker.prototype.isVisible = function (lab) {
|
||||
if (!lab) {
|
||||
return false;
|
||||
}
|
||||
return this.state.hired > 0 ||
|
||||
lab.state.money >= this.state.cost * GLOBAL_VISIBILITY_THRESHOLD;
|
||||
};
|
||||
|
||||
Worker.prototype.isAvailable = function (lab) {
|
||||
if (!lab) {
|
||||
return false;
|
||||
}
|
||||
return lab.state.money >= this.state.cost;
|
||||
};
|
||||
|
||||
Worker.prototype.hire = function (lab) {
|
||||
if (lab && lab.buy(this.state.cost)) {
|
||||
this.state.hired++;
|
||||
var cost = this.state.cost;
|
||||
this.state.cost = Math.floor(cost * this.cost_increase);
|
||||
return cost;
|
||||
}
|
||||
return -1; // not enough money
|
||||
};
|
||||
|
||||
Worker.prototype.getTotal =
|
||||
function () {
|
||||
return this.state.hired * this.state.rate;
|
||||
};
|
||||
|
||||
/** @class Upgrade
|
||||
*/
|
||||
var Upgrade = function (obj) {
|
||||
GameObject.apply(this, [obj]);
|
||||
this.state.visible = false;
|
||||
this.state.used = false;
|
||||
};
|
||||
|
||||
Upgrade.prototype = Object.create(GameObject.prototype);
|
||||
|
||||
Upgrade.prototype.constructor = Upgrade;
|
||||
|
||||
Upgrade.prototype.meetsRequirements = function (allObjects) {
|
||||
if (!allObjects) {
|
||||
return false;
|
||||
}
|
||||
for (var i = 0; i < this.requirements.length; i++) {
|
||||
var req = this.requirements[i];
|
||||
if (allObjects[req.key].state[req.property] < req.threshold) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
Upgrade.prototype.isAvailable = function (lab, allObjects) {
|
||||
if (!lab || !allObjects) {
|
||||
return false;
|
||||
}
|
||||
return !this.state.used && lab.state.money >= this.cost &&
|
||||
this.meetsRequirements(allObjects);
|
||||
};
|
||||
|
||||
Upgrade.prototype.isVisible = function (lab, allObjects) {
|
||||
if (!lab || !allObjects) {
|
||||
return false;
|
||||
}
|
||||
if (!this.state.used &&
|
||||
(this.state.visible ||
|
||||
lab.state.money >= this.cost * GLOBAL_VISIBILITY_THRESHOLD &&
|
||||
this.meetsRequirements(allObjects))) {
|
||||
this._visible = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
Upgrade.prototype.buy = function (lab, allObjects) {
|
||||
if (lab && allObjects && !this.state.used && lab.buy(this.cost)) {
|
||||
for (var i = 0; i < this.targets.length; i++) {
|
||||
var t = this.targets[i];
|
||||
allObjects[t.key].state[t.property] *= this.factor || 1;
|
||||
allObjects[t.key].state[t.property] += this.constant || 0;
|
||||
}
|
||||
this.state.used = true; // How about actually REMOVING used upgrades?
|
||||
this.state.visible = false;
|
||||
return this.cost;
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
|
||||
/** @class Achievement
|
||||
*/
|
||||
@@ -394,8 +291,6 @@ var GameObjects = module.exports = (function () {
|
||||
return {
|
||||
Lab: Lab,
|
||||
Card: Card,
|
||||
Worker: Worker,
|
||||
Upgrade: Upgrade,
|
||||
Achievement: Achievement,
|
||||
Cards: Cards
|
||||
};
|
||||
|
||||
+75
-63
@@ -5,7 +5,7 @@
|
||||
if (!module) module=function(){};
|
||||
var chai;
|
||||
if (!chai){
|
||||
chair = require("chai");
|
||||
chai = require("chai");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -16,11 +16,41 @@ if (!chai){
|
||||
var Rules = module.exports = (function functionName(_,chai) {
|
||||
|
||||
|
||||
/** Generate all combination of arguments from array using functional programming instead of recursive
|
||||
* @param {Object} opts - An array or arrays with keys describing options [['Ben','Jade','Darren'],['Smith','Miller']]
|
||||
* @returns {Array} - An array of arrays e.g. [['Ben','Smith'],[..]]
|
||||
**/
|
||||
function cartesianProductOf(opts) {
|
||||
if (arguments.length>1) opts=arguments;
|
||||
return _.reduce(opts, function(a, b) {
|
||||
return _.flatten(_.map(a, function(x) {
|
||||
return _.map(b, function(y) {
|
||||
return x.concat([y]);
|
||||
});
|
||||
}), true);
|
||||
}, [ [] ]);
|
||||
};
|
||||
|
||||
|
||||
/** Generate all combination of arguments from objects using functional programming instead of recursive
|
||||
* @param {Object} opts - An object or arrays with keys describing options {firstName:['Ben','Jade','Darren'],lastName:['Smith','Miller']}
|
||||
* @returns {Array} - An array of objects e.g. [{firstName:'Ben',LastName:'Smith'},{..]
|
||||
**/
|
||||
function cartesianProductObj(optObj){
|
||||
var opts = _.values(optObj);
|
||||
var keys = _.keys(optObj);
|
||||
var combs = cartesianProductOf(opts);
|
||||
return _.map(combs,function(comb){
|
||||
return _.zipObject(keys,comb);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rule prototype
|
||||
* @param {String} key A short key
|
||||
* @param {String} description Description of the rule using angular templating from options
|
||||
* @param {Function} ruleFunc A function returning a true or a failure message or a error
|
||||
* @param {Function} ruleFunc A function returning a true or a failure message or a assertion error
|
||||
* @param {Object} optionDefaults Default options for the rule e.g. {n:1, parameter:'color'}.
|
||||
* @param {Object} optionDesc Object with object for each option
|
||||
* @param {Array} optionDesc[].possibleVals Array of possible values or empty if they are to many to be enumerated
|
||||
@@ -30,23 +60,44 @@ var Rules = module.exports = (function functionName(_,chai) {
|
||||
* `The rule uses <%= parameter %>` and for every parameter you can
|
||||
* use `The rule doesn't use <%= parameterUnused %>` to have each unused param substituted in.
|
||||
*/
|
||||
var Rule = function (description, ruleFunc, optionDefaults, optionDesc, hintTmpls) {
|
||||
var Rule = function (key, description, ruleFunc, optionDefaults, optionDesc, hintTmpls) {
|
||||
|
||||
// check inputs
|
||||
if (!(typeof (description) === 'string' || description instanceof String) || !description.length)
|
||||
throw new TypeError('description should be a non empty string');
|
||||
throw new TypeError('Description should be a non empty string');
|
||||
this.description = description;
|
||||
if (!(ruleFunc instanceof Function))
|
||||
throw new TypeError('ruleFunc should be a function');
|
||||
|
||||
this.key=key;
|
||||
this.ruleFunc = ruleFunc;
|
||||
this.optionDesc = optionDesc || {};
|
||||
this.options = this.optionDefaults = optionDefaults || {};
|
||||
this.hintTmpls = hintTmpls || [];
|
||||
|
||||
// init
|
||||
this.state = {};
|
||||
this.hintsUsed = 0;
|
||||
this.state = {
|
||||
hintsUsed: 0,
|
||||
wrongCards: 0,
|
||||
rightCards: 0,
|
||||
wrongGuesses: 0,
|
||||
rightGuesses: 0,
|
||||
};
|
||||
// used for template rendering
|
||||
this.otherOptions={nth:this.nth,lastn:this.lastn};
|
||||
// render hint templates
|
||||
this.hints = this.genHints();
|
||||
// work out all option combos, only takes a second
|
||||
this.optionsPossible=this.genOptions();
|
||||
};
|
||||
Rule.prototype.genOptions = function () {
|
||||
var possibleVals={};
|
||||
for (var prop in this.optionDesc) {
|
||||
if (this.optionDesc.hasOwnProperty(prop)) {
|
||||
possibleVals[prop]=this.optionDesc[prop].possibleVals;
|
||||
}
|
||||
}
|
||||
return this.optionsPossible=cartesianProductObj(possibleVals);
|
||||
};
|
||||
Rule.prototype.setOptions = function (options) {
|
||||
this.options = _.defaults(options, this.optionDefaults);
|
||||
@@ -98,56 +149,6 @@ var Rules = module.exports = (function functionName(_,chai) {
|
||||
Rule.prototype.describe = function () {
|
||||
return this.describeVariation(this.options);
|
||||
};
|
||||
// Rule.prototype.describeHtml = function (arguments) {
|
||||
// // we want template params where each options is replace with a select box
|
||||
// var tmplParams = {};
|
||||
//
|
||||
// for (var option in this.optionDesc) {
|
||||
// if (this.optionDesc.hasOwnProperty(option)) {
|
||||
// var vals = this.optionDesc[option].possibleVals;
|
||||
// if (vals) {
|
||||
// s = '<select name="' + option + '" ng-model="rule.options.' + option + '" class="form-control input-sm">\n';
|
||||
// for (var i = 0; i < vals.length; i++) {
|
||||
// s += '<option value="' + vals[i] + '">' + vals[i] + '</option>\n';
|
||||
// }
|
||||
// s += '</select>\n';
|
||||
// tmplParams[option] = s;
|
||||
// } else {
|
||||
// tmplParams[option] = option;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return _.template(this.description)(tmplParams);
|
||||
// };
|
||||
/** Generate angular template for this rule **/
|
||||
// Rule.prototype.describeNg = function (arguments) {
|
||||
//
|
||||
// // first put option name into this option template
|
||||
// // _.templateSettings.interpolate = /<%=([\s\S]+?)%>/g;
|
||||
// optionTmpl = '' +
|
||||
// '<select name="<%=option%>" type="number" ng-model="rule.options.<%=option%>" class="form-control input-sm">\n' +
|
||||
// '<option ng-repeat="v in rule.optionDesc.<%=option%>.possibleVals" value="{{v}}">{{v}}</option>\n' +
|
||||
// '</select>\n';
|
||||
//
|
||||
// // we want template params where each options is replace with a select box
|
||||
// var tmplParams = {};
|
||||
//
|
||||
// for (var option in this.optionDesc) {
|
||||
// if (this.optionDesc.hasOwnProperty(option)) {
|
||||
// var vals = this.optionDesc[option].possibleVals;
|
||||
// if (vals) {
|
||||
// tmplParams[option] = _.template(optionTmpl)({
|
||||
// option: option
|
||||
// });
|
||||
// } else {
|
||||
// tmplParams[option] = option;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // now in description replace params with select box
|
||||
// return _.template(this.description)(tmplParams);
|
||||
// };
|
||||
/** Compile description using options to express rule**/
|
||||
Rule.prototype.describeVariation = function (options) {
|
||||
var compiled = _.template(this.description);
|
||||
@@ -191,15 +192,15 @@ var Rules = module.exports = (function functionName(_,chai) {
|
||||
};
|
||||
/** Get next hint **/
|
||||
Rule.prototype.nextHint = function () {
|
||||
var hint = this.hints[this.hintsUsed];
|
||||
this.hintsUsed++;
|
||||
var hint = this.hints[this.state.hintsUsed];
|
||||
this.state.hintsUsed++;
|
||||
return hint || "";
|
||||
|
||||
};
|
||||
/** Generate an automatic hint from params **/
|
||||
Rule.prototype.genHints = function () {
|
||||
// first manual hints
|
||||
this.hintsUsed = 0;
|
||||
this.state.hintsUsed = 0;
|
||||
var hints = [];
|
||||
|
||||
// compile hints for each unused property
|
||||
@@ -226,7 +227,7 @@ var Rules = module.exports = (function functionName(_,chai) {
|
||||
for (var optionUnused in unusedOptions) {
|
||||
if (unusedOptions.hasOwnProperty(optionUnused)) {
|
||||
|
||||
// find hint templats that take this unused option
|
||||
// find hint templates that take this unused option
|
||||
for (var i = 0; i < this.hintTmpls.length; i++) {
|
||||
var tmpl = this.hintTmpls[i];
|
||||
if (tmpl.indexOf(optionUnused) >= 0) {
|
||||
@@ -250,8 +251,8 @@ var Rules = module.exports = (function functionName(_,chai) {
|
||||
}
|
||||
|
||||
// on on a last hint
|
||||
hints.push("That's all the hints for this rule. But don't forget to check for hints for the overall game. This is a game of inductive logic to try to disprove rules.");
|
||||
hints.push("You cheeky blighter. Feel free to restart the game to get a new rule if this one is no fun (it will happen).");
|
||||
hints.push("That's all the hints. But this is a game of inductive logic so try to disprove rules instead of proving them.");
|
||||
hints.push("No more hints you cheeky blighter!");
|
||||
|
||||
// and finally remove duplicate hints
|
||||
hints = _.uniq(hints);
|
||||
@@ -299,6 +300,11 @@ var Rules = module.exports = (function functionName(_,chai) {
|
||||
}
|
||||
};
|
||||
|
||||
Rule.prototype.loadState =
|
||||
function (state) {
|
||||
$.extend(this.state, state);
|
||||
};
|
||||
|
||||
|
||||
// Now defined actual rules
|
||||
var rules = [];
|
||||
@@ -307,6 +313,7 @@ var Rules = module.exports = (function functionName(_,chai) {
|
||||
// here is a example rule where the card must have differen't color etc from the last card
|
||||
// but it's abstracted to allow variations
|
||||
new Rule(
|
||||
"d4a2f61a-0fb9-4eb6-9258-3e14ae4cd512",
|
||||
"Next card must not have the same <%= property %> as the <%= lastn(n) %> card",
|
||||
function (card, lastCards, allCards, options) {
|
||||
var lastNCard = lastCards[lastCards.length - this.options.n];
|
||||
@@ -336,10 +343,10 @@ var Rules = module.exports = (function functionName(_,chai) {
|
||||
]
|
||||
),
|
||||
new Rule(
|
||||
"2b70bd6a-8bdd-49d4-bec7-bfb9de090e78",
|
||||
"If <%= lastn(n) %> cards value was between <%= min %> and <%= max %> play a card that isn't and vice versa.",
|
||||
function (card, lastCards, allCards, options) {
|
||||
var lastNCard = lastCards[lastCards.length - this.options.n];
|
||||
var property = this.options.property;
|
||||
var lastWasbetween = options.min < lastNCard.value && lastNCard.value < options.max;
|
||||
if (lastWasbetween)
|
||||
return chai.expect(card)
|
||||
@@ -382,6 +389,7 @@ var Rules = module.exports = (function functionName(_,chai) {
|
||||
]
|
||||
),
|
||||
new Rule(
|
||||
"3e12d713-335a-42e7-81ed-7064442f628a",
|
||||
"Play a card with a value <%= min %> to <%= max %> higher than the value of the <%= lastn(n) %> card. The numbers wrap around once they reach the max",
|
||||
function (card, lastCards, allCards, options) {
|
||||
var lastNCard = lastCards[lastCards.length - this.options.n];
|
||||
@@ -426,6 +434,7 @@ var Rules = module.exports = (function functionName(_,chai) {
|
||||
|
||||
|
||||
new Rule(
|
||||
"99b1d408-000d-41e6-8a0c-886a5d21d06f",
|
||||
"If the <%= lastn(n) %> card is an even-valued card, play a <%= evenColor %> card. Otherwise play the other color",
|
||||
function (card, lastCards, allCards, options) {
|
||||
var lastNCard = lastCards[lastCards.length - this.options.n];
|
||||
@@ -465,6 +474,7 @@ var Rules = module.exports = (function functionName(_,chai) {
|
||||
),
|
||||
|
||||
new Rule(
|
||||
"4014c459-a7a7-4a49-98f5-302a1b7b89e7",
|
||||
"Play a card that has the same <%= property %> or color as the <%= lastn(n) %> card but not both.",
|
||||
function (card, lastCards, allCards, options) {
|
||||
var lastNCard = lastCards[lastCards.length - options.n];
|
||||
@@ -495,6 +505,7 @@ var Rules = module.exports = (function functionName(_,chai) {
|
||||
),
|
||||
|
||||
new Rule(
|
||||
"793d93cb-ca09-4cda-8781-6fce02edf09c",
|
||||
"If the <%= lastn(n) %> card's number is higher than <%= min %>, change <%= property %>, and if lower, keep it the same.",
|
||||
function (card, lastCards, allCards, options) {
|
||||
var lastNCard = lastCards[lastCards.length - options.n];
|
||||
@@ -540,6 +551,7 @@ var Rules = module.exports = (function functionName(_,chai) {
|
||||
]
|
||||
),
|
||||
new Rule(
|
||||
"f4fba793-f886-4db8-9853-240002bb112e",
|
||||
"If the <%= lastn(n) %> card was a <%= property %> card, play a higher value card otherwise lower.",
|
||||
//TODO what if we have a high card? we can only go higher
|
||||
function (card, lastCards, allCards, options) {
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
/** Extend chai to be used in defining rules **/
|
||||
|
||||
// might want to use chair string for startswith etc
|
||||
// chai-properties for muliple properties
|
||||
// chai-adhoc for easier additions https://github.com/AnAppAMonth/chai-adhoc
|
||||
var chai = (function functionName(chai) {
|
||||
|
||||
// wrap every chainer to add message to chain? that would be interesting
|
||||
|
||||
// card method that set's name of card?
|
||||
|
||||
// wrap or overide property chain to add to name
|
||||
|
||||
// and methods to compare to Nth last card's property
|
||||
|
||||
// and what about more complex ones like mod and odd and prime
|
||||
|
||||
|
||||
})(chai);
|
||||
+1
-1
@@ -89,7 +89,7 @@ var UI = module.exports = (function (FastClick,Cookies) {
|
||||
if (typeof Cookies.get('cookielaw') === 'undefined') {
|
||||
var alert = '<div id="cookielaw" class="alert alert-info" role="alert">';
|
||||
alert += '<button type="button" class="btn btn-primary">OK</button>';
|
||||
alert += '<i class="fa fa-info-circle alert-glyph"></i> <span class="alert-text">Particle Clicker uses local storage to store your current progress.</span>';
|
||||
alert += '<i class="fa fa-info-circle alert-glyph"></i> <span class="alert-text">Cards for science uses local storage to store your current progress.</span>';
|
||||
alert += '</div>';
|
||||
alert = $(alert);
|
||||
alert.find('button').click(function ()
|
||||
|
||||
Reference in New Issue
Block a user