Made it work on mobiles - kindof

This commit is contained in:
2016-03-01 12:41:20 +08:00
parent f91fd433da
commit 3fd49faec0
9 changed files with 140 additions and 47 deletions
+66 -4
View File
@@ -1,7 +1,69 @@
# Particle Clicker
# Cards for science
An addictive incremental game that teaches players the history of high energy particle physics.
Cards For Science is a card game where you work out the secret rule to determine which cards can be played. This game is based on Eleusis by Robert Abbott and John Golden's Eleusis Express.
Developed during the 2014 CERN Webfest over a weekend.
<img src="./docs/screenshots.png"></img>
Visit [http://cern.ch/particle-clicker](http://cern.ch/particle-clicker) to play the game.
## Install
`npm i`
## Serving
`npm start`
## Deploy
To run a producton bundle with webpack:
- `npm run dist`
Then to send to amazon s3 bucket:
- `gulp s3`
Note this depends on your amazon credentials and bucket being setup up in untracked file ./secrets/aws-credentials.json.
For more refer to the [docs](https://www.npmjs.com/package/gulp-awspublish).
I've been hosting it on an amazon bucket at cardsforscience.com.
## Testing
`npm test`
## Adding rules
Add rules to rules.js as a new rule object. Read the jsdoc comment for the rule object for params.
## Simulating
After adding a rule go to /src/js/rules/simulate.html and click "export table as JSON". Make this the contents of simulations.json. This tells the game which rule options are balanced.
## Developing
- `index.webpack` Html is from
- app.js is the main angular app
- game.js is the main game app, provided as a servie from angular 1
- cards.json are the cards and thier properties
- simulations - give balalance to the rules
- rules.js has the rules and thier classes
- ui.js is mostly left over
- helpers.js is mostly left over
- analytics is outdates and can be replaces with angulartics
## TODO
- [ ] acheivements
- [ ] analystics (I want to know how long they spend on each rule, and how many guesses)
- [ ] more rules, we have ~9 rules with ~300 variations
- [ ] every black card must be follower by a card with a face
- [ ] "Alternate between cards which have closed loops in their number or letter designations (e.g. 4, Q), and cards which don't (e.g. 2, K)".
- [ ] Play a sequence of suits from clubs to spades and back repeating the suit with clubs and spades, thusly, C, D, H, S, S, H, D, C, C, etc.
- [ ] Play a progressive pattern of alternating red and black cards, such that first one black and one red card alternate, then two black and 2 red, then 3 black and 3 red, then repeat the pattern.
- [ ] Cards are played consecutively upward or downward by 1, except skipping all the prime numbers (3,5,7,11,13). When 1 or 12 is reached the pattern reverses with the next card up or down. This Universe may start on any card except a prime number.
- [ ] The sum of the card played plus the last card played must total a number that can be divided by 3 evenly. Thus totals of 3, 6, 9, 12, 15, 18, 21, & 24 are allowed. (For example, if the first card turned is an 8, correct cards are 1, 4, 7, 10, 13). The starting card may be anything but a 3, 6, 9, or 12, and that means these 4 values will never be played.
- [ ] Each card played must be lower in value than the previous card, unless the card is 3 or less (3, 2, or 1), then the next card is that card's value plus 10 (3+10=13, 2+10=12, 1+10=11).
- [ ] prompts
- [ ] when all cards are gone
- [ ] when starting
- [ ] when all hints are gone
-5
View File
@@ -6,11 +6,6 @@ var gutil = require('gulp-util')
var webpack = require('webpack-stream');
// var source = require('vinyl-source-stream');
// var buffer = require('vinyl-buffer');
// var del = require('del');
// var globby = require('globby');
var concurrent = require("concurrent-transform");
var rename = require('gulp-rename');
var awspublish = require('gulp-awspublish');
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "CardsForScience",
"version": "0.0.6",
"version": "0.0.7",
"description": "Cards For Science",
"keywords": [
"cards",
+13 -11
View File
@@ -9,6 +9,8 @@
<meta property="og:type" content="game">
<meta property="og:description" content="A card game where you work out the secret rule to determine which cards can be played next.">
<meta property="og:image" content="assets/favicon.png">
<meta name="msvalidate.01" content="36C4A686262A56C0F7978C7A90F26B1A" />
<meta name="google-site-verification" content="SF3w4G37_C-mMW_XxVVRNhe1BdkyTjQwQfo9D_G0VbE" />
<link rel="apple-touch-icon" sizes="57x57" href="assets/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="assets/apple-icon-60x60.png">
@@ -67,7 +69,7 @@
<div id="main-content" class="container-fluid Paired">
<div class="row">
<div class="col-md-3 col-md-3s col-lg-2 col-no-padding visible-md-block visible-lg-block">
<div class="col-md-3 col-lg-2 col-sm-4 col-no-padding">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
@@ -81,7 +83,7 @@
<div id="handContent">
<div class="row" ng-cloak>
<div class="col-xs-2 col-no-padding " ng-repeat="r in rc.cards|orderBy:'key'" ng-show="rc.isAvailable(r)">
<div class="col-md-2 col-sm-3 col-no-padding " ng-repeat="r in rc.cards|orderBy:'key'" ng-show="rc.isAvailable(r)">
<span ng-show="rc.isAvailable(r)"
id="{{r.key}}"
class="{{r.key}} card cards-store {{ r.state.interesting ? 'blink' : '' }} {{r.color}} {{rc.isAvailable(r) ? ' ui-draggable': 'empty'}}"
@@ -103,10 +105,10 @@
</div>
</div>
<div id="column-lab" class="col-xs-6 col-md-6 col-md-6s col-lg-7 col-no-padding-xs" ng-controller="StatsController as lc">
<div id="column-lab" class="col-md-6 col-sm-8 col-lg-7 col-no-padding-xs" ng-controller="StatsController as lc">
<div class="row status" ng-cloak>
<div class="col-xs-12 text-center col-no-padding-xs">
<div class="col-sm-12 text-center col-no-padding-xs">
<div class="{{lc.lab.state.score<0?'bg-danger':''}} animate-increase animate-decrease" ><strong>Score</strong><br>{{ lc.lab.state.score | niceNumber }}</div>
<div class="update-value " ng-model="lc.lab.state.score" cfs-score-change id="update-data"></div>
@@ -129,7 +131,7 @@
>
<div class="main-line card-line" id="lastCards">
<div class="row" >
<div class="col-xs-1 col-no-padding add-from-top" ng-repeat="r in dc.lastCards | limitTo: -10" ng-cloak>
<div class="col-md-1 col-sm-1 col-no-padding add-from-top" ng-repeat="r in dc.lastCards | limitTo: -10" ng-cloak>
<span
class="{{r.key}} card {{r.color}}"
data-cards="{{r.key}}"
@@ -143,7 +145,7 @@
<div class=""><strong>Incorrect cards:</strong><br></div>
<div class="side-line card-line short-lines-nup" id="incorrectCards">
<div class="row">
<div class="col-md-1 col-no-padding" ng-repeat="rr in dc.incorrectCards | limitTo: -10" ng-cloak>
<div class="col-md-1 col-sm-1 col-no-padding" ng-repeat="rr in dc.incorrectCards | limitTo: -10" ng-cloak>
<div class="row">
<div ng-repeat="r in rr| limitTo: -7" class="col-md-12 col-no-padding add-from-right ">
<span
@@ -192,8 +194,8 @@
</div>
<div class="col-md-3 col-md-3s col-lg-2 col-no-padding visible-md-block visible-lg-block">
<div class="panel panel-default hidden-xs hidden-sm">
<div class="col-md-3 col-lg-2 col-sm-6 col-no-padding">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<i class="fa fa-wrench"></i> Winning: guess which rule
@@ -217,7 +219,7 @@
</div>
</div>
<div id="column-tabs" class="col-xs-6 visible-xs-block visible-sm-block col-no-padding">
<!-- <div id="column-tabs" class="col-xs-6 visible-xs-block visible-sm-block col-no-padding">
<ul id="TabList" class="nav nav-tabs" role="tablist">
<li class="active"><a href="#cards" role="tab" data-toggle="tab"><i class="fa fa-cogs"></i> Elements </a></li>
<li><a href="#hr" role="tab" data-toggle="tab"><i class="fa fa-users"></i> HR</a></li>
@@ -234,7 +236,7 @@
</div>
</div>
</div>
</div> -->
</div>
</div>
@@ -308,7 +310,7 @@
</div>
<div class="modal-body">
<h4>About</h4>
<p class="small">Version: 0.6</p>
<p class="small">Version: 0.7</p>
<p class="small bg-warning">This is a pre-release. <p>Cards For Science is a card game where you work out the secret rule to determine which cards can be played. This game is based on <a href="http://www.logicmazes.com/games/eleusis/">Eleusis</a> by Robert Abbott and John Golden's <a href="http://www.logicmazes.com/games/eleusis/express.html">Eleusis</a> Express.
+2 -2
View File
@@ -432,7 +432,7 @@ var app = (function (Helpers,analytics,Game,Rules) {
alertify.confirm(
'Do you really want to restart the game? All progress will be lost.',
function(event){
alertify.alert('Restarting. <p> P.S. The rule was: <p>"'+game.rule.describe(),function(){
alertify.alert('Restarting. <p> The rule was: <p>"'+game.rule.describe(),function(){
event.preventDefault();
// ObjectStorage.clear();
// $window.location.reload(true); /// reloads are better for ads?
@@ -459,7 +459,7 @@ var app = (function (Helpers,analytics,Game,Rules) {
if (newValue<0&&!vm.lost){
vm.lost=true;
alertify.alert(
'<p>You lost :( <p> Play again? <p><p>P.S. The rule was: <p>"'+game.rule.describe()+'"',
'<p>You lost :( Play again? <p><p> The rule was: <p>"'+game.rule.describe()+'"',
function(event){
event.preventDefault();
// ObjectStorage.clear();
+1 -1
View File
@@ -149,7 +149,7 @@ var Game = module.exports =(function (Helpers, GameObjects, ObjectStorage,Rules,
var hypo=[];
// a random 2, 2 variations of each
for (var i = 0; i < 3; i++) {
for (var i = 0; i < 1; i++) {
var rule = _.sample(this.rules);
rule = angular.copy(rule);
rule.randomize();
+41 -14
View File
@@ -21,13 +21,34 @@ var Rules = module.exports = (function functionName(_,chai) {
this.rules=rules;
};
Simulation.prototype.run = function () {
var allPromises = [];
var allres = [];
for (var i = 0; i < this.rules.length; i++) {
var rule = this.rules[i];
var promises = rule.simulate();
allPromises.push(promises);
var res = rule.simulate(this.cards);
allres.push.apply(allres,res);
}
return Promise.all(allPromises).then(function(data){return _.concat(data);});
this.results=allres;
return allres;
};
Simulation.prototype.summarize = function () {
var summarize={};
var props = _.keys(this.results[0]);
for (var i = 0; i < props.length; i++) {
var property=props[i];
var vals = _.map(results,property);
summarize[property]={
min: _.min(vals),
max: _.max(vals),
n: vals.length,
count: _.filter(vals,Boolean).length,
hist: _.countBy(vals),
mean: _.mean(vals),
nTruthy: _.filter(vals,Boolean).length,
nFalsey: _.filter(vals,function(v){return !Boolean(v);}).length,
};
}
return summarize;
};
@@ -328,9 +349,14 @@ var Rules = module.exports = (function functionName(_,chai) {
var rights=[];
var wrongs=[];
var errors=[];
var lastCards = _.sampleSize(cards,3);
self.setOptions(options);
// simulate once
for (var i = 0; i < n; i++) {
// random last cards each time
var lastCards = _.sampleSize(cards,3);
var res=undefined;
var error=undefined;
var card = _.sample(cards);
@@ -338,7 +364,7 @@ var Rules = module.exports = (function functionName(_,chai) {
try{
var res = self.testAndTell(card,lastCards,cards);
} catch(e){
console.error('simulateOne',err);
console.error('simulateOne',e);
error=e;
}
@@ -356,23 +382,24 @@ var Rules = module.exports = (function functionName(_,chai) {
}
}
}
var ratioRight = rights.length/(rights.length+wrongs.length);
if (isNaN(ratioRight)) ratioRight = 0;
var ok = ratioRight>0.1&&ratioRight<0.66;
return {
wrongs:wrongs,
wrongs:_.uniq(wrongs),
wrong:wrongs.length,
right:rights.length,
rights:rights,
rights:_.uniq(rights),
error:errors.length,
errors:errors,
errors:_.uniq(errors),
key:self.key,
description:self.describe(),
options:self.options,
n:n,
time:new Date()-t0,
ok:ok,
ratioRight:_.round(ratioRight,4),
ratioRight:_.round(ratioRight,2),
};
};
@@ -589,7 +616,7 @@ var Rules = module.exports = (function functionName(_,chai) {
new Rule(
"793d93cb-ca09-4cda-8781-6fce02edf09c",
"If the <%= lastn(n) %> card's number is higher than <%= min %>, change <%= property %>, and if lower, keep it the same.",
"If the <%= lastn(n) %> card's number is higher than <%= min %>, change <%= property %> from it, 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;
@@ -635,16 +662,16 @@ var Rules = module.exports = (function functionName(_,chai) {
),
new Rule(
"f4fba793-f886-4db8-9853-240002bb112e",
"If the <%= lastn(n) %> card was a <%= property %> card, play a higher value card otherwise lower. But any card is OK if the <%= lastn(n) %> card was an Ace, King to Joker.",
"If the <%= lastn(n) %> card was a <%= property %> card, play a higher value card otherwise lower. But any card is OK if the <%= lastn(n) %> card was an Ace,2, or King to Joker.",
function (card, lastCards, allCards, options) {
var lastNCard = lastCards[lastCards.length - options.n];
var value = lastNCard.value;
var lastHadProperty = lastNCard[options.property];
// reverse on card of these values
var reverseOn=[1,14,15,16];
var reverseOn=[1,2,14,15,16];
if (reverseOn.indexOf(value)>-1) return true;
if (lastHadProperty) {
return chai.expect(card)
.to.have.property('value')
+15 -8
View File
@@ -13,6 +13,7 @@
<body>
<h1>Simulate rules</h1>
<textarea rows="10" style="width: 1000px; height: 400px" id="summary"></textarea>
<textarea rows="3" style="width: 1000px; height: 100px" id="oks"></textarea>
<div id="export"></div>
<table id="results" class="table">
@@ -25,12 +26,18 @@
<script src="../../../clientApp.bundle.js"></script>
<script>
var results = [];
for (var i = 0; i < clientApp.Rules.rules.length; i++) {
var rule = clientApp.Rules.rules[i];
var res = rule.simulate(clientApp.cards);
results.push.apply(results,res);
}
var simulation = new clientApp.Rules.Simulation(clientApp.Rules.rules,clientApp.cards);
var results=simulation.run();
var summary = simulation.summarize()
// var results = [];
// for (var i = 0; i < clientApp.Rules.rules.length; i++) {
// var rule = clientApp.Rules.rules[i];
// var res = rule.simulate(clientApp.cards);
// results.push.apply(results,res);
// }
$('#oks').text('ok: '+_.map(results,'ok').reduce(_.add)+'/'+results.length);
var data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(results));
$('<a class="btn btn-default" href="data:' + data + '" download="data.json">export table as JSON</a>').appendTo('#export');
@@ -56,8 +63,8 @@
table.append(ts);
$('#results').dataTable();
// var summaryJson = JSON.stringify(simulation.summarize(),null,4);
// $('#summary').text(summaryJson);
var summaryJson = JSON.stringify(summary,null,4);
$('#summary').text(summaryJson);
</script>
File diff suppressed because one or more lines are too long