mirror of
https://github.com/wassname/cardsforscience.git
synced 2026-06-27 16:14:52 +08:00
Added rules and tests for them
This commit is contained in:
+29
-6
@@ -303,17 +303,20 @@ h1 br {
|
||||
padding-top: 50px;
|
||||
}
|
||||
.test-tube {
|
||||
border-left: 5px solid #949494;
|
||||
/*border-left: 5px solid #949494;
|
||||
border-right: 5px solid #949494;
|
||||
border-bottom: 5px solid #949494;
|
||||
border-bottom-left-radius: 10px;
|
||||
border-bottom-right-radius: 10px;
|
||||
border-bottom-right-radius: 10px;*/
|
||||
border: 5px solid #949494;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
/* science-click custom css */
|
||||
|
||||
|
||||
.panel-body.large {
|
||||
min-height: 500px;
|
||||
min-height: 600px;
|
||||
}
|
||||
|
||||
.ui-draggable {
|
||||
@@ -338,13 +341,19 @@ h1 br {
|
||||
|
||||
.white-badge {
|
||||
color: black;
|
||||
background-color: transparent;
|
||||
background-color: white;
|
||||
border-radius: 2px;
|
||||
padding: 2px;
|
||||
z-index: 100;
|
||||
position: relative;
|
||||
font-weight: bold;
|
||||
border: 1px black solid;
|
||||
/*font-weight: bold;*/
|
||||
top: -1em;
|
||||
left: 2em;
|
||||
left: 2.5em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* https://github.com/mbostock/d3/blob/master/lib/colorbrewer/colorbrewer.css */
|
||||
.Paired .q0-12{fill:rgb(166,206,227)}
|
||||
.Paired .q1-12{fill:rgb(31,120,180)}
|
||||
@@ -395,3 +404,17 @@ h1 br {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.ui-grid-filter-select {
|
||||
background: white;
|
||||
font-size: 22px;
|
||||
}
|
||||
#card-deck{
|
||||
font-size: 75px;
|
||||
}
|
||||
.ui-grid-cell-contents{
|
||||
font-size: 22px;
|
||||
}
|
||||
.ui-grid-viewport .ui-grid-cell-contents{
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
+13
-6
@@ -96,7 +96,7 @@
|
||||
id="{{r.key}}"
|
||||
class="{{r.key}} element element-store {{ r.state.interesting ? 'blink' : '' }} {{r.color}} {{r.state.amount>0 ? ' ui-draggable': 'empty'}}"
|
||||
data-element="{{r.key}}"
|
||||
data-drag="true"
|
||||
data-drag="rc.isAvailable(r)"
|
||||
jqyoui-draggable="{containment:'offset'}"
|
||||
data-jqyoui-options="{{rc.dragOptions}}"
|
||||
data-hashkey={{r.$$hashKey}}
|
||||
@@ -150,9 +150,10 @@
|
||||
>
|
||||
Your detector. Click on it to generate events.
|
||||
</canvas>
|
||||
<canvas id="detector-flame" width="300" height="300" class="prevent-select center-block " ng-click="dc.toggleFlameFuel()">
|
||||
<span id="card-deck" title="deal more cards" ng-click="dc.click()" class="prevent-select">🂠</span>
|
||||
<!-- <canvas id="detector-flame" width="300" height="300" class="prevent-select center-block " ng-click="dc.toggleFlameFuel()">
|
||||
Your bunsen burner. Click it to turn on and off.
|
||||
</canvas>
|
||||
</canvas> -->
|
||||
<button id="clearall" class="btn btn-default" ng-click="dc.clearAll()"><i class="fa fa-refresh"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -346,8 +347,14 @@
|
||||
|
||||
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.js"></script>
|
||||
|
||||
<script src="bower_components/chai/chai.js"></script>
|
||||
<script src="bower_components/should/should.js"></script>
|
||||
<script src="bower_components/expect/index.js"></script>
|
||||
<script src="bower_components/jasmine-core/lib/jasmine-core/jasmine.js"></script>
|
||||
|
||||
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.17/angular.js"></script>
|
||||
<script src="bower_components/angular-dragdrop/src/angular-dragdrop.js"></script>
|
||||
<script src="bower_components/angular-animate/angular-animate.js"></script>
|
||||
|
||||
<script src="js/external/retina.js"></script>
|
||||
<script src="js/external/fastclick.js"></script>
|
||||
@@ -359,11 +366,11 @@
|
||||
<script src="js/helpers.js"></script>
|
||||
<script src="js/analytics.js"></script>
|
||||
<script src="js/gameobjects.js"></script>
|
||||
<script src="js/rules.js"></script>
|
||||
|
||||
|
||||
<script src="js/detector/flame.js"></script>
|
||||
<script src="js/detector/bubblr.js"></script>
|
||||
<script src="js/detector/event.js"></script>
|
||||
<!-- <script src="js/detector/flame.js"></script>
|
||||
<script src="js/detector/bubblr.js"></script> -->
|
||||
<script src="js/detector/detector.js"></script>
|
||||
|
||||
<script src="js/ui.js"></script>
|
||||
|
||||
@@ -14,12 +14,12 @@ var app = (function () {
|
||||
// var elements = Helpers.loadFile('json/elements.json');
|
||||
// elements = elements.map(
|
||||
// function (r) {
|
||||
// return new GameObjects.ElementStore(r);
|
||||
// return new GameObjects.Card(r);
|
||||
// });
|
||||
// // put in extended array with helper methods
|
||||
// elementStore = new GameObjects.ElementStores();
|
||||
// elementStore.push.apply(elementStore,elements);
|
||||
// return elementStore;
|
||||
// Card = new GameObjects.Cards();
|
||||
// Card.push.apply(Card,elements);
|
||||
// return Card;
|
||||
// });
|
||||
|
||||
|
||||
@@ -107,10 +107,10 @@ var app = (function () {
|
||||
var draggable = angular.element(ui.draggable);
|
||||
var key = draggable.data('element');
|
||||
if (!draggable.hasClass('element-store')) {
|
||||
var elementStore = vm.elements.get(key);
|
||||
var Card = vm.elements.get(key);
|
||||
var i = _.findIndex(vm.elements,{$$hashKey:draggable.data('hashkey')});
|
||||
detector.elements.splice(i, 1);
|
||||
elementStore.state.amount += 1;
|
||||
Card.state.amount += 1;
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -150,8 +150,8 @@ var app = (function () {
|
||||
return false;
|
||||
};
|
||||
vm.toggleFlameFuel = function () {
|
||||
console.log('toggleFlameFuel');
|
||||
detector.flamer.toggleFuel();
|
||||
// console.log('toggleFlameFuel');
|
||||
// detector.flamer.toggleFuel();
|
||||
};
|
||||
vm.clearAll = function () {
|
||||
detector.clearAll(game);
|
||||
@@ -200,13 +200,20 @@ var app = (function () {
|
||||
enableFiltering: true,
|
||||
columnDefs: [{
|
||||
field: 'inputs',
|
||||
filter: {},
|
||||
filter: {
|
||||
type: 'select',
|
||||
selectOptions: _(game.elements).filter({state:{discovered:true}}).map(function(e){return {value:e.key,label:e.key};}).value(),
|
||||
},
|
||||
visible: true
|
||||
}, {
|
||||
field: 'reactants',
|
||||
visible: false
|
||||
}, {
|
||||
field: 'results',
|
||||
filter: {
|
||||
type: 'select',
|
||||
selectOptions: _(game.elements).filter({state:{discovered:true}}).map(function(e){return {value:e.key,label:e.key};}).value(),
|
||||
},
|
||||
visible: true,
|
||||
sort: {
|
||||
direction: 'asc'
|
||||
|
||||
+22
-47
@@ -4,26 +4,7 @@ var Detector = function(){
|
||||
|
||||
|
||||
return {
|
||||
core:
|
||||
{
|
||||
// canvas: null,
|
||||
// ctx: null
|
||||
},
|
||||
//
|
||||
// events:
|
||||
// {
|
||||
// canvas: null,
|
||||
// ctx: null,
|
||||
// list: [],
|
||||
// },
|
||||
|
||||
flame:
|
||||
{
|
||||
// canvas: null,
|
||||
// ctx: null
|
||||
},
|
||||
|
||||
elements: new GameObjects.ElementStores(),
|
||||
elements: new GameObjects.Cards(),
|
||||
|
||||
visible: true,
|
||||
|
||||
@@ -36,21 +17,10 @@ var Detector = function(){
|
||||
|
||||
bubblr: undefined,
|
||||
|
||||
init: function(baseSize,element)
|
||||
init: function()
|
||||
{
|
||||
// get canvas
|
||||
// this.core.canvas = document.getElementById('detector-core');
|
||||
// if (!this.core.canvas) {
|
||||
// this.core.canvas=$('<canvas id="detector-core"></canvas>');
|
||||
// $(element).append(this.core.canvas);
|
||||
// }
|
||||
// this.core.ctx = this.core.canvas.getContext('2d');
|
||||
//
|
||||
// this.flame.canvas = document.getElementById('detector-flame');
|
||||
// this.flame.ctx = this.flame.canvas.getContext('2d');
|
||||
|
||||
this.initBubbles();
|
||||
this.initFlame();
|
||||
// this.initBubbles();
|
||||
// this.initFlame();
|
||||
},
|
||||
|
||||
initBubbles: function(){
|
||||
@@ -72,10 +42,10 @@ var Detector = function(){
|
||||
this.bubblr = bubblrElem.data('plugin_bubblr');
|
||||
},
|
||||
|
||||
initFlame: function(){
|
||||
var flameElem = $('#detector-flame').flame();
|
||||
this.flamer = flameElem.data('plugin_flame')
|
||||
},
|
||||
// initFlame: function(){
|
||||
// var flameElem = $('#detector-flame').flame();
|
||||
// this.flamer = flameElem.data('plugin_flame')
|
||||
// },
|
||||
|
||||
bindOnResize: function(){
|
||||
// HACK
|
||||
@@ -114,19 +84,19 @@ var Detector = function(){
|
||||
/** When a user clicks the detector **/
|
||||
addEvent: function()
|
||||
{
|
||||
this.bubblr.bubble(); // bubble for 500ms, TODO make one bubble
|
||||
// this.bubblr.bubble(); // bubble for 500ms, TODO make one bubble
|
||||
},
|
||||
|
||||
/** When a worker clicks the detector **/
|
||||
addEventExternal: function(numWorkers)
|
||||
{
|
||||
this.bubblr.genBubbles(numWorkers);
|
||||
// this.bubblr.genBubbles(numWorkers);
|
||||
},
|
||||
|
||||
/** Draw current events **/
|
||||
draw: function(duration)
|
||||
{
|
||||
this.bubblr.bubble();
|
||||
// this.bubblr.bubble();
|
||||
},
|
||||
|
||||
/** Clear an element back to element Store **/
|
||||
@@ -196,9 +166,14 @@ var Detector = function(){
|
||||
if (newElement && intersectingElements.indexOf(newElement)===-1) intersectingElements.push(newElement);
|
||||
|
||||
|
||||
var observation = this.experiment({inputs:intersectingElements,location:$draggable.offset()},game);
|
||||
console.log('intersectingElements', intersectingElements.length, observation);
|
||||
return observation;
|
||||
var uniqueElems = _(intersectingElements).map('key').uniq().value().length;
|
||||
if (intersectingElements.length==2 && uniqueElems>1){
|
||||
var observation = this.experiment({inputs:intersectingElements,location:$draggable.offset()},game);
|
||||
console.log('intersectingElements', intersectingElements.length, observation);
|
||||
return observation;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
@@ -209,7 +184,7 @@ var Detector = function(){
|
||||
var inputKeys = inputs.map(function(e){return e.key;});
|
||||
inputKeys.sort(); // this makes reaction be independant of order
|
||||
|
||||
var result = game.rules[inputKeys];
|
||||
var result = game.testRules(inputKeys);
|
||||
if (result) {
|
||||
this.reaction(inputs,result.reactants,result.results, options.location, game);
|
||||
} else {
|
||||
@@ -232,7 +207,7 @@ var Detector = function(){
|
||||
// get the uuid from inputs
|
||||
var ingredient = inputs.filter(function(e){return e.key===reactants[i];})[0];
|
||||
var j = _.findIndex(this.elements,{uuid:ingredient.uuid});
|
||||
var removed = this.elements.slice(j,1);
|
||||
var removed = this.elements.splice(j,1);
|
||||
}
|
||||
|
||||
// TODO use angular effects to remove in puff of fade
|
||||
@@ -259,7 +234,7 @@ var Detector = function(){
|
||||
}
|
||||
|
||||
// effects
|
||||
this.bubblr.bubble();
|
||||
// this.bubblr.bubble();
|
||||
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/** Define and draw to canvas particle events, used in detector **/
|
||||
|
||||
/**
|
||||
* Define and draw to canvas particle events, used in detector
|
||||
* @param {Object} type Object with name 'electron'||'jet'||'muon'
|
||||
* @param {Number} count Number of particles in this event
|
||||
* @param {Boolean} external Wether even was caused by player or worker
|
||||
*/
|
||||
function ParticleEvent(type, count, external)
|
||||
{
|
||||
this.work = typeof external !== 'undefined' ? external : false;
|
||||
this.type = type;
|
||||
this.length = 0;
|
||||
this.radius = 0;
|
||||
this.direction = 0;
|
||||
this.sign = (Math.random() - 0.5 >= 0) ? 1 : -1;
|
||||
this.alpha = this.work ? 0.5 : 1;
|
||||
this.count = count;
|
||||
|
||||
switch (this.type.name)
|
||||
{
|
||||
case 'electron':
|
||||
this.length = detector.radius.siliconSpace * detector.ratio + Math.round((detector.radius.ecal * detector.ratio + 10 - detector.radius.siliconSpace * detector.ratio) * Math.random());
|
||||
this.direction = Math.random() * Math.PI * 2;
|
||||
this.radius = 20 + Math.round((100 - 20) * Math.random());
|
||||
break;
|
||||
case 'jet':
|
||||
this.length = detector.radius.ecal * detector.ratio + Math.round((detector.radius.mucal * detector.ratio - detector.radius.ecal * detector.ratio) * Math.random());
|
||||
this.direction = Math.random() * Math.PI * 2;
|
||||
this.radius = 40 + Math.round((200 - 40) * Math.random());
|
||||
break;
|
||||
case 'muon':
|
||||
this.length = detector.radius.mucal * detector.ratio + 3 * detector.radius.mucalDark * detector.ratio + Math.round((4 * detector.radius.mucalLight * detector.ratio + 2 * detector.radius.mucalDark * detector.ratio) * Math.random());
|
||||
this.direction = Math.random() * Math.PI * 2;
|
||||
this.radius = 200 + Math.round((600 - 200) * Math.random());
|
||||
break;
|
||||
}
|
||||
|
||||
this.draw(16, true);
|
||||
};
|
||||
|
||||
ParticleEvent.prototype.draw = function(duration, init)
|
||||
{
|
||||
init = typeof init !== 'undefined' ? init : false;
|
||||
|
||||
var ctx = detector.events.ctx;
|
||||
var cx = detector.width / 2;
|
||||
var cy = detector.height / 2;
|
||||
|
||||
ctx.save();
|
||||
|
||||
ctx.globalAlpha = this.alpha;
|
||||
ctx.strokeStyle = this.type.color;
|
||||
ctx.fillStyle = this.type.color;
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
ctx.translate(cx, cy);
|
||||
ctx.rotate(this.direction);
|
||||
ctx.translate(-cx, -cy);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(cx + this.length / 2, cy + this.sign * Math.round(Math.sqrt(Math.abs(this.radius * this.radius - this.length * this.length / 4))), this.radius, - this.sign * Math.PI / 2 - Math.asin(this.length / (2 * this.radius)), - this.sign * Math.PI / 2 + Math.asin(this.length / (2 * this.radius)), false);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.restore();
|
||||
|
||||
if (!init) {
|
||||
this.alpha -= 0.03 / 16 * duration;
|
||||
}
|
||||
};
|
||||
+175
-80
@@ -76,103 +76,198 @@ var Game = (function (Helpers, GameObjects, ObjectStorage) {
|
||||
// })
|
||||
// ).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
|
||||
// once anyway...
|
||||
var o = new type(object);
|
||||
self.allObjects[o.key] = o;
|
||||
return o;
|
||||
};
|
||||
self.elements = self.elements.slice(0, 20).map(
|
||||
function (r) {
|
||||
return makeGameObject(GameObjects.ElementStore, r);
|
||||
});
|
||||
self.workers = self.workers.map(
|
||||
function (w) {
|
||||
return makeGameObject(GameObjects.Worker, w);
|
||||
});
|
||||
self.upgrades = self.upgrades.map(
|
||||
function (u) {
|
||||
return makeGameObject(GameObjects.Upgrade, u);
|
||||
});
|
||||
self.achievements = self.achievements.map(
|
||||
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));
|
||||
}
|
||||
// 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
|
||||
// once anyway...
|
||||
var o = new type(object);
|
||||
self.allObjects[o.key] = o;
|
||||
return o;
|
||||
};
|
||||
self.elements = self.elements.map(
|
||||
function (r) {
|
||||
return makeGameObject(GameObjects.Card, r);
|
||||
});
|
||||
self.workers = self.workers.map(
|
||||
function (w) {
|
||||
return makeGameObject(GameObjects.Worker, w);
|
||||
});
|
||||
self.upgrades = self.upgrades.map(
|
||||
function (u) {
|
||||
return makeGameObject(GameObjects.Upgrade, u);
|
||||
});
|
||||
self.achievements = self.achievements.map(
|
||||
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 elements in extended array with utility methods
|
||||
self.elementStore = new GameObjects.ElementStores();
|
||||
self.elementStore.push.apply(self.elementStore, self.elements);
|
||||
self.elements = self.elementStore;
|
||||
// put elements in extended array with utility methods
|
||||
self.Card = new GameObjects.Cards();
|
||||
self.Card.push.apply(self.Card, self.elements);
|
||||
self.elements = self.Card;
|
||||
// var totalElements = _(self.elements).map('state.amount').sum();
|
||||
// if (totalElements<1) self.initialElements();
|
||||
|
||||
self.rules = self.generateRules();
|
||||
|
||||
self.loaded = true;
|
||||
return self;
|
||||
self.rules = self.generateRules();
|
||||
|
||||
self.loaded = true;
|
||||
return self;
|
||||
// });
|
||||
};
|
||||
|
||||
Game.prototype.initialElements = function () {
|
||||
// if we are making new rules we will also reset element stores
|
||||
this.elements.map(function (element) {
|
||||
element.state.amount = 0;
|
||||
element.state.discovered = false;
|
||||
element.state.interesting = false;
|
||||
});
|
||||
// but give us a random 4 number cards of one suite
|
||||
var startSuit = _.sample(["Spades", "Hearts", "Diamonds", "Clubs"]);
|
||||
|
||||
this.elements.map(function (element) {
|
||||
if (element.number && element.suit === startSuit) {
|
||||
element.state.amount = 5;
|
||||
element.state.discovered = true;
|
||||
}
|
||||
});
|
||||
console.log('Set initial cards');
|
||||
return startSuit;
|
||||
}
|
||||
|
||||
/** Generate rules between runes **/
|
||||
Game.prototype.generateRules = function () {
|
||||
var rules = ObjectStorage['rules'];
|
||||
if (!rules) {
|
||||
var elements = this.elements;
|
||||
// generate rules and store them with a hash of inredients
|
||||
// the rule will be an object with reactants, catalysts, conditions, results
|
||||
// todo make a strcture that's more like a tree with progression etc
|
||||
// todo add duds, misleading ones, explosions wildcards
|
||||
// todo make this theory based?
|
||||
// todo simulation
|
||||
var rules = {};
|
||||
for (var k = 0; k < this.elements.length * 20; k++) {
|
||||
// make a rules
|
||||
var rule = {
|
||||
reactants: [],
|
||||
catalysts: [],
|
||||
conditions: [],
|
||||
results: [],
|
||||
inputs: []
|
||||
}
|
||||
var numOfIngredients = 2 + Math.round(Math.random() * 2);
|
||||
for (var i = 0; i < numOfIngredients; i++) {
|
||||
var j = Math.round(Math.random() * (elements.length - 1));
|
||||
rule.reactants.push(elements[j].key);
|
||||
}
|
||||
|
||||
if (Math.random() < 0.1) {
|
||||
var j = Math.round(Math.random() * (elements.length - 1));
|
||||
rule.catalysts.push(elements[j].key);
|
||||
/**
|
||||
* Make the values sequential for given card names
|
||||
* @param {Array} names - String names e.g. ['King','Queen']
|
||||
* @param {Object} rules - Rules
|
||||
* @return {Object} - modified Rules
|
||||
*/
|
||||
function orderValues(names, rules, reverse) {
|
||||
var namedCards = _.filter(elements, function (c) {
|
||||
return names.indexOf(c.name) > -1;
|
||||
});
|
||||
var uNamedCardVals = _.uniq(_.map(namedCards, 'value'));
|
||||
var maxVal = _.max(uNamedCardVals);
|
||||
var initialValue = rules.value[uNamedCardVals[0]];
|
||||
for (var i = 0; i < uNamedCardVals.length; i++) {
|
||||
var v = uNamedCardVals[i];
|
||||
if (reverse)
|
||||
rules.value[v] = initialValue + maxVal - v;
|
||||
else
|
||||
rules.value[v] = initialValue + v;
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
var rules = ObjectStorage.load('rules');
|
||||
if (!rules) {
|
||||
|
||||
var startSuit = this.initialElements();
|
||||
|
||||
var elements = this.elements;
|
||||
var attrs = ["key", "name", "value", "suit", "color", "royal", "face", "number"];
|
||||
var rules = {};
|
||||
|
||||
// first lets apply random values to each attribute
|
||||
for (var i = 0; i < attrs.length; i++) {
|
||||
var attr = attrs[i];
|
||||
rules[attr] = {};
|
||||
var uniqVals = _.uniq(_.map(elements, attr));
|
||||
for (var j = 0; j < uniqVals.length; j++) {
|
||||
var v = uniqVals[j];
|
||||
// E.g. rules.suit.black=4, rules.name.Queen=10 etc
|
||||
rules[attr][v] = Math.round(Math.random() * 104);
|
||||
}
|
||||
var numOfresults = Math.round(Math.random() * 3);
|
||||
for (var i = 0; i < numOfresults; i++) {
|
||||
var j = Math.round(Math.random() * (elements.length - 1));
|
||||
rule.results.push(elements[j].key);
|
||||
}
|
||||
rule.inputs = [].concat(rule.reactants, rule.catalysts)
|
||||
rule.reactants.sort()
|
||||
rule.results.sort()
|
||||
rule.catalysts.sort()
|
||||
rule.inputs.sort();
|
||||
// index byhash of sorted array of reactants
|
||||
rules[rule.inputs] = rule
|
||||
}
|
||||
|
||||
// now lets overide some attrbutes with a bit more order
|
||||
|
||||
// number cards should be in sequence as should face cards
|
||||
// _.uniq(_.map(_.filter(cards,{face:'true'}),'value'))
|
||||
var royals = ["Jack", "Knight", "Queen", "King"];
|
||||
var numbers = ["Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"];
|
||||
// lets randomly add the ace to the top or bottom
|
||||
if (Math.random() > 0.5) {
|
||||
royals.push("Ace");
|
||||
} else {
|
||||
numbers.push("Ace");
|
||||
}
|
||||
orderValues(royals, rules);
|
||||
orderValues(numbers, rules);
|
||||
|
||||
// and make the startingSuit 0 for a simpler set of initial rules
|
||||
rules.suit[startSuit] = 0;
|
||||
|
||||
// and finally get the joker a change for a negative
|
||||
rules.value[16] = Math.random(Math.random() * 20 - 10);
|
||||
|
||||
|
||||
|
||||
console.log('Reset and made new rules');
|
||||
|
||||
}
|
||||
ObjectStorage['rules'] = rules;
|
||||
ObjectStorage.save('rules', rules);
|
||||
return rules;
|
||||
},
|
||||
Game.prototype.save = function () {
|
||||
// Save every object's state to local storage
|
||||
for (var key in this.allObjects) {
|
||||
ObjectStorage.save(key, this.allObjects[key].state);
|
||||
/**
|
||||
* Test the rules
|
||||
* @param {array} inputKeys - e.g ["🂤", "🂤"]
|
||||
* @return {Object} rule with {inputs,reactants,results}
|
||||
*/
|
||||
Game.prototype.testRules = function (inputKeys) {
|
||||
var self = this;
|
||||
var attrs = ["value", "suit"]; // attrs we use, possible expand later
|
||||
|
||||
|
||||
// work out total for this combo
|
||||
var total = 0;
|
||||
for (var i = 0; i < inputKeys.length; i++) {
|
||||
var key = inputKeys[i];
|
||||
var element = _.find(self.elements, {
|
||||
key: key
|
||||
});
|
||||
for (var j = 0; j < attrs.length; j++) {
|
||||
var attr = attrs[j];
|
||||
// add appropriate value for this card's attribute
|
||||
// e.g. total+=rules.suit["spade]
|
||||
total += self.rules[attr][element[attr]];
|
||||
}
|
||||
}
|
||||
|
||||
// you keep you results and thus get more cards unless the total is
|
||||
// <5
|
||||
var maxValue = 14; //=_(self.elements).map('value').map(function(v){return parseInt(v);}).max()
|
||||
var divisor = Math.round(maxValue * 3); // ~66% chance of dud if they don't understand rules
|
||||
var value = total % maxValue;
|
||||
var resultElem = _.find(self.elements, {
|
||||
value: value
|
||||
});
|
||||
var reactants = resultElem ? inputKeys : [];
|
||||
var results = resultElem ? [resultElem.key] : [];
|
||||
// TODO add penalty for duds? like more cards
|
||||
|
||||
return {
|
||||
results: results,
|
||||
inputs: inputKeys,
|
||||
conditions: [],
|
||||
catalysts: [],
|
||||
reactants: reactants
|
||||
};
|
||||
};
|
||||
Game.prototype.save = function () {
|
||||
// Save every object's state to local storage
|
||||
for (var key in this.allObjects) {
|
||||
ObjectStorage.save(key, this.allObjects[key].state);
|
||||
}
|
||||
};
|
||||
|
||||
return Game;
|
||||
}(Helpers, GameObjects, ObjectStorage));
|
||||
|
||||
+42
-60
@@ -98,7 +98,13 @@ var GameObjects = (function () {
|
||||
obsText[k] = observation[k].sort().join('');
|
||||
}
|
||||
}
|
||||
this.state.observations.push(obsText);
|
||||
obsText.amount=1;
|
||||
// check if an obs with all the attributes matching (extra attribs are ok)
|
||||
var index = _.findIndex(this.state.observations,obsText);
|
||||
if (index>-1)
|
||||
this.state.observations[index].amount+=1;
|
||||
else
|
||||
this.state.observations.push(obsText);
|
||||
};
|
||||
|
||||
|
||||
@@ -111,50 +117,50 @@ var GameObjects = (function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
var ElementStores = function (obj) {
|
||||
var Cards = function (obj) {
|
||||
this.push.apply(this, obj);
|
||||
};
|
||||
|
||||
ElementStores.prototype = Object.create(Array.prototype);
|
||||
Cards.prototype = Object.create(Array.prototype);
|
||||
|
||||
ElementStores.prototype.constructor = Array.constructor;
|
||||
Cards.prototype.constructor = Array.constructor;
|
||||
|
||||
ElementStores.prototype.pushAll = function (items) {
|
||||
Cards.prototype.pushAll = function (items) {
|
||||
this.push.apply(this, items);
|
||||
};
|
||||
|
||||
/** Add a random element or specify it's key **/
|
||||
ElementStores.prototype.addToStore = function (element) {
|
||||
Cards.prototype.addToStore = function (element) {
|
||||
if (element) this.get(element);
|
||||
if (!element) element = this.select();
|
||||
return element.state.amount += 1;
|
||||
};
|
||||
|
||||
/** Add a random discovered element or specify it's key **/
|
||||
ElementStores.prototype.addKnownToStore = function (element) {
|
||||
Cards.prototype.addKnownToStore = function (element) {
|
||||
var discovered = this.filter(function (e) {
|
||||
return e.state.discovered;
|
||||
});
|
||||
discovered = new GameObjects.ElementStores(discovered);
|
||||
discovered = new GameObjects.Cards(discovered);
|
||||
if (element) discovered.get(element);
|
||||
if (!element) element = discovered.select();
|
||||
return element.state.amount += 1;
|
||||
};
|
||||
|
||||
/** Select random element from store **/
|
||||
ElementStores.prototype.select = function () {
|
||||
Cards.prototype.select = function () {
|
||||
var i = Math.round((this.length - 1) * Math.random());
|
||||
return this[i];
|
||||
};
|
||||
/** Get element by key **/
|
||||
ElementStores.prototype.get = function (key) {
|
||||
Cards.prototype.get = function (key) {
|
||||
return this.filter(function (e) {
|
||||
return e.key === key;
|
||||
})[0];
|
||||
};
|
||||
|
||||
/** Get element by hashid **/
|
||||
ElementStores.prototype.getByHashKey = function (hashKey) {
|
||||
Cards.prototype.getByHashKey = function (hashKey) {
|
||||
if (hashKey === undefined) {
|
||||
console.warn('GetByHashKey given an undefined hashkey', hashKey)
|
||||
return;
|
||||
@@ -172,66 +178,42 @@ var GameObjects = (function () {
|
||||
}
|
||||
};
|
||||
|
||||
/** filter by e.g. {uuid:'34hgyh454'} **/
|
||||
// ElementStores.prototype.filterBy = function (filter) {
|
||||
// return this.filter(function (e) {
|
||||
// var match = true;
|
||||
// for (var k in filter) {
|
||||
// if (filter.hasOwnProperty(k)) {
|
||||
// match = match && (e[k] === filter[k]);
|
||||
// };
|
||||
// }
|
||||
// return match;
|
||||
// });
|
||||
// };
|
||||
//
|
||||
// /** Get indexes matching filter e.g. {uuid:'34hgyh454'} **/
|
||||
// ElementStores.prototype.findIndex = function (filter) {
|
||||
// var self = this;
|
||||
// return this.filterBy(function (e) {
|
||||
// var match = true;
|
||||
// for (var k in filter) {
|
||||
// if (filter.hasOwnProperty(k)) {
|
||||
// match = match && (e[k] === filter[k]);
|
||||
// };
|
||||
// }
|
||||
// return match;
|
||||
// })
|
||||
// .map(function (e) {
|
||||
// return self.indexOf(e);
|
||||
// });
|
||||
// };
|
||||
|
||||
/** @class ElementStore
|
||||
/** @class Card
|
||||
*/
|
||||
var ElementStore = function (obj) {
|
||||
var Card = function (obj) {
|
||||
// load from localStorage by obj.key
|
||||
GameObject.apply(this, [obj]);
|
||||
this.state.amount = Math.round(Math.random() * 2);
|
||||
this.state.discovered = Math.random() < 0.1;
|
||||
this.state.interesting = Math.random() < 0.1;
|
||||
this.state.color = Math.round(Math.random() * 11);
|
||||
this.uuid = this.guid();
|
||||
|
||||
// apply defaults to undefined values
|
||||
this.state = _.defaults(this.state,{
|
||||
amount: 0,
|
||||
discovered: false,
|
||||
interesting: false,
|
||||
});
|
||||
|
||||
// generate uuid
|
||||
this.uuid = this.uuid || this.guid();
|
||||
};
|
||||
|
||||
ElementStore.prototype = Object.create(GameObject.prototype);
|
||||
Card.prototype = Object.create(GameObject.prototype);
|
||||
|
||||
ElementStore.prototype.constructor = ElementStore;
|
||||
Card.prototype.constructor = Card;
|
||||
|
||||
ElementStore.prototype.isVisible = function (lab) {
|
||||
Card.prototype.isVisible = function (lab) {
|
||||
if (!lab) {
|
||||
return false;
|
||||
}
|
||||
return this.state.discovered;
|
||||
};
|
||||
|
||||
ElementStore.prototype.isAvailable = function (lab) {
|
||||
Card.prototype.isAvailable = function (lab) {
|
||||
if (!lab) {
|
||||
return false;
|
||||
}
|
||||
return this.state.amount > 0;
|
||||
};
|
||||
|
||||
ElementStore.prototype.research = function (lab) {
|
||||
Card.prototype.research = function (lab) {
|
||||
if (lab && lab.research(this.state.cost, this.state.reputation)) {
|
||||
this.state.level++;
|
||||
if (this.state.info_levels.length > 0 &&
|
||||
@@ -246,7 +228,7 @@ var GameObjects = (function () {
|
||||
return -1;
|
||||
};
|
||||
|
||||
ElementStore.prototype.getInfo = function () {
|
||||
Card.prototype.getInfo = function () {
|
||||
if (!this._info) {
|
||||
this._info = Helpers.loadFile(this.info);
|
||||
}
|
||||
@@ -254,16 +236,16 @@ var GameObjects = (function () {
|
||||
return this._info;
|
||||
};
|
||||
|
||||
/** Create a new element for the test tube from this ElementStore **/
|
||||
ElementStore.prototype.spawn = function () {
|
||||
/** Create a new element for the test tube from this Card **/
|
||||
Card.prototype.spawn = function () {
|
||||
var element = angular.copy(this);
|
||||
element.uuid = element.guid();
|
||||
element.state = undefined;
|
||||
this.state.amount -= 1;
|
||||
// this.state.amount -= 1;
|
||||
return element;
|
||||
};
|
||||
|
||||
ElementStore.prototype.decreaseStore = function () {
|
||||
Card.prototype.decreaseStore = function () {
|
||||
return this.state.amount -= 1;
|
||||
};
|
||||
|
||||
@@ -406,10 +388,10 @@ var GameObjects = (function () {
|
||||
// Expose classes in module.
|
||||
return {
|
||||
Lab: Lab,
|
||||
ElementStore: ElementStore,
|
||||
Card: Card,
|
||||
Worker: Worker,
|
||||
Upgrade: Upgrade,
|
||||
Achievement: Achievement,
|
||||
ElementStores: ElementStores
|
||||
Cards: Cards
|
||||
};
|
||||
}());
|
||||
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
/**
|
||||
* Rules objects for game
|
||||
* @param {[type]} function functionName( [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
var Rules = (function functionName(_) {
|
||||
|
||||
/**
|
||||
* Rule prototype
|
||||
* @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 {Object} options - Options for the rule will be given on test and description rendering
|
||||
*/
|
||||
|
||||
/**
|
||||
* Rule prototype
|
||||
* @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 {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
|
||||
* @param {String} optionDesc[].description Description of this option e.g. 'Property to compare to last card'
|
||||
* @param {String} optionDesc[].type Type for this option e.g. 'String'
|
||||
* @param {Array} hintTmpls Array of hint templates. Each should only contain one option e.g.
|
||||
* `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) {
|
||||
if (!(typeof(description)==='string'||description instanceof String)|| !description.length)
|
||||
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.ruleFunc = ruleFunc;
|
||||
this.optionDesc = optionDesc||{};
|
||||
this.options = this.optionDefaults = optionDefaults||{};
|
||||
this.hintTmpls=hintTmpls||[];
|
||||
|
||||
// use angular and mustache templating
|
||||
_.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
|
||||
|
||||
// init
|
||||
this.hintsUsed = 0;
|
||||
this.hints=this.genHints();
|
||||
};
|
||||
Rule.prototype.setOptions = function (options) {
|
||||
this.options = _.defaults(options, this.optionDefaults);
|
||||
this.hints=this.genHints();
|
||||
return this.options;
|
||||
};
|
||||
/** Tests the rule and returns true, false, or an AssertionError **/
|
||||
Rule.prototype.testAndTell = function (card, lastCards, allCards) {
|
||||
chai.expect(card).to.be.a('object');
|
||||
chai.expect(lastCards).to.be.a('array');
|
||||
chai.expect(allCards).to.be.a('array');
|
||||
|
||||
var result;
|
||||
var reason;
|
||||
try {
|
||||
result = this.ruleFunc(card, lastCards, allCards, this.options);
|
||||
if (result instanceof chai.Assertion){
|
||||
reason=result;
|
||||
result=true;
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof chai.AssertionError){
|
||||
result = false;
|
||||
reason=e;
|
||||
} else {throw(e);}
|
||||
}
|
||||
return {result:result,reason:reason};
|
||||
};
|
||||
Rule.prototype.test = function (card, lastCards, allCards) {
|
||||
var res = this.testAndTell(card,lastCards,allCards);
|
||||
return res.result;
|
||||
};
|
||||
/** Describe rule using set options **/
|
||||
Rule.prototype.describe = function () {
|
||||
return this.describeVariation(this.options);
|
||||
};
|
||||
/** Compile description using options to express rule**/
|
||||
Rule.prototype.describeVariation = function (options) {
|
||||
var compiled = _.template(this.description);
|
||||
return compiled(_.defaults(options,this.options));
|
||||
};
|
||||
/** Return options string for humans **/
|
||||
Rule.prototype.describeOptions = function () {
|
||||
var s = "";
|
||||
// explicit python style
|
||||
var template = '{{option}} \n\tDescription: {{description}}\n\tType {{type}} \n\tValues: current:{{current}}, default:{{defaultVal}}, all:[{{possibleVals}}]\n ';
|
||||
// jsdoc style I think
|
||||
// var template = '{{type}}\t[{{option}}={{defaultVal}}]\t{{description}}. ({{current}})[{{possibleVals}}]\n';
|
||||
for (var option in this.optionDesc) {
|
||||
if (this.optionDesc.hasOwnProperty(option)) {
|
||||
var tmplParams = _.defaults({option:option,defaultVal:this.optionDefaults[option],current:this.options[option]},this.optionDesc[option]);
|
||||
s+=_.template(template)(tmplParams);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
};
|
||||
/** Describe all variations on the default options **/
|
||||
Rule.prototype.describeVariations = function () {
|
||||
var s="";
|
||||
for (var option in this.optionDesc) {
|
||||
if (this.optionDesc.hasOwnProperty(option)) {
|
||||
var vals = this.optionDesc[option].possibleVals;
|
||||
for (var i = 0; i < vals.length; i++) {
|
||||
var options={};
|
||||
options[option]=vals[i];
|
||||
s+=this.describeVariation(options)+'\n';
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return s;
|
||||
};
|
||||
/** Get next hint **/
|
||||
Rule.prototype.nextHint = function () {
|
||||
var hint = this.hints[this.hintsUsed];
|
||||
this.hintsUsed++;
|
||||
return hint||"";
|
||||
|
||||
};
|
||||
/** Generate an automatic hint from params **/
|
||||
Rule.prototype.genHints = function () {
|
||||
// first manual hints
|
||||
this.hintsUsed=0;
|
||||
var hints = [];
|
||||
|
||||
// compile hints for each unused property
|
||||
// this onl handles one unused property per hint
|
||||
|
||||
// get all unused options
|
||||
var unusedOptions = {};
|
||||
for (var option in this.optionDesc) {
|
||||
if (this.optionDesc.hasOwnProperty(option)) {
|
||||
// for each option find any unused options
|
||||
var posVals = this.optionDesc[option].possibleVals;
|
||||
if (posVals){
|
||||
var optionUnused = _.difference(posVals,[this.options[option]]);
|
||||
unusedOptions[option+'Unused']=optionUnused;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy options
|
||||
var tmplParams = _.extend({},this.options);
|
||||
|
||||
|
||||
// make hint from unused options if there are hint templates for them
|
||||
for (var optionUnused in unusedOptions) {
|
||||
if (unusedOptions.hasOwnProperty(optionUnused)) {
|
||||
|
||||
// find hint templats that take this unused option
|
||||
for (var i = 0; i < this.hintTmpls.length; i++) {
|
||||
var tmpl = this.hintTmpls[i];
|
||||
if (tmpl.indexOf(optionUnused)>=0){
|
||||
var tmplCmp = _.template(tmpl);
|
||||
var unused = unusedOptions[optionUnused];
|
||||
// generate a hint for each unsed options
|
||||
for (var j = 0; j < unused.length; j++) {
|
||||
tmplParams[optionUnused]=unused[j];
|
||||
var hint = tmplCmp(tmplParams);
|
||||
hints.push(hint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now make other hints for used params
|
||||
for (var i = 0; i < this.hintTmpls.length; i++) {
|
||||
var hint = _.template(this.hintTmpls[i])(tmplParams);
|
||||
hints.push(hint);
|
||||
}
|
||||
|
||||
// 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).");
|
||||
|
||||
// and finally remove duplicate hints
|
||||
hints=_.uniq(hints);
|
||||
|
||||
return hints;
|
||||
};
|
||||
|
||||
/** How many combination of this rule **/
|
||||
Rule.prototype.combinations = function (arguments) {
|
||||
var pos = _.map(this.optionDesc,'possibleVals');
|
||||
var c=0;
|
||||
for (var i = 0; i < pos.length; i++) {
|
||||
c*pos[i].length;
|
||||
}
|
||||
return c;
|
||||
};
|
||||
// TODO estimate hardness perhaps through simulation, combinatorics or hints
|
||||
|
||||
|
||||
// Now defined actual rules
|
||||
var rules = [];
|
||||
|
||||
rules.push(
|
||||
// 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(
|
||||
"Next card must not have the same {{property}} as the last {{n}}'th card",
|
||||
function (card, lastCards, allCards, options) {
|
||||
var lastNCard = lastCards[this.options.n-1];
|
||||
var property = this.options.property;
|
||||
return chai.expect(card)
|
||||
.to.have.property(property)
|
||||
.not.equal(lastNCard[property]);
|
||||
},
|
||||
{
|
||||
property: 'color',
|
||||
n: 1
|
||||
},
|
||||
{
|
||||
property: {
|
||||
description: 'The property to compare in last and current card',
|
||||
possibleVals: ['color','face','number','value','suit'],
|
||||
type: 'String'
|
||||
},
|
||||
n: {
|
||||
description: 'Number for how many cards back. Start counting at 1',
|
||||
possibleVals: [1,2,3],
|
||||
type: 'Number'
|
||||
}
|
||||
},
|
||||
[
|
||||
'This rule does not involve {{propertyUnused}}',
|
||||
// 'This rule does not involve the {{nUnused}}th last card',
|
||||
'This rule does involve {{property}}',
|
||||
'This rule does involve the {{n}}th last card',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
return {
|
||||
Rule: Rule,
|
||||
rules: rules,
|
||||
};
|
||||
|
||||
|
||||
})(_);
|
||||
@@ -9,6 +9,11 @@ var UI = (function () {
|
||||
FastClick.attach(document.body);
|
||||
});
|
||||
|
||||
// $('.prevent-select').on('mousedown', function(e) {
|
||||
// e.preventDefault();
|
||||
// });
|
||||
|
||||
|
||||
/** Show a bootstrap modal with dynamic content e.g. background info **/
|
||||
var showModal = function(title, text, level) {
|
||||
var $modal = $('#infoBox');
|
||||
|
||||
+59
-59
@@ -1,59 +1,59 @@
|
||||
[{"key": "🂡","name":"Ace","value":"1","suite":"Spades","color":"Black","royal":"false","face":"false","number":"false"},
|
||||
{"key": "🂢","name":"Two","value":"2","suite":"Spades","color":"Black","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🂣","name":"Three","value":"3","suite":"Spades","color":"Black","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🂤","name":"Four","value":"4","suite":"Spades","color":"Black","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🂥","name":"Five","value":"5","suite":"Spades","color":"Black","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🂦","name":"Six","value":"6","suite":"Spades","color":"Black","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🂧","name":"Seven","value":"7","suite":"Spades","color":"Black","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🂨","name":"Eight","value":"8","suite":"Spades","color":"Black","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🂩","name":"Nine","value":"9","suite":"Spades","color":"Black","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🂪","name":"Ten","value":"10","suite":"Spades","color":"Black","royal":"false","face":"true","number":"true"},
|
||||
{"key": "🂫","name":"Jack","value":"11","suite":"Spades","color":"Black","royal":"true","face":"true","number":"false"},
|
||||
{"key": "🂬","name":"Knight","value":"12","suite":"Spades","color":"Black","royal":"true","face":"true","number":"false"},
|
||||
{"key": "🂭","name":"Queen","value":"13","suite":"Spades","color":"Black","royal":"true","face":"true","number":"false"},
|
||||
{"key": "🂮","name":"King","value":"14","suite":"Spades","color":"Black","royal":"true","face":"true","number":"false"},
|
||||
{"key": "🂱","name":"Ace","value":"1","suite":"Hearts","color":"Red","royal":"false","face":"false","number":"false"},
|
||||
{"key": "🂲","name":"Two","value":"2","suite":"Hearts","color":"Red","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🂳","name":"Three","value":"3","suite":"Hearts","color":"Red","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🂴","name":"Four","value":"4","suite":"Hearts","color":"Red","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🂵","name":"Five","value":"5","suite":"Hearts","color":"Red","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🂶","name":"Six","value":"6","suite":"Hearts","color":"Red","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🂷","name":"Seven","value":"7","suite":"Hearts","color":"Red","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🂸","name":"Eight","value":"8","suite":"Hearts","color":"Red","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🂹","name":"Nine","value":"9","suite":"Hearts","color":"Red","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🂺","name":"Ten","value":"10","suite":"Hearts","color":"Red","royal":"false","face":"true","number":"true"},
|
||||
{"key": "🂻","name":"Jack","value":"11","suite":"Hearts","color":"Red","royal":"true","face":"true","number":"false"},
|
||||
{"key": "🂼","name":"Knight","value":"12","suite":"Hearts","color":"Red","royal":"true","face":"true","number":"false"},
|
||||
{"key": "🂽","name":"Queen","value":"13","suite":"Hearts","color":"Red","royal":"true","face":"true","number":"false"},
|
||||
{"key": "🂾","name":"King","value":"14","suite":"Hearts","color":"Red","royal":"true","face":"true","number":"false"},
|
||||
{"key": "🃁","name":"Ace","value":"1","suite":"Diamonds","color":"Red","royal":"false","face":"false","number":"false"},
|
||||
{"key": "🃂","name":"Two","value":"2","suite":"Diamonds","color":"Red","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🃃","name":"Three","value":"3","suite":"Diamonds","color":"Red","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🃄","name":"Four","value":"4","suite":"Diamonds","color":"Red","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🃅","name":"Five","value":"5","suite":"Diamonds","color":"Red","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🃆","name":"Six","value":"6","suite":"Diamonds","color":"Red","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🃇","name":"Seven","value":"7","suite":"Diamonds","color":"Red","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🃈","name":"Eight","value":"8","suite":"Diamonds","color":"Red","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🃉","name":"Nine","value":"9","suite":"Diamonds","color":"Red","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🃊","name":"Ten","value":"10","suite":"Diamonds","color":"Red","royal":"false","face":"true","number":"true"},
|
||||
{"key": "🃋","name":"Jack","value":"11","suite":"Diamonds","color":"Red","royal":"true","face":"true","number":"false"},
|
||||
{"key": "🃌","name":"Knight","value":"12","suite":"Diamonds","color":"Red","royal":"true","face":"true","number":"false"},
|
||||
{"key": "🃍","name":"Queen","value":"13","suite":"Diamonds","color":"Red","royal":"true","face":"true","number":"false"},
|
||||
{"key": "🃎","name":"King","value":"14","suite":"Diamonds","color":"Red","royal":"true","face":"true","number":"false"},
|
||||
{"key": "🃑","name":"Ace","value":"1","suite":"Clubs","color":"Black","royal":"false","face":"false","number":"false"},
|
||||
{"key": "🃒","name":"Two","value":"2","suite":"Clubs","color":"Black","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🃓","name":"Three","value":"3","suite":"Clubs","color":"Black","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🃔","name":"Four","value":"4","suite":"Clubs","color":"Black","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🃕","name":"Five","value":"5","suite":"Clubs","color":"Black","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🃖","name":"Six","value":"6","suite":"Clubs","color":"Black","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🃗","name":"Seven","value":"7","suite":"Clubs","color":"Black","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🃘","name":"Eight","value":"8","suite":"Clubs","color":"Black","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🃙","name":"Nine","value":"9","suite":"Clubs","color":"Black","royal":"false","face":"false","number":"true"},
|
||||
{"key": "🃚","name":"Ten","value":"10","suite":"Clubs","color":"Black","royal":"false","face":"true","number":"true"},
|
||||
{"key": "🃛","name":"Jack","value":"11","suite":"Clubs","color":"Black","royal":"true","face":"true","number":"false"},
|
||||
{"key": "🃜","name":"Knight","value":"12","suite":"Clubs","color":"Black","royal":"true","face":"true","number":"false"},
|
||||
{"key": "🃝","name":"Queen","value":"13","suite":"Clubs","color":"Black","royal":"true","face":"true","number":"false"},
|
||||
{"key": "🃞","name":"King","value":"14","suite":"Clubs","color":"Black","royal":"true","face":"true","number":"false"},
|
||||
{"key": "🂠","name":"Playing Card","value":"15","suite":"Black","color":"Black","royal":"false","face":"false","number":"false"},
|
||||
{"key": "🃏","name":"Joker","value":"16","suite":"Black","color":"Black","royal":"false","face":"true","number":"false"},
|
||||
{"key": "🃟","name":"Joker","value":"16","suite":"Red","color":"Red","royal":"false","face":"true","number":"false"}]
|
||||
[{"key": "🂡","name":"Ace","value":1,"suit":"Spades","color":"Black","royal":false,"face":false,"number":false},
|
||||
{"key": "🂢","name":"Two","value":2,"suit":"Spades","color":"Black","royal":false,"face":false,"number":true},
|
||||
{"key": "🂣","name":"Three","value":3,"suit":"Spades","color":"Black","royal":false,"face":false,"number":true},
|
||||
{"key": "🂤","name":"Four","value":4,"suit":"Spades","color":"Black","royal":false,"face":false,"number":true},
|
||||
{"key": "🂥","name":"Five","value":5,"suit":"Spades","color":"Black","royal":false,"face":false,"number":true},
|
||||
{"key": "🂦","name":"Six","value":6,"suit":"Spades","color":"Black","royal":false,"face":false,"number":true},
|
||||
{"key": "🂧","name":"Seven","value":7,"suit":"Spades","color":"Black","royal":false,"face":false,"number":true},
|
||||
{"key": "🂨","name":"Eight","value":8,"suit":"Spades","color":"Black","royal":false,"face":false,"number":true},
|
||||
{"key": "🂩","name":"Nine","value":9,"suit":"Spades","color":"Black","royal":false,"face":false,"number":true},
|
||||
{"key": "🂪","name":"Ten","value":10,"suit":"Spades","color":"Black","royal":false,"face":true,"number":true},
|
||||
{"key": "🂫","name":"Jack","value":11,"suit":"Spades","color":"Black","royal":true,"face":true,"number":false},
|
||||
{"key": "🂬","name":"Knight","value":12,"suit":"Spades","color":"Black","royal":true,"face":true,"number":false},
|
||||
{"key": "🂭","name":"Queen","value":13,"suit":"Spades","color":"Black","royal":true,"face":true,"number":false},
|
||||
{"key": "🂮","name":"King","value":14,"suit":"Spades","color":"Black","royal":true,"face":true,"number":false},
|
||||
{"key": "🂱","name":"Ace","value":1,"suit":"Hearts","color":"Red","royal":false,"face":false,"number":false},
|
||||
{"key": "🂲","name":"Two","value":2,"suit":"Hearts","color":"Red","royal":false,"face":false,"number":true},
|
||||
{"key": "🂳","name":"Three","value":3,"suit":"Hearts","color":"Red","royal":false,"face":false,"number":true},
|
||||
{"key": "🂴","name":"Four","value":4,"suit":"Hearts","color":"Red","royal":false,"face":false,"number":true},
|
||||
{"key": "🂵","name":"Five","value":5,"suit":"Hearts","color":"Red","royal":false,"face":false,"number":true},
|
||||
{"key": "🂶","name":"Six","value":6,"suit":"Hearts","color":"Red","royal":false,"face":false,"number":true},
|
||||
{"key": "🂷","name":"Seven","value":7,"suit":"Hearts","color":"Red","royal":false,"face":false,"number":true},
|
||||
{"key": "🂸","name":"Eight","value":8,"suit":"Hearts","color":"Red","royal":false,"face":false,"number":true},
|
||||
{"key": "🂹","name":"Nine","value":9,"suit":"Hearts","color":"Red","royal":false,"face":false,"number":true},
|
||||
{"key": "🂺","name":"Ten","value":10,"suit":"Hearts","color":"Red","royal":false,"face":true,"number":true},
|
||||
{"key": "🂻","name":"Jack","value":11,"suit":"Hearts","color":"Red","royal":true,"face":true,"number":false},
|
||||
{"key": "🂼","name":"Knight","value":12,"suit":"Hearts","color":"Red","royal":true,"face":true,"number":false},
|
||||
{"key": "🂽","name":"Queen","value":13,"suit":"Hearts","color":"Red","royal":true,"face":true,"number":false},
|
||||
{"key": "🂾","name":"King","value":14,"suit":"Hearts","color":"Red","royal":true,"face":true,"number":false},
|
||||
{"key": "🃁","name":"Ace","value":1,"suit":"Diamonds","color":"Red","royal":false,"face":false,"number":false},
|
||||
{"key": "🃂","name":"Two","value":2,"suit":"Diamonds","color":"Red","royal":false,"face":false,"number":true},
|
||||
{"key": "🃃","name":"Three","value":3,"suit":"Diamonds","color":"Red","royal":false,"face":false,"number":true},
|
||||
{"key": "🃄","name":"Four","value":4,"suit":"Diamonds","color":"Red","royal":false,"face":false,"number":true},
|
||||
{"key": "🃅","name":"Five","value":5,"suit":"Diamonds","color":"Red","royal":false,"face":false,"number":true},
|
||||
{"key": "🃆","name":"Six","value":6,"suit":"Diamonds","color":"Red","royal":false,"face":false,"number":true},
|
||||
{"key": "🃇","name":"Seven","value":7,"suit":"Diamonds","color":"Red","royal":false,"face":false,"number":true},
|
||||
{"key": "🃈","name":"Eight","value":8,"suit":"Diamonds","color":"Red","royal":false,"face":false,"number":true},
|
||||
{"key": "🃉","name":"Nine","value":9,"suit":"Diamonds","color":"Red","royal":false,"face":false,"number":true},
|
||||
{"key": "🃊","name":"Ten","value":10,"suit":"Diamonds","color":"Red","royal":false,"face":true,"number":true},
|
||||
{"key": "🃋","name":"Jack","value":11,"suit":"Diamonds","color":"Red","royal":true,"face":true,"number":false},
|
||||
{"key": "🃌","name":"Knight","value":12,"suit":"Diamonds","color":"Red","royal":true,"face":true,"number":false},
|
||||
{"key": "🃍","name":"Queen","value":13,"suit":"Diamonds","color":"Red","royal":true,"face":true,"number":false},
|
||||
{"key": "🃎","name":"King","value":14,"suit":"Diamonds","color":"Red","royal":true,"face":true,"number":false},
|
||||
{"key": "🃑","name":"Ace","value":1,"suit":"Clubs","color":"Black","royal":false,"face":false,"number":false},
|
||||
{"key": "🃒","name":"Two","value":2,"suit":"Clubs","color":"Black","royal":false,"face":false,"number":true},
|
||||
{"key": "🃓","name":"Three","value":3,"suit":"Clubs","color":"Black","royal":false,"face":false,"number":true},
|
||||
{"key": "🃔","name":"Four","value":4,"suit":"Clubs","color":"Black","royal":false,"face":false,"number":true},
|
||||
{"key": "🃕","name":"Five","value":5,"suit":"Clubs","color":"Black","royal":false,"face":false,"number":true},
|
||||
{"key": "🃖","name":"Six","value":6,"suit":"Clubs","color":"Black","royal":false,"face":false,"number":true},
|
||||
{"key": "🃗","name":"Seven","value":7,"suit":"Clubs","color":"Black","royal":false,"face":false,"number":true},
|
||||
{"key": "🃘","name":"Eight","value":8,"suit":"Clubs","color":"Black","royal":false,"face":false,"number":true},
|
||||
{"key": "🃙","name":"Nine","value":9,"suit":"Clubs","color":"Black","royal":false,"face":false,"number":true},
|
||||
{"key": "🃚","name":"Ten","value":10,"suit":"Clubs","color":"Black","royal":false,"face":true,"number":true},
|
||||
{"key": "🃛","name":"Jack","value":11,"suit":"Clubs","color":"Black","royal":true,"face":true,"number":false},
|
||||
{"key": "🃜","name":"Knight","value":12,"suit":"Clubs","color":"Black","royal":true,"face":true,"number":false},
|
||||
{"key": "🃝","name":"Queen","value":13,"suit":"Clubs","color":"Black","royal":true,"face":true,"number":false},
|
||||
{"key": "🃞","name":"King","value":14,"suit":"Clubs","color":"Black","royal":true,"face":true,"number":false},
|
||||
{"key": "🂠","name":"Playing Card","value":15,"suit":"Black","color":"Black","royal":false,"face":false,"number":false},
|
||||
{"key": "🃏","name":"Joker","value":16,"suit":"Black","color":"Black","royal":false,"face":true,"number":false},
|
||||
{"key": "🃟","name":"Joker","value":16,"suit":"Red","color":"Red","royal":false,"face":true,"number":false}]
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
[
|
||||
{"key":"ᚠ"},
|
||||
{"key":"ᚡ"},
|
||||
{"key":"ᚢ"},
|
||||
{"key":"ᚣ"},
|
||||
{"key":"ᚤ"},
|
||||
{"key":"ᚥ"},
|
||||
{"key":"ᚦ"},
|
||||
{"key":"ᚧ"},
|
||||
{"key":"ᚨ"},
|
||||
{"key":"ᚩ"},
|
||||
{"key":"ᚪ"},
|
||||
{"key":"ᚫ"},
|
||||
{"key":"ᚬ"},
|
||||
{"key":"ᚭ"},
|
||||
{"key":"ᚮ"},
|
||||
{"key":"ᚯ"},
|
||||
{"key":"ᚰ"},
|
||||
{"key":"ᚱ"},
|
||||
{"key":"ᚲ"},
|
||||
{"key":"ᚳ"},
|
||||
{"key":"ᚴ"},
|
||||
{"key":"ᚵ"},
|
||||
{"key":"ᚶ"},
|
||||
{"key":"ᚷ"},
|
||||
{"key":"ᚸ"},
|
||||
{"key":"ᚹ"},
|
||||
{"key":"ᚺ"},
|
||||
{"key":"ᚻ"},
|
||||
{"key":"ᚼ"},
|
||||
{"key":"ᚽ"},
|
||||
{"key":"ᚾ"},
|
||||
{"key":"ᚿ"},
|
||||
{"key":"ᛀ"},
|
||||
{"key":"ᛁ"},
|
||||
{"key":"ᛂ"},
|
||||
{"key":"ᛃ"},
|
||||
{"key":"ᛄ"},
|
||||
{"key":"ᛅ"},
|
||||
{"key":"ᛆ"},
|
||||
{"key":"ᛇ"},
|
||||
{"key":"ᛈ"},
|
||||
{"key":"ᛉ"},
|
||||
{"key":"ᛊ"},
|
||||
{"key":"ᛋ"},
|
||||
{"key":"ᛌ"},
|
||||
{"key":"ᛍ"},
|
||||
{"key":"ᛎ"},
|
||||
{"key":"ᛏ"},
|
||||
{"key":"ᛐ"},
|
||||
{"key":"ᛑ"},
|
||||
{"key":"ᛒ"},
|
||||
{"key":"ᛓ"},
|
||||
{"key":"ᛔ"},
|
||||
{"key":"ᛕ"},
|
||||
{"key":"ᛖ"},
|
||||
{"key":"ᛗ"},
|
||||
{"key":"ᛘ"},
|
||||
{"key":"ᛙ"},
|
||||
{"key":"ᛚ"},
|
||||
{"key":"ᛛ"},
|
||||
{"key":"ᛜ"},
|
||||
{"key":"ᛝ"},
|
||||
{"key":"ᛞ"},
|
||||
{"key":"ᛟ"},
|
||||
{"key":"ᛠ"},
|
||||
{"key":"ᛡ"},
|
||||
{"key":"ᛢ"},
|
||||
{"key":"ᛣ"},
|
||||
{"key":"ᛤ"},
|
||||
{"key":"ᛥ"},
|
||||
{"key":"ᛦ"},
|
||||
{"key":"ᛧ"},
|
||||
{"key":"ᛨ"},
|
||||
{"key":"ᛩ"},
|
||||
{"key":"ᛪ"},
|
||||
{"key":"᛫"},
|
||||
{"key":"᛬"},
|
||||
{"key":"᛭"},
|
||||
{"key":"ᛮ"},
|
||||
{"key":"ᛯ"},
|
||||
{"key":"ᛰ"}
|
||||
]
|
||||
+7
-3
@@ -53,7 +53,10 @@ module.exports = function (config) {
|
||||
// dependencies
|
||||
'bower_components/jquery/dist/jquery.js',
|
||||
'bower_components/jquery-ui/jquery-ui.js',
|
||||
|
||||
|
||||
'bower_components/bootstrap/dist/js/bootstrap.js',
|
||||
|
||||
'bower_components/angular/angular.js',
|
||||
'bower_components/angular-route/angular-route.js',
|
||||
'bower_components/angular-resource/angular-resource.js',
|
||||
@@ -61,7 +64,10 @@ module.exports = function (config) {
|
||||
'bower_components/angular-mocks/angular-mocks.js',
|
||||
'bower_components/angular-dragdrop/src/angular-dragdrop.js',
|
||||
'bower_components/angular-ui-grid/ui-grid.js',
|
||||
|
||||
'bower_components/lodash/dist/lodash.js',
|
||||
'bower_components/chai/chai.js',
|
||||
|
||||
'js/external/*.js',
|
||||
|
||||
// fixtures
|
||||
@@ -88,9 +94,7 @@ module.exports = function (config) {
|
||||
'js/helpers.js',
|
||||
'js/analytics.js',
|
||||
'js/gameobjects.js',
|
||||
'js/detector/flame.js',
|
||||
'js/detector/bubblr.js',
|
||||
'js/detector/event.js',
|
||||
'js/rules.js',
|
||||
'js/detector/detector.js',
|
||||
'js/ui.js',
|
||||
'js/game.js',
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
'use strict';
|
||||
|
||||
/* jasmine specs for filters go here */
|
||||
var allCards;
|
||||
beforeEach(function(){
|
||||
allCards = Helpers.loadFile('json/elements.json');
|
||||
});
|
||||
|
||||
describe('Rules', function () {
|
||||
var card, lastCards;
|
||||
|
||||
beforeEach(
|
||||
module('Rules')
|
||||
);
|
||||
|
||||
beforeEach(function(){
|
||||
lastCards = _.sampleSize(allCards,4);
|
||||
card = _.sample(allCards);
|
||||
});
|
||||
|
||||
describe('Rule', function () {
|
||||
it('should test false on false', function () {
|
||||
var rule = new Rules.Rule('1',function(){return false;},{},{},[]);
|
||||
var res = rule.test(card,lastCards,allCards);
|
||||
expect(res).toBe(false);
|
||||
});
|
||||
it('should test false on assertion error', function () {
|
||||
var rule = new Rules.Rule('2',function(){return chai.expect(1).to.equal(0);},{},{},[]);
|
||||
var res = rule.test(card,lastCards,allCards);
|
||||
expect(res).toBe(false);
|
||||
});
|
||||
it('should test true on assertion', function () {
|
||||
var rule = new Rules.Rule('3',function(){return chai.expect(1).to.equal(1);},{},{},[]);
|
||||
var res = rule.test(card,lastCards,allCards);
|
||||
expect(res).toBe(true);
|
||||
});
|
||||
it('should test true on true', function () {
|
||||
var rule = new Rules.Rule('4',function(){return true;},{},{},[]);
|
||||
var res = rule.test(card,lastCards,allCards);
|
||||
expect(res).toBe(true);
|
||||
});
|
||||
it('should throw test on error', function () {
|
||||
var rule = new Rules.Rule('5',function(){throw new Error('test');return true;},{},{},[]);
|
||||
expect(function(){
|
||||
rule.test(card,lastCards,allCards);
|
||||
}).toThrow();
|
||||
});
|
||||
});
|
||||
Rules.rules.forEach(function(rule){
|
||||
describe('rule', function () {
|
||||
it('should test', function () {
|
||||
var res = rule.test(card,lastCards,allCards);
|
||||
Boolean(res);
|
||||
});
|
||||
it('should describe itself', function () {
|
||||
var desc = rule.describe();
|
||||
expect(typeof desc).toBe('string');
|
||||
expect(desc).not.toContain(/[{}]+/);
|
||||
});
|
||||
it('should describeOptions', function () {
|
||||
var desc = rule.describeOptions();
|
||||
expect(typeof desc).toBe('string');
|
||||
expect(desc).not.toContain(/[{}]+/);
|
||||
});
|
||||
it('should describeVariations', function () {
|
||||
var desc = rule.describeVariations();
|
||||
expect(typeof desc).toBe('string');
|
||||
expect(desc).not.toContain(/[{}]+/);
|
||||
});
|
||||
it('should genHints', function () {
|
||||
var hints = rule.genHints();
|
||||
expect(hints instanceof Array).toBe(true);
|
||||
expect(hints.length).toBeGreaterThan(0);
|
||||
expect(hints.join('')).not.toContain(/[{}]+/);
|
||||
});
|
||||
it('should set options', function () {
|
||||
var opts1 = rule.options;
|
||||
var opts = rule.setOptions({a24tgsdgtg43t5fd:1});
|
||||
expect(typeof opts).toBe('object');
|
||||
expect(opts).not.toEqual(opts1);
|
||||
});
|
||||
|
||||
// now check each rule permutation
|
||||
var options=Object.keys(rule.optionDesc);
|
||||
options.forEach(function(option){
|
||||
var vals = rule.optionDesc[option].possibleVals;
|
||||
for (var i = 0; i < vals.length; i++) {
|
||||
it('should test with option: '+option+' = '+vals[i],function(){
|
||||
var options={};
|
||||
options[option]=vals[i];
|
||||
rule.setOptions(options);
|
||||
var res = rule.test(card,lastCards,allCards);
|
||||
Boolean(res);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user