diff --git a/bower.json b/bower.json
index 56518bc..636b5f1 100644
--- a/bower.json
+++ b/bower.json
@@ -10,8 +10,7 @@
"**/.*",
"node_modules",
"bower_components",
- "test",
- "tests"
+ "test"
],
"dependencies": {
"angular": "1.4.x",
@@ -22,6 +21,10 @@
"angular-resource": "1.4.x",
"angular-animate": "1.4.x",
"angular-dragdrop": "~1.0.13",
- "lodash": "~4.5.1"
+ "lodash": "~4.5.1",
+ "chai": "~3.5.0",
+ "angular-ui-grid": "~3.1.1",
+ "jquery-ui": "~1.11.4",
+ "font-awesome": "~4.5.0"
}
}
diff --git a/css/style.css b/css/style.css
index 1860cfa..29ae19b 100644
--- a/css/style.css
+++ b/css/style.css
@@ -30,20 +30,6 @@ h1 br {
position: relative;
}
-#detector-flame{
- position: relative;
- /* So it looks like the flame it touching the test-tube */
- top: -60px;
-}
-
-#detector-core {
- z-index: 0;
-}
-
-#detector-events {
- z-index: 1;
-}
-
#detector-info {
z-index: 10;
position: absolute;
@@ -140,9 +126,9 @@ h1 br {
width: 99%;
}
-.panel {
+/*.panel {
margin-bottom: 0;
-}
+}*/
.media-list-no-margin {
margin-top: -15px;
@@ -209,8 +195,8 @@ h1 br {
@media screen and (min-width: 768px) {
#detector-holder {
- margin-left: -15px;
- margin-right: -15px;
+ /*margin-left: -15px;
+ margin-right: -15px;*/
}
.status {
@@ -250,11 +236,11 @@ h1 br {
@media screen and (min-width: 992px) and (max-width: 1199px){
.col-md-3s {
- width:20%;
+ /*width:20%;*/
}
.col-md-5s {
- width:40%;
+ /*width:40%;*/
}
}
@@ -418,3 +404,45 @@ h1 br {
.ui-grid-viewport .ui-grid-cell-contents{
font-size: 22px;
}
+
+.card-panel {
+ min-height: 130px;
+ min-width: 100px;
+ /*border: 1px solid black;*/
+ /*border-radius: 4px;*/
+ /*padding: 5px;*/
+ /*margin: 15px;*/
+ /*font-size: 20px;*/
+}
+.short-lines {
+ line-height: 3em;
+}
+.main-line{
+ border: 3px green solid;
+ border-radius: 5px;
+ /*margin: 10px;*/
+}
+.side-line {
+ /*padding-top: 10px;*/
+ /*margin: 10px;*/
+ border:2px red solid;
+ border-radius: 5px;
+ min-height: 200px;
+}
+.card-line{
+ margin-bottom: 5px;
+}
+.left-list ul{
+ padding-left: 5px;
+}
+.hypotheses select{
+ height:20px;
+ padding:1px;
+
+}
+.guess-correct{
+
+}
+.guess-wrong{
+
+}
diff --git a/index.html b/index.html
index f43573d..ce41327 100644
--- a/index.html
+++ b/index.html
@@ -11,11 +11,10 @@
-
+
-
@@ -23,14 +22,7 @@
-
-
-
+
+
- Elements
+ Hand
-
-
+
{{r.key}}
- {{r.state.amount}}
+ {{r.state.amount}}
@@ -112,111 +103,142 @@
-
-
+
+
+
+
+
+
Score
+ {{ lc.lab.state.score | niceNumber }}
+
+
+
+
+
-
-
-
- Your detector. Click on it to generate events.
-
-
🂠
-
-
+
+
+
+
+
+
+
+
+
Hint
+
(-{{dc.hintCost}} score)
+
+
+
+
+
+
+
+
Rule
+
(-{{dc.ruleCost}} score)
+
+
+ {{dc.rule}}
+
+
+
+
+
+
+
-
+
-
+
-
-
-
-
- Observations
-
-
-
-
- Upgrades
+ Guess the rule
@@ -241,6 +263,7 @@
+
+
+
+
+
+
-
-
-
-
+
+
+
-
+
+
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
diff --git a/js/app.js b/js/app.js
index db57dff..9d2ed60 100644
--- a/js/app.js
+++ b/js/app.js
@@ -8,6 +8,80 @@ var app = (function () {
var app = angular.module('scienceAlchemy', ['ngDragDrop', 'ui.grid']);
// directives
+ /**
+ * Provides an easy way to toggle a checkboxes indeterminate property
+ *
+ * @example
+ */
+ // app.directive('uiIndeterminate', [
+ // function () {
+ //
+ // return {
+ // compile: function (tElm, tAttrs) {
+ // if (!tAttrs.type || tAttrs.type.toLowerCase() !== 'checkbox') {
+ // return angular.noop;
+ // }
+ //
+ // return function ($scope, elm, attrs) {
+ // $scope.$watch(attrs.uiIndeterminate, function (newVal) {
+ // elm[0].indeterminate = !!newVal;
+ // });
+ // };
+ // }
+ // };
+ // }
+ // ]);
+
+
+ /**
+ * Directive to render a rule and bind it's option with select boxes
+ * This expects ng-model="rule" as an attribute
+ */
+ function cfsRule($compile) {
+ return {
+ link: function (scope, element, attrs) {
+ scope.$eval("$index");
+ var rule = scope.$eval(attrs.ngModel);
+
+ // first generate a select box for each option (using lodash templating)
+ _.templateSettings.interpolate = /<%=([\s\S]+?)%>/g;
+ var optionTmpl = '' +
+ '
\n' +
+ ' \n';
+
+ var tmplParams = _.defaults({},rule.options,rule.otherOptions);
+ for (var option in rule.optionDesc) {
+ if (rule.optionDesc.hasOwnProperty(option)) {
+ var vals = rule.optionDesc[option].possibleVals;
+ if (vals) {
+ tmplParams[option] = _.template(optionTmpl)({
+ option: option
+ });
+ } else {
+ // if there are no options replace '{{color}}' with 'color'
+ tmplParams[option] = option;
+ }
+ }
+ }
+ // now put each select box into description
+ // replace '{{color}}' with '
0) {
- lab.acquireData(sum);
- UI.showUpdateValue("#update-data", sum);
- detector.addEventExternal(game.workers.map(function (w) {
- return w.state.hired;
- }).reduce(function (a, b) {
- return a + b;
- }, 0));
- }
- }, 1000);
};
- LabController.$inject = ['$interval', 'game', 'detector', 'lab'];
+ LabController.$inject = ['$interval', 'game', 'lab'];
app.controller('LabController', LabController);
- function ObservationsController($scope, game, lab) {
- var vm = this;
- vm.observations = lab.state.observations;
- vm.gridOptions = {
- enableFiltering: true,
- columnDefs: [{
- field: 'inputs',
- 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'
- }
- }, {
- field: 'catalysts',
- visible: false
- }, {
- field: 'conditions',
- visible: false
- }, ],
- data: vm.observations
- };
- };
- ObservationsController.$inject = ['$scope', 'game', 'lab'];
- app.controller('ObservationsController', ObservationsController);
-
function UpgradesController($scope, game, lab) {
var vm = this;
+ // present just a few hypothesis
+ var rules = Rules.rules.map(function (r) {
+ return angular.copy(r);
+ });
+ 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.upgrades = game.upgrades;
vm.isVisible = function (upgrade) {
return upgrade.isVisible(lab, game.allObjects);
@@ -245,6 +284,30 @@ var app = (function () {
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';
+ else return '';
+
+ };
+ vm.guess = function (e, rule) {
+ var params = angular.element(e.target).parent('form').serializeArray();
+
+ var sameRule = rule.description == game.rule.description;
+ var sameOpts = angular.equals(rule.options, game.rule.options);
+ if (sameRule && sameOpts) {
+ // right!
+ lab.state.score += 200;
+ if (!rule.state) rule.state={};
+ rule.state.guessed=true;
+ } else {
+ lab.state.score -= 200;
+ rule.state.guessed=false;
+ }
+
+ console.log('guess', arguments);
+ };
};
UpgradesController.$inject = ['$scope', 'game', 'lab'];
app.controller('UpgradesController', UpgradesController);
diff --git a/js/detector/bubblr.js b/js/detector/bubblr.js
deleted file mode 100644
index 889b045..0000000
--- a/js/detector/bubblr.js
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- Bubblr v1.0 - http://mikeyhogarth.wordpress.com/2012/04/15/bubblr-jquery-bubbles-plugin/
- Copyright (c) 2012 Mikey Hogarth
- template based on original jquery lightweight plugin biolerplate: @ajpiano, @addyosmani
- This plugin available for use in all personal or commercial projects under both MIT and GPL licenses.
-*/
-
-(function ($, window, document, undefined) {
-
- var pluginName = "bubblr";
-
- /** default options **/
- var defaults = {
- numberOfBubbles: 10,
- backgroundColor: "transparent",
- bubbleColor: "White",
- bubbleOpacity: 0.7,
- bubbleMinSize: 1,
- bubbleMaxSize: 2,
- bubbleMaxSpeed: 2,
- bubbleMinSpeed: 1,
- animationSpeed: 10
- };
-
- /**
- * Create the bubblr
- * @param {dom element} element - dom canvas element
- * @param {object} options - options see Bubblr._defaults for options
- */
- function Bubblr(element, options) {
- this.element = element;
- this.options = $.extend({}, defaults, options);
- this._defaults = defaults;
- this.state = {
- bubbles: [],
- started: false,
- globalTick: 0,
- genBubbles: false,
- }
- this.init();
- this.start();
- }
-
- Bubblr.prototype.init = function () {
-
- if (this.element.getContext) {
- this.ctx = this.element.getContext("2d");
- } else {
- return;
- }
-
- $canvas = $(this.element);
-
- this.width = $canvas.width();
- this.height = $canvas.height();
-
- $canvas.css("background-color", this.options.backgroundColor)
-
- // initial bubbles
- for (i = 0; i < this.options.numberOfBubbles; i++) {
- this.state.bubbles[i] = this.generateBubble();
- }
- for (i in this.state.bubbles) {
- this.drawBubble(this.state.bubbles[i]);
- }
-
- };
-
- /**
- * Recenter on resize,
- * bind this to $(window).on('resize',bubblr.onResize.bind(bubblr);) if needed
- **/
- Bubblr.prototype.onResize = function () {
- this.clear();
- this.width = $(this.element).outerWidth();
- this.height = $(this.element).outerWidth();
- };
-
- /** Start animation loop if not started **/
- Bubblr.prototype.start = function () {
- if (!this.state.started) {
- this.state.started = true;
- this.animationLoop();
- }
- };
-
- /** Stop animation loop **/
- Bubblr.prototype.stop = function () {
- this.state.started = false;
- this.clear();
- };
-
- /** Animation loop run Bubblr.stop and start control this **/
- Bubblr.prototype.animationLoop = function () {
- window.requestAnimFrame(this.animationLoop.bind(this));
- this.state.globalTick++;
- if (this.state.started) this.animate();
- };
-
- Bubblr.prototype.animate = function (arguments) {
- this.clear();
- for (i in this.state.bubbles) {
- this.update(i, this.state.bubbles[i]);
- this.draw(i, this.state.bubbles[i]);
- }
-
- // clear bubbles where y<0 (pop em)
- var toRemove = this.state.bubbles.findIndex(function (b) {
- return b.y < 0;
- });
- for (var i = 0; i < toRemove.length; i++) {
- var bubble = this.state.bubbles.splice(toRemove[i], 1)[0];
- //bubble.pop();
- }
-
- };
-
- Bubblr.prototype.clear = function () {
- this.ctx.globalAlpha = 1;
- this.ctx.fillStyle = this.options.backgroundColor;
- this.ctx.clearRect(0, 0, this.width, this.height);
- };
-
-
- Bubblr.prototype.draw = function (index, bubble) {
- this.ctx.globalAlpha = this.options.bubbleOpacity;
- this.drawBubble(bubble);
- };
-
- /** Update bubble position **/
- Bubblr.prototype.update = function (index, bubble) {
- bubble.y = bubble.y - bubble.speed
-
- if (bubble.y < 0 && this.state.continuous)
- // reset to bottom if continuous running is on
- this.state.bubbles[index] = this.generateBubble(true);
- else {}
-
- };
-
- /**
- * Generate a single bubble
- * @param {object} options - options for the bubble
- * @param {Number} options.x - Starting x position. Defaults to a random
- * location.
- * @param {Number} options.y - starting y level. Default to the bottom or
- * null for random position, a number sets a
- * specific level. Note the top is 0, while the
- * bottom is `-$(element).height()`
- */
- Bubblr.prototype.bubble = function (options) {
- this.state.bubbles.push(this.generateBubble(options));
- };
-
- /**
- * Helper to generate multiple bubble
- * @param {[type]} amount - amount of bubbles to create
- * @param {[type]} options - see Bubblr.bubble for description
- */
- Bubblr.prototype.genBubbles = function (amount, options) {
- for (var i = 0; i < amount; i++) {
- this.state.bubbles.push(this.generateBubble(options));
- }
- }
-
- Bubblr.prototype.drawBubble = function (bubble) {
- this.ctx.fillStyle = this.options.bubbleColor;
- this.ctx.beginPath();
- this.ctx.arc(bubble.x, bubble.y, bubble.radius, 0, Math.PI * 2, true);
- this.ctx.closePath();
- this.ctx.fill();
- };
-
- Bubblr.prototype.generateBubble = function (options) {
- options = options || {};
- var bubble = new Object();
-
-
- if (options.x === undefined || options.x === null)
- bubble.x = this.randomize(1, this.width);
- else
- bubble.x = options.x
-
- if (options.y === undefined)
- bubble.y = this.height;
- else if (options.y === null)
- bubble.y = this.randomize(1, this.height);
- else
- bubble.y = options.y
-
- if (options.radius)
- bubble.radius = options.radius
- else
- bubble.radius = this.randomize(this.options.bubbleMinSize, this.options.bubbleMaxSize);
-
- if (options.speed)
- bubble.speed = options.speed;
- else
- bubble.speed = this.randomize(this.options.bubbleMinSpeed, this.options.bubbleMaxSpeed);
-
- return bubble;
- };
-
- Bubblr.prototype.randomize = function (min, max) {
- return Math.floor((Math.random() * max) + min);
- };
-
- // $.flame will create or return the bubblr element
- $.fn[pluginName] = function (options) {
- return this.each(function () {
- if (!$.data(this, 'plugin_' + pluginName)) {
- $.data(this, 'plugin_' + pluginName,
- new Bubblr(this, options));
- }
- });
- }
-
-})(jQuery, window, document);
-
-// shim for requestAnimFrame
-window.requestAnimFrame = (function () {
- return window.requestAnimationFrame ||
- window.webkitRequestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- window.oRequestAnimationFrame ||
- window.msRequestAnimationFrame ||
- function ( /* function */ callback, /* DOMElement */ element) {
- window.setTimeout(callback, 1000 / 60);
- };
-})();
diff --git a/js/detector/detector.js b/js/detector/detector.js
index 6ab4c45..9f548c1 100644
--- a/js/detector/detector.js
+++ b/js/detector/detector.js
@@ -5,6 +5,8 @@ var Detector = function(){
return {
elements: new GameObjects.Cards(),
+ lastCards: new GameObjects.Cards(),
+ incorrectCards: new GameObjects.Cards(),
visible: true,
@@ -17,70 +19,12 @@ var Detector = function(){
bubblr: undefined,
- init: function()
+ init: function(game)
{
- // this.initBubbles();
- // this.initFlame();
+ // deal first card
+ this.lastCards.push(_.sample(game.elements));
},
- initBubbles: function(){
- // init the test tube animation
- var bubblrElem = $('#detector-core').bubblr({
- backgroundColor: '#e8e8e8',
- bubbleColor: "#bfbfbf",
- bubbleMinSize: 3,
- bubbleMaxSize: 5,
- bubbleMaxSpeed: 2,
- bubbleMinSpeed: 1,
- animationSpeed: 20,
- // bubbleXposMultiplier allows us to position bubbles on the x-axis
- bubbleXposMultiplier: 2,
- // bubbleYpopLimit determines how far in pixels from the canvas's
- // top edge bubbles will disappear
- bubbleYpopLimit: 10
- });
- this.bubblr = bubblrElem.data('plugin_bubblr');
- },
-
- // initFlame: function(){
- // var flameElem = $('#detector-flame').flame();
- // this.flamer = flameElem.data('plugin_flame')
- // },
-
- bindOnResize: function(){
- // HACK
- $(window).on('resize',this.onResize.bind(this));
- },
-
- // onResize: function(){
- // // TODO, do one, schedule a check and then prevent firing until then
- // if ($(window).width() >= 1200) {
- // if (this.width != 500) {
- // $('#detector').width(500).height(500);
- // this.init(500);
- // }
- // } else if ($(window).width() < 768 && $(window).height() - 90 < 300) {
- // var newWidth = $(window).width() - Math.max($(window).width() - ($(window).height() - 90 + 10), 300) - 10;
- // if (this.width != newWidth) {
- // $('#detector').width(newWidth).height(newWidth);
- // this.init(newWidth);
- // }
- // } else if ($(window).width() < 992) {
- // if (this.width != 300) {
- // $('#detector').width(300).height(300);
- // this.init(300);
- // }
- // } else {
- // if (this.width != 400) {
- // $('#detector').width(400).height(400);
- // this.init(400);
- // }
- // }
- //
- // this.bubblr.onResize();
- // this.flamer.onResize();
- // },
-
/** When a user clicks the detector **/
addEvent: function()
{
@@ -99,19 +43,6 @@ var Detector = function(){
// this.bubblr.bubble();
},
- /** Clear an element back to element Store **/
- storeElementBy: function(qObject,game){
- var i = _.findIndex(this.elements,qObject);
- var removedElement = this.elements.splice(i,1)[0];
- return game.elements.get(removedElement.key).state.amount+=1;
- },
-
- clearAll: function(game){
- var hashKeys = this.elements.map(function(e){return e.$$hashKey;});
- for (var i = 0; i < hashKeys.length; i++) {
- this.storeElementBy({'$$hashKey': hashKeys[i]}, game);
- }
- },
onDrop: function(event, ui, game){
var self=this;
@@ -122,60 +53,15 @@ var Detector = function(){
// if the dragger came from the elements panels, clone it to here
var newElement;
if ($draggable.hasClass('element-store')){
-
var elementStore = game.elements.filter(function(e){return e.key==$draggable.data('element');})[0];
elementStore.state.amount-=1;
newElement = angular.copy(elementStore);
- newElement.state.top=$draggable.offset().top;
- newElement.state.left=$draggable.offset().left;
this.elements.push(newElement);
}
-
- // get everything intersecting the drop
- var draggableTop = $draggable.offset().top;
- var draggableHeight = $draggable.height();
- var draggableBottom = draggableTop + draggableHeight;
- var draggableLeft = $draggable.offset().left;
- var draggableWidth = $draggable.height();
- var draggableRight = draggableLeft + draggableWidth;
- var detectorDOMElems = angular.element('#detector').find('.element').not('.element-store'); // replace with detector.elements
- var intersectingDOMElems = detectorDOMElems.filter( function() {
- var $elem = angular.element(this);
- var top = $elem.offset().top;
- var height = $elem.height();
- var bottom = top + height;
-
- var left = $elem.offset().left;
- var width = $elem.width();
- var right = left + width;
-
- var isCoveredByDraggable = top <= draggableBottom && bottom >= draggableTop
- && left <= draggableRight && right >= draggableLeft;
- return isCoveredByDraggable;
- });
-
- // We have the DOM's in the area (maybe missing the newly dropped one)
- // var droppedModel = game.elements.getByHashKey($draggable.data('hashkey'));
- var intersectingElements = intersectingDOMElems.toArray().map(function(input){
- return self.elements.getByHashKey(angular.element(input).data('hashkey'));
- });
-
- // make sure we include the dropped element as in some cases
- // it wont have DOM object yet so it wont be picked up as intersecting
- if (newElement && intersectingElements.indexOf(newElement)===-1) intersectingElements.push(newElement);
-
-
- 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;
- }
-
-
+ var observation = game.test
+ console.log('intersectingElements', intersectingElements.length, observation);
+ return observation;
},
/** Run an experiment depending on reactants and conditions **/
diff --git a/js/detector/flame.js b/js/detector/flame.js
deleted file mode 100644
index d4614ec..0000000
--- a/js/detector/flame.js
+++ /dev/null
@@ -1,219 +0,0 @@
-
-/**
- * @name Flame
- * @description jquery plugin to generate flame on a canvas element..
- * Based on http://codepen.io/jackrugile/pen/Jbnpv
- * @copyright (c) 2015 wassname
- * @license: MIT
- */
-;(function ( $, window, document, undefined ) {
- var pluginName = "flame";
-
- var defaults = {
- hueRange: 50,
- };
-
- var defaultState = {
- parts: [],
- partCount: 200,
- partsFull: false,
- on: true,
- rendering: false,
- globalTick: 0,
- width: null,
- height: null,
- }
-
- var Part = function(flame){
- this.flame=flame;
- this.ctx=this.flame.ctx;
- this.reset();
- };
-
-
- Part.prototype.reset = function(){
- this.startRadius = this.rand(1, 25);
- this.radius = this.startRadius;
- this.width = this.flame.state.width;
- this.height = this.flame.state.height;
- this.x = this.width/2 + (this.rand(0, 6) - 3);
- this.y = 250;
- this.vx = 0;
- this.vy = 0;
- this.hue = this.rand(this.flame.state.globalTick - this.flame.options.hueRange, this.flame.state.globalTick + this.flame.options.hueRange);
- this.saturation = this.rand(50, 100);
- this.lightness = this.rand(20, 70);
- this.startAlpha = this.rand(1, 10) / 100;
- this.alpha = this.startAlpha;
- this.decayRate = 0.1;
- this.startLife = 7;
- this.life = this.startLife;
- this.lineWidth = this.rand(1, 3);
- }
-
- Part.prototype.update = function(){
- this.vx += (this.rand(0, 200) - 100) / 1500;
- this.vy -= this.life/50;
- this.x += this.vx;
- this.y += this.vy;
- this.alpha = this.startAlpha * (this.life / this.startLife);
- this.radius = this.startRadius * (this.life / this.startLife);
- this.life -= this.decayRate;
- if(
- this.x > this.width + this.radius ||
- this.x < -this.radius ||
- this.y > this.height + this.radius ||
- this.y < -this.radius ||
- this.life <= this.decayRate
- ){
- this.reset();
- }
- };
-
- Part.prototype.render = function(){
- this.ctx.beginPath();
- this.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
- this.ctx.fillStyle = this.ctx.strokeStyle = 'hsla('+this.hue+', '+this.saturation+'%, '+this.lightness+'%, '+this.alpha+')';
- this.ctx.lineWidth = this.lineWidth;
- this.ctx.fill();
- this.ctx.stroke();
- };
-
- Part.prototype.rand = function(min, max){
- return Math.floor( (Math.random() * (max - min + 1) ) + min);
- };
-
- var Flame = function(element, options){
- this.element = element;
- this.options = $.extend( {}, defaults, options) ;
- this._defaults = defaults;
- this.init();
- };
-
- Flame.prototype.init = function (arguments) {
- if(this.element.getContext) {
- this.ctx = this.element.getContext("2d");
- } else {
- return;
- }
- if (this.state) this.stop();
- this.state = $.extend( {parts: [],partsFull: false,globalTick: 0,}, defaultState, this.state);
- // this.state = {
- // parts: [],
- // partCount: 200,
- // partsFull: false,
- // on: true,
- // rendering: false,
- // globalTick: 0,
- // width: null,
- // height: null,
- // }
- this.state.width = $(this.element).outerWidth();
- this.state.height = $(this.element).outerWidth();
- this.start();
- }
-
- /** If needed: $(window).on('resize',this.onResize.bind(this) **/
- Flame.prototype.onResize = function (arguments) {
- this.init();
- }
-
- Flame.prototype.createParts = function(){
- if(this.state.parts.length > this.state.partCount){
- this.state.partsFull = true;
- } else {
- this.state.parts.push(new Part(this));
- }
- };
-
- Flame.prototype.updateParts = function(){
- var i = this.state.parts.length;
- while(i--){
- this.state.parts[i].update();
- }
- };
-
- Flame.prototype.renderParts = function(){
- var i = this.state.parts.length;
- while(i--){
- this.state.parts[i].render();
- }
- };
-
- Flame.prototype.clear = function (arguments) {
- this.ctx.globalAlpha = 1;
- this.ctx.fillStyle = 'hsla(0, 0%, 0%, .0)';
- this.ctx.clearRect(0,0,this.state.width, this.state.height);
- }
-
- /** Fades the previous flames into opacity to product a blur **/
- Flame.prototype.fade = function(){
- this.ctx.globalCompositeOperation = 'destination-out';
- this.ctx.fillStyle = 'hsla(0, 0%, 0%, .3)';
- this.ctx.fillRect(0, 0, this.state.width, this.state.height);
- this.ctx.globalCompositeOperation = 'lighter';
- };
-
- Flame.prototype.draw = function (arguments) {
- this.fade();
- if (this.state.on){
- this.createParts();
- } else if (this.state.parts.length>1){
- this.state.parts.pop();
- }
- this.updateParts();
- this.renderParts();
- }
-
- Flame.prototype.start = function (arguments) {
- if (!this.state.rendering){
- this.state.rendering=true
- this.animate();
- return this
- } else {return;}
- }
-
- Flame.prototype.stop = function (arguments) {
- this.state.rendering=false;
- this.clear();
- return this;
- }
-
- /** Toggle fuel and the flame will burn down or up again **/
- Flame.prototype.toggleFuel = function (state) {
- if (state===undefined)
- this.state.on=!this.state.on;
- else
- this.state.on=state;
- return this.state.on;
- }
-
- Flame.prototype.animate = function(){
- window.requestAnimFrame(this.animate.bind(this),this.element);
- this.state.globalTick++;
- if (this.state.rendering) this.draw();
- };
-
- $.fn[pluginName] = function ( options ) {
- return this.each(function () {
- if (!$.data(this, 'plugin_' + pluginName)) {
- $.data(this, 'plugin_' + pluginName,
- new Flame( this, options ));
- }
- });
- }
-
- // shim for requestAnimFrame
- window.requestAnimFrame = (function(){
- return window.requestAnimationFrame ||
- window.webkitRequestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- window.oRequestAnimationFrame ||
- window.msRequestAnimationFrame ||
- function(/* function */ callback, /* DOMElement */ element){
- window.setTimeout(callback, 1000 / 60);
- };
- })();
-
-
-})( jQuery, window, document );
diff --git a/js/game.js b/js/game.js
index 1a916d8..6bf6ff5 100644
--- a/js/game.js
+++ b/js/game.js
@@ -5,7 +5,7 @@ var Game = (function (Helpers, GameObjects, ObjectStorage) {
'use strict';
var Game = function () {
- // this.lab = new GameObjects.Lab();
+ this.lab = null;
this.elements = null;
this.workers = null;
this.upgrades = null;
@@ -14,7 +14,11 @@ var Game = (function (Helpers, GameObjects, ObjectStorage) {
// lab: this.lab
};
this.loaded = false;
- this.rules = null;
+ this.rules = Rules.rules;
+ this.rule=undefined;
+
+ this.lastCards= [];
+ this.incorrectCards= [];
};
Game.prototype.load = function ($http, $q) {
@@ -28,10 +32,7 @@ var Game = (function (Helpers, GameObjects, ObjectStorage) {
// make it work with Angular. If you know a way, let me know, and I'll
// give you a beer. - Kevin
this.elements = Helpers.loadFile('json/elements.json');
- this.workers = Helpers.loadFile('/json/workers.json');
- this.upgrades = Helpers.loadFile('./json/upgrades.json');
this.achievements = Helpers.loadFile('./json/achievements.json');
- this.keywords = Helpers.loadFile('./json/keywords.json');
// function successCallback(response) {
// return angular.fromJson(response.data);
@@ -88,14 +89,6 @@ var Game = (function (Helpers, GameObjects, ObjectStorage) {
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);
@@ -110,158 +103,88 @@ var Game = (function (Helpers, GameObjects, ObjectStorage) {
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;
- // });
};
- 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;
+ Game.prototype.init = function () {
+ // setup game
+ this.rule = _.sample(Rules.rules);
+ this.rule.randomize();
+
+ // check if we have any cards in hand
+ // var totalElements = _(self.elements).map('state.amount').sum();
+ // if (totalElements<1) self.dealHand();
+ this.dealHand();
+
+ // deal first card
+ // TODO make sure these follow rule
+ this.lastCards.push.apply(this.lastCards,_.sampleSize(this.elements,3));
+ for (var i = 0; i < this.lastCards.length; i++) {
+ this.incorrectCards[i]=[];
+ }
+
+ // reset score
+ this.lab.state.score = 200;
+ return self;
+ };
+
+ Game.prototype.dealHand = function (n) {
+ n=n||12;
+ var hand=_.sampleSize(this.elements,n);
+ this.elements.map(function(card){
+ card.state.amount=0;
});
- // but give us a random 4 number cards of one suite
- var startSuit = _.sample(["Spades", "Hearts", "Diamonds", "Clubs"]);
+ for (var i = 0; i < hand.length; i++) {
+ var card = hand[i];
+ this.elements.get(card.key).state.amount++;
+ }
- 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;
- }
+ };
+ Game.prototype.onClick = function (event, ui) {
+ var self=this;
+ console.debug('onClick',arguments);
- /** Generate rules between runes **/
- Game.prototype.generateRules = function () {
+ var cardType = angular.element(ui.draggable).data('element');
+ var card = _.find(this.elements,{key:cardType});
+ return this.play(card);
+ };
+ Game.prototype.onDrop = function (event, ui) {
+ var self=this;
+ console.debug('onDrop',arguments);
- /**
- * 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 cardType = angular.element(ui.draggable).data('element');
+ var card = _.find(this.elements,{key:cardType});
+ return this.play(card);
+ };
+ Game.prototype.play = function (card) {
+ var self=this;
+ card.state.amount-=1;
- var rules = ObjectStorage.load('rules');
- if (!rules) {
+ var turn = this.lastCards.length-1;
+ var correct = this.test(card);
+ if (correct){
+ if(!this.incorrectCards[turn]) this.incorrectCards[turn]=[];
+ this.lastCards.push(angular.copy(card));
+ if(!this.incorrectCards[turn+1]) this.incorrectCards[turn+1]=[];
+ this.lab.state.score+=1;
+ } else {
+ // add incorrect one to sidelines
+ if (!this.incorrectCards[turn]) this.incorrectCards[turn]=[];
+ this.incorrectCards[turn].push(angular.copy(card));
- 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);
- }
- }
-
- // 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.save('rules', rules);
- return rules;
- },
- /**
- * 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
- };
- };
+ // deal 2 random cards
+ _.sample(this.elements).state.amount+=1;
+ _.sample(this.elements).state.amount+=1;
+ this.lab.state.score-=1;
+ }
+ return correct;
+ };
+ /** Test the rule **/
+ Game.prototype.test = function (card) {
+ return this.rule.test(card,this.lastCards,this.elements);
+ };
Game.prototype.save = function () {
// Save every object's state to local storage
for (var key in this.allObjects) {
diff --git a/js/gameobjects.js b/js/gameobjects.js
index f6968db..29c7094 100644
--- a/js/gameobjects.js
+++ b/js/gameobjects.js
@@ -37,7 +37,7 @@ var GameObjects = (function () {
GameObject.apply(this, [{
key: 'lab',
state: {
- name: 'Click here to give your lab an awesome name!',
+ name: 'Write your name here',
detector: 1,
factor: 5,
data: 0,
@@ -50,6 +50,11 @@ var GameObjects = (function () {
dataSpent: 0,
time: 0,
observations: [],
+ score: 0,
+ highScore: 0,
+ hints: 0,
+ rulesGuessed: [],
+ rulesFailed: [],
}
}]);
diff --git a/js/rules.js b/js/rules.js
index 915aab3..120b89b 100644
--- a/js/rules.js
+++ b/js/rules.js
@@ -5,13 +5,7 @@
*/
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
@@ -23,93 +17,162 @@ var Rules = (function functionName(_) {
* @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.
+ * `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)
+ 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');
+ 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;
+ this.optionDesc = optionDesc || {};
+ this.options = this.optionDefaults = optionDefaults || {};
+ this.hintTmpls = hintTmpls || [];
// init
+ this.state = {};
this.hintsUsed = 0;
- this.hints=this.genHints();
+ this.otherOptions={nth:this.nth,lastn:this.lastn};
+ this.hints = this.genHints();
};
Rule.prototype.setOptions = function (options) {
this.options = _.defaults(options, this.optionDefaults);
- this.hints=this.genHints();
+ this.hints = this.genHints();
return this.options;
};
+ Rule.prototype.randomize = function (options) {
+ var options = {};
+ for (var option in this.optionDesc) {
+ if (this.optionDesc.hasOwnProperty(option)) {
+ var vals = this.optionDesc[option].possibleVals;
+ options[option] = _.sample(vals);
+ }
+ }
+ return this.setOptions(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');
+ // 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;
+ if (result instanceof chai.Assertion) {
+ reason = result;
+ result = true;
}
} catch (e) {
- if (e instanceof chai.AssertionError){
+ if (e instanceof chai.AssertionError) {
result = false;
- reason=e;
- } else {throw(e);}
+ reason = e;
+ } else {
+ throw (e);
+ }
}
- return {result:result,reason:reason};
+ return {
+ result: result,
+ reason: reason
+ };
};
Rule.prototype.test = function (card, lastCards, allCards) {
- var res = this.testAndTell(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);
};
+ // 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 = '\n';
+ // for (var i = 0; i < vals.length; i++) {
+ // s += '' + vals[i] + ' \n';
+ // }
+ // s += ' \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 = '' +
+ // '\n' +
+ // '{{v}} \n' +
+ // ' \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);
- return compiled(_.defaults(options,this.options));
+ return compiled(_.defaults(options, this.options, this.otherOptions));
};
/** 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 ';
+ 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';
+ // 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);
+ 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="";
+ 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';
+ var options = {};
+ options[option] = vals[i];
+ var v = this.describeVariation(options) + '\n';
+ s.push(v);
}
}
@@ -120,13 +183,13 @@ var Rules = (function functionName(_) {
Rule.prototype.nextHint = function () {
var hint = this.hints[this.hintsUsed];
this.hintsUsed++;
- return hint||"";
+ return hint || "";
};
/** Generate an automatic hint from params **/
Rule.prototype.genHints = function () {
// first manual hints
- this.hintsUsed=0;
+ this.hintsUsed = 0;
var hints = [];
// compile hints for each unused property
@@ -138,15 +201,15 @@ var Rules = (function functionName(_) {
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;
+ if (posVals) {
+ var optionUnused = _.difference(posVals, [this.options[option]]);
+ unusedOptions[option + 'Unused'] = optionUnused;
}
}
}
// copy options
- var tmplParams = _.extend({},this.options);
+ var tmplParams = _.defaults({}, this.options, this.otherOptions);
// make hint from unused options if there are hint templates for them
@@ -156,12 +219,12 @@ var Rules = (function functionName(_) {
// 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){
+ 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];
+ tmplParams[optionUnused] = unused[j];
var hint = tmplCmp(tmplParams);
hints.push(hint);
}
@@ -181,22 +244,51 @@ var Rules = (function functionName(_) {
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);
+ 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;
+ var pos = _.map(this.optionDesc, 'possibleVals');
+ var c = 0;
for (var i = 0; i < pos.length; i++) {
- c*pos[i].length;
+ c * pos[i].length;
}
return c;
};
// TODO estimate hardness perhaps through simulation, combinatorics or hints
+ /** Helper to format numbers **/
+ Rule.prototype.nth = function (d) {
+ if (d > 3 && d < 21) return 'th'; // thanks kennebec
+ switch (d % 10) {
+ case 1:
+ return "st";
+ case 2:
+ return "nd";
+ case 3:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ /** Helper to format numbers **/
+ Rule.prototype.lastn = function (d) {
+ if (d > 3 && d < 21) return d+'th to last'; // thanks kennebec
+ switch (d % 10) {
+ case 1:
+ return d+" st to last";
+ case 2:
+ return d+" nd to last";
+ case 3:
+ return d+" rd to last";
+ default:
+ return d+" th to last";
+ }
+ };
+
// Now defined actual rules
var rules = [];
@@ -205,40 +297,286 @@ var Rules = (function functionName(_) {
// 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",
+ "Next card must not have the same <%= property %> as the <%= lastn(n) %> card",
function (card, lastCards, allCards, options) {
- var lastNCard = lastCards[this.options.n-1];
+ var lastNCard = lastCards[lastCards.length - this.options.n];
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'],
+ possibleVals: ['color', 'face', 'number', 'value', 'suit'],
type: 'String'
},
n: {
description: 'Number for how many cards back. Start counting at 1',
- possibleVals: [1,2,3],
+ 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',
+ }, [
+ 'This rule does not involve <%= propertyUnused %>',
+ 'This rule does involve <%= property %>',
+ 'This rule does involve the <%= n %><%=nth(n)%> last card',
+ 'This rule does not involve the <%= nUnused %><%=nth(n)%> last card', // only indirectly
+ ]
+ ),
+ new Rule(
+ "If last <%= n %><%=nth(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)
+ .to.have.property('value')
+ .not.within(options.min, options.max);
+ else
+ return chai.expect(card)
+ .to.have.property('value')
+ .within(options.min, options.max);
+ }, {
+ n: 1,
+ min: 0,
+ max: 7
+ }, {
+ min: {
+ description: 'The min bounds to compare value to',
+ possibleVals: [0, 1, 2, 3, 4, 5],
+ type: 'Number'
+ },
+ max: {
+ description: 'The max bounds to compare value to',
+ possibleVals: [7, 8, 9, 10, 11, 12, 13, 14, 15],
+ type: 'Number'
+ },
+ n: {
+ description: 'Number for how many cards back. Start counting at 1',
+ possibleVals: [1, 2, 3],
+ type: 'Number'
+ }
+ }, [
+ 'This rule does not involve color',
+ 'This rule does not involve if it\'s a face card',
+ 'This rule does not involve royalty',
+ 'This rule does not involve color',
+ 'This rule does not involve suit',
+ 'This rule does not involve the <%= nUnused %><%=nth(nUnused)%> last card',
+ 'This rule does involve value',
+ 'This rule does involve a value cuttoff',
+ 'This rule does involve the <%= n %><%=nth(n)%> last card',
+ ]
+ ),
+ new Rule(
+ "Play a card with a value <%= min %> to <%= max %> higher than the value of the last <%=n%><%=nth(n)%> card. The numbers wrap around once they reach the max",
+ 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)
+ .to.have.property('value')
+ .not.within(options.min, options.max);
+ else
+ return chai.expect(card)
+ .to.have.property('value')
+ .within(options.min, options.max);
+ }, {
+ n: 1,
+ min: 1,
+ max: 4
+ }, {
+ min: {
+ description: 'The min difference to the last nth card',
+ possibleVals: [1, 2, 3],
+ type: 'Number'
+ },
+ max: {
+ description: 'The max difference to the last nth card',
+ possibleVals: [4, 5, 6, 7, 8],
+ type: 'Number'
+ },
+ n: {
+ description: 'Number for how many cards back. Start counting at 1',
+ possibleVals: [1, 2, 3],
+ type: 'Number'
+ }
+ }, [
+ 'This rule does not involve color',
+ 'This rule does not involve if it\'s a face card',
+ 'This rule does not involve royalty',
+ 'This rule does not involve color',
+ 'This rule does not involve suit',
+ 'This rule does not involve the <%= nUnused %><%=nth(nUnused)%> last card',
+ 'This rule does involve value',
+ 'This rule does involve the difference in value to the last card',
+ 'This rule does involve the difference in values that wraps around',
+ 'This rule does involve the difference in values of at least <%= min %>',
+ 'This rule does involve the <%= n %><%=nth(n)%> last card',
+ ]
+ ),
+
+
+
+ new Rule(
+ "If the last <%= n %><%=nth(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];
+ var lastWasEven = lastNCard % 2 == 0;
+ if (lastWasEven)
+ return chai.expect(card)
+ .to.have.property('color')
+ .equals(options.evenColor);
+ else
+ return chai.expect(card)
+ .to.have.property('color')
+ .not.equals(options.evenColor);
+ }, {
+ n: 1,
+ evenColor: 'red',
+ }, {
+ evenColor: {
+ description: 'The color to play if lastNCard was even',
+ possibleVals: ['red', 'black'],
+ 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 if it\'s a face card',
+ 'This rule does not involve royalty',
+ 'This rule does not involve suit',
+ 'This rule does not involve the <%= nUnused %><%=nth(nUnused)%> last card',
+ 'This rule does not involve the difference in value to the last card',
+ 'This rule does involve color',
+ 'This rule does involve value',
+ 'This rule does involve the <%= n %><%=nth(n)%> last card',
+ ]
+ ),
+
+ new Rule(
+ "Play a card that has the same <%= property %> or color as the last <%= n %><%=nth(n)%> card but not both.",
+ function (card, lastCards, allCards, options) {
+ var lastNCard = lastCards[lastCards.length - options.n];
+ var matchesColor = lastNCard.color === card.color;
+ var matches2 = lastNCard.suit === lastNCard.suit;
+ return ((matchesColor && !matches2) || (!matchesColor && matches2));
+ }, {
+ n: 1,
+ property: 'suit',
+ }, {
+ property: {
+ description: 'The property to compare to the lastNCard',
+ possibleVals: ['suit', 'value', 'face', 'royal'],
+ 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 the <%= nUnused %><%=nth(nUnused)%> last card',
+ 'This rule does involve color',
+ 'This rule does not involve <%= propertyUnused %>',
+ 'This rule does involve <%= property %>',
+ 'This rule does involve the <%= n %><%=nth(n)%> last card',
+ ]
+ ),
+
+ new Rule(
+ "If the last <%= n %><%=nth(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];
+ var lastWasHigher = lastNCard.value > options.min;
+ if (lastWasHigher) {
+ return chai.expect(card)
+ .to.have.property(options.property)
+ .not.equals(lastNCard[options.property]);
+ } else {
+ return chai.expect(card)
+ .to.have.property(options.property)
+ .equals(lastNCard[options.property]);
+ }
+ var matches2 = lastNCard.suit === lastNCard.suit;
+ return ((matchesColor && !matches2) || (!matchesColor && matches2));
+ }, {
+ n: 1,
+ min: 7,
+ property: 'suit',
+ }, {
+ property: {
+ description: 'The property to compare to the lastNCard',
+ possibleVals: ['suit', 'face', 'royal', 'color'],
+ type: 'String'
+ },
+ n: {
+ description: 'Number for how many cards back. Start counting at 1',
+ possibleVals: [1, 2, 3],
+ type: 'Number'
+ },
+ min: {
+ description: 'The min difference to the last nth card',
+ possibleVals: [5, 6, 7, 8, 9],
+ type: 'Number'
+ },
+ }, [
+ 'This rule does not involve the <%= nUnused %><%=nth(nUnused)%> last card',
+ 'This rule does not involve <%= propertyUnused %>',
+ 'This rule does involve value',
+ 'This rule does a minimum value',
+ 'This rule does involve <%= property %>',
+ 'This rule does involve the <%= n %><%=nth(n)%> last card',
+ ]
+ ),
+ new Rule(
+ "If the last <%= n %><%=nth(n)%> card was a <%= property %> card, play a higher value card otherwise lower.",
+ function (card, lastCards, allCards, options) {
+ var lastNCard = lastCards[lastCards.length - options.n];
+ var lastHadProperty = lastNCard[options.property];
+ if (lastHadProperty) {
+ return chai.expect(card)
+ .to.have.property('value')
+ .above(lastNCard[options.value]);
+ } else {
+ return chai.expect(card)
+ .to.have.property('value')
+ .lessThan(lastNCard[options.value]);
+ }
+ }, {
+ n: 1,
+ property: 'face',
+ }, {
+ property: {
+ description: 'The property to compare to the lastNCard',
+ possibleVals: ['face', 'royal', 'spade', 'club', 'diamond', 'heart', 'red', 'black'],
+ 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 the <%= nUnused %><%=nth(nUnused)%> last card',
+ 'This rule does not check for <%= propertyUnused %> cards',
+ 'This rule does involve <%= property %>',
+ 'This rule wants you to play a higher card in some circumstances',
+ 'This rule does involve the <%= n %><%=nth(n)%> last card',
]
)
- );
+
+ );
+
return {
Rule: Rule,
rules: rules,
diff --git a/json/elements.json b/json/elements.json
index 0d567c5..1603c53 100644
--- a/json/elements.json
+++ b/json/elements.json
@@ -1,59 +1,1063 @@
-[{"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}]
+[{
+ "key": "🂡",
+ "name": "Ace",
+ "value": 1,
+ "suit": "Spades",
+ "color": "Black",
+ "royal": false,
+ "face": false,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂢",
+ "name": "Two",
+ "value": 2,
+ "suit": "Spades",
+ "color": "Black",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂣",
+ "name": "Three",
+ "value": 3,
+ "suit": "Spades",
+ "color": "Black",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂤",
+ "name": "Four",
+ "value": 4,
+ "suit": "Spades",
+ "color": "Black",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂥",
+ "name": "Five",
+ "value": 5,
+ "suit": "Spades",
+ "color": "Black",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂦",
+ "name": "Six",
+ "value": 6,
+ "suit": "Spades",
+ "color": "Black",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂧",
+ "name": "Seven",
+ "value": 7,
+ "suit": "Spades",
+ "color": "Black",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂨",
+ "name": "Eight",
+ "value": 8,
+ "suit": "Spades",
+ "color": "Black",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂩",
+ "name": "Nine",
+ "value": 9,
+ "suit": "Spades",
+ "color": "Black",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂪",
+ "name": "Ten",
+ "value": 10,
+ "suit": "Spades",
+ "color": "Black",
+ "royal": false,
+ "face": true,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂫",
+ "name": "Jack",
+ "value": 11,
+ "suit": "Spades",
+ "color": "Black",
+ "royal": true,
+ "face": true,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂬",
+ "name": "Knight",
+ "value": 12,
+ "suit": "Spades",
+ "color": "Black",
+ "royal": true,
+ "face": true,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂭",
+ "name": "Queen",
+ "value": 13,
+ "suit": "Spades",
+ "color": "Black",
+ "royal": true,
+ "face": true,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂮",
+ "name": "King",
+ "value": 14,
+ "suit": "Spades",
+ "color": "Black",
+ "royal": true,
+ "face": true,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂱",
+ "name": "Ace",
+ "value": 1,
+ "suit": "Hearts",
+ "color": "Red",
+ "royal": false,
+ "face": false,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂲",
+ "name": "Two",
+ "value": 2,
+ "suit": "Hearts",
+ "color": "Red",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂳",
+ "name": "Three",
+ "value": 3,
+ "suit": "Hearts",
+ "color": "Red",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂴",
+ "name": "Four",
+ "value": 4,
+ "suit": "Hearts",
+ "color": "Red",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂵",
+ "name": "Five",
+ "value": 5,
+ "suit": "Hearts",
+ "color": "Red",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂶",
+ "name": "Six",
+ "value": 6,
+ "suit": "Hearts",
+ "color": "Red",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂷",
+ "name": "Seven",
+ "value": 7,
+ "suit": "Hearts",
+ "color": "Red",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂸",
+ "name": "Eight",
+ "value": 8,
+ "suit": "Hearts",
+ "color": "Red",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂹",
+ "name": "Nine",
+ "value": 9,
+ "suit": "Hearts",
+ "color": "Red",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂺",
+ "name": "Ten",
+ "value": 10,
+ "suit": "Hearts",
+ "color": "Red",
+ "royal": false,
+ "face": true,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂻",
+ "name": "Jack",
+ "value": 11,
+ "suit": "Hearts",
+ "color": "Red",
+ "royal": true,
+ "face": true,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂼",
+ "name": "Knight",
+ "value": 12,
+ "suit": "Hearts",
+ "color": "Red",
+ "royal": true,
+ "face": true,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂽",
+ "name": "Queen",
+ "value": 13,
+ "suit": "Hearts",
+ "color": "Red",
+ "royal": true,
+ "face": true,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂾",
+ "name": "King",
+ "value": 14,
+ "suit": "Hearts",
+ "color": "Red",
+ "royal": true,
+ "face": true,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃁",
+ "name": "Ace",
+ "value": 1,
+ "suit": "Diamonds",
+ "color": "Red",
+ "royal": false,
+ "face": false,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃂",
+ "name": "Two",
+ "value": 2,
+ "suit": "Diamonds",
+ "color": "Red",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃃",
+ "name": "Three",
+ "value": 3,
+ "suit": "Diamonds",
+ "color": "Red",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃄",
+ "name": "Four",
+ "value": 4,
+ "suit": "Diamonds",
+ "color": "Red",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃅",
+ "name": "Five",
+ "value": 5,
+ "suit": "Diamonds",
+ "color": "Red",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃆",
+ "name": "Six",
+ "value": 6,
+ "suit": "Diamonds",
+ "color": "Red",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃇",
+ "name": "Seven",
+ "value": 7,
+ "suit": "Diamonds",
+ "color": "Red",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃈",
+ "name": "Eight",
+ "value": 8,
+ "suit": "Diamonds",
+ "color": "Red",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃉",
+ "name": "Nine",
+ "value": 9,
+ "suit": "Diamonds",
+ "color": "Red",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃊",
+ "name": "Ten",
+ "value": 10,
+ "suit": "Diamonds",
+ "color": "Red",
+ "royal": false,
+ "face": true,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃋",
+ "name": "Jack",
+ "value": 11,
+ "suit": "Diamonds",
+ "color": "Red",
+ "royal": true,
+ "face": true,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃌",
+ "name": "Knight",
+ "value": 12,
+ "suit": "Diamonds",
+ "color": "Red",
+ "royal": true,
+ "face": true,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃍",
+ "name": "Queen",
+ "value": 13,
+ "suit": "Diamonds",
+ "color": "Red",
+ "royal": true,
+ "face": true,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃎",
+ "name": "King",
+ "value": 14,
+ "suit": "Diamonds",
+ "color": "Red",
+ "royal": true,
+ "face": true,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃑",
+ "name": "Ace",
+ "value": 1,
+ "suit": "Clubs",
+ "color": "Black",
+ "royal": false,
+ "face": false,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃒",
+ "name": "Two",
+ "value": 2,
+ "suit": "Clubs",
+ "color": "Black",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃓",
+ "name": "Three",
+ "value": 3,
+ "suit": "Clubs",
+ "color": "Black",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃔",
+ "name": "Four",
+ "value": 4,
+ "suit": "Clubs",
+ "color": "Black",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃕",
+ "name": "Five",
+ "value": 5,
+ "suit": "Clubs",
+ "color": "Black",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃖",
+ "name": "Six",
+ "value": 6,
+ "suit": "Clubs",
+ "color": "Black",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃗",
+ "name": "Seven",
+ "value": 7,
+ "suit": "Clubs",
+ "color": "Black",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃘",
+ "name": "Eight",
+ "value": 8,
+ "suit": "Clubs",
+ "color": "Black",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃙",
+ "name": "Nine",
+ "value": 9,
+ "suit": "Clubs",
+ "color": "Black",
+ "royal": false,
+ "face": false,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃚",
+ "name": "Ten",
+ "value": 10,
+ "suit": "Clubs",
+ "color": "Black",
+ "royal": false,
+ "face": true,
+ "number": true,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃛",
+ "name": "Jack",
+ "value": 11,
+ "suit": "Clubs",
+ "color": "Black",
+ "royal": true,
+ "face": true,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃜",
+ "name": "Knight",
+ "value": 12,
+ "suit": "Clubs",
+ "color": "Black",
+ "royal": true,
+ "face": true,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃝",
+ "name": "Queen",
+ "value": 13,
+ "suit": "Clubs",
+ "color": "Black",
+ "royal": true,
+ "face": true,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": true,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃞",
+ "name": "King",
+ "value": 14,
+ "suit": "Clubs",
+ "color": "Black",
+ "royal": true,
+ "face": true,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🂠",
+ "name": "Playing Card",
+ "value": 15,
+ "suit": "Black",
+ "color": "Black",
+ "royal": false,
+ "face": false,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": false,
+ "odd": true,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃏",
+ "name": "Joker",
+ "value": 16,
+ "suit": "Black",
+ "color": "Black",
+ "royal": false,
+ "face": true,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}, {
+ "key": "🃟",
+ "name": "Joker",
+ "value": 16,
+ "suit": "Red",
+ "color": "Red",
+ "royal": false,
+ "face": true,
+ "number": false,
+ "red": false,
+ "black": false,
+ "even": true,
+ "odd": false,
+ "loop": false,
+ "heart": false,
+ "spade": false,
+ "club": false,
+ "diamond": false
+}]
diff --git a/test/unit/directivesSpec.js b/test/unit/directivesSpec.js
index 2e5469a..44b8bc0 100644
--- a/test/unit/directivesSpec.js
+++ b/test/unit/directivesSpec.js
@@ -2,6 +2,37 @@
/* jasmine specs for directives go here */
-describe('directives', function() {
+describe('directives', function () {
+ var $compile,
+ $rootScope;
+ // Load the myApp module, which contains the directive
+ beforeEach(module('scienceAlchemy'));
+ // beforeEach(module('Rules'));
+
+ // Store references to $rootScope and $compile
+ // so they are available to all tests in this describe block
+ beforeEach(inject(function (_$compile_, _$rootScope_) {
+ // The injector unwraps the underscores (_) from around the parameter names when matching
+ $compile = _$compile_;
+ $rootScope = _$rootScope_;
+ }));
+
+ it('Replaces the element with the appropriate content', function () {
+ // define a rule for testing
+ $rootScope.rule = Rules.rules[0];
+
+ // Compile a piece of HTML containing the directive
+ var element = $compile('
')($rootScope);
+
+ // fire all the watches, so the scope expressions will be evaluated
+ // $rootScope.$digest();
+ $rootScope.$apply();
+
+ // Check that the compiled element contains the templated content
+ var html = element.html();
+ expect(html).toContain(" ')($rootScope);
+
+ // fire all the watches, so the scope expressions will be evaluated
+ // $rootScope.$digest();
+ $rootScope.$apply();
+
+ // Check that the compiled element contains the templated content
+ var html = element.html();
+ expect(html).toContain("