mirror of
https://github.com/wassname/cardsforscience.git
synced 2026-09-11 12:00:40 +08:00
Added rules and tests for them
This commit is contained in:
+175
-80
@@ -76,103 +76,198 @@ var Game = (function (Helpers, GameObjects, ObjectStorage) {
|
||||
// })
|
||||
// ).then(function () {
|
||||
|
||||
// Turn JSON files into actual game objects and fill map of all objects
|
||||
var makeGameObject = function (type, object) {
|
||||
// It's okay to define this function here since load is only called
|
||||
// once anyway...
|
||||
var o = new type(object);
|
||||
self.allObjects[o.key] = o;
|
||||
return o;
|
||||
};
|
||||
self.elements = self.elements.slice(0, 20).map(
|
||||
function (r) {
|
||||
return makeGameObject(GameObjects.ElementStore, r);
|
||||
});
|
||||
self.workers = self.workers.map(
|
||||
function (w) {
|
||||
return makeGameObject(GameObjects.Worker, w);
|
||||
});
|
||||
self.upgrades = self.upgrades.map(
|
||||
function (u) {
|
||||
return makeGameObject(GameObjects.Upgrade, u);
|
||||
});
|
||||
self.achievements = self.achievements.map(
|
||||
function (a) {
|
||||
return makeGameObject(GameObjects.Achievement, a);
|
||||
});
|
||||
// Load states from local store
|
||||
for (var key in self.allObjects) {
|
||||
var o = self.allObjects[key];
|
||||
o.loadState(ObjectStorage.load(key));
|
||||
}
|
||||
// Turn JSON files into actual game objects and fill map of all objects
|
||||
var makeGameObject = function (type, object) {
|
||||
// It's okay to define this function here since load is only called
|
||||
// once anyway...
|
||||
var o = new type(object);
|
||||
self.allObjects[o.key] = o;
|
||||
return o;
|
||||
};
|
||||
self.elements = self.elements.map(
|
||||
function (r) {
|
||||
return makeGameObject(GameObjects.Card, r);
|
||||
});
|
||||
self.workers = self.workers.map(
|
||||
function (w) {
|
||||
return makeGameObject(GameObjects.Worker, w);
|
||||
});
|
||||
self.upgrades = self.upgrades.map(
|
||||
function (u) {
|
||||
return makeGameObject(GameObjects.Upgrade, u);
|
||||
});
|
||||
self.achievements = self.achievements.map(
|
||||
function (a) {
|
||||
return makeGameObject(GameObjects.Achievement, a);
|
||||
});
|
||||
// Load states from local store
|
||||
for (var key in self.allObjects) {
|
||||
var o = self.allObjects[key];
|
||||
o.loadState(ObjectStorage.load(key));
|
||||
}
|
||||
|
||||
// put elements in extended array with utility methods
|
||||
self.elementStore = new GameObjects.ElementStores();
|
||||
self.elementStore.push.apply(self.elementStore, self.elements);
|
||||
self.elements = self.elementStore;
|
||||
// put elements in extended array with utility methods
|
||||
self.Card = new GameObjects.Cards();
|
||||
self.Card.push.apply(self.Card, self.elements);
|
||||
self.elements = self.Card;
|
||||
// var totalElements = _(self.elements).map('state.amount').sum();
|
||||
// if (totalElements<1) self.initialElements();
|
||||
|
||||
self.rules = self.generateRules();
|
||||
|
||||
self.loaded = true;
|
||||
return self;
|
||||
self.rules = self.generateRules();
|
||||
|
||||
self.loaded = true;
|
||||
return self;
|
||||
// });
|
||||
};
|
||||
|
||||
Game.prototype.initialElements = function () {
|
||||
// if we are making new rules we will also reset element stores
|
||||
this.elements.map(function (element) {
|
||||
element.state.amount = 0;
|
||||
element.state.discovered = false;
|
||||
element.state.interesting = false;
|
||||
});
|
||||
// but give us a random 4 number cards of one suite
|
||||
var startSuit = _.sample(["Spades", "Hearts", "Diamonds", "Clubs"]);
|
||||
|
||||
this.elements.map(function (element) {
|
||||
if (element.number && element.suit === startSuit) {
|
||||
element.state.amount = 5;
|
||||
element.state.discovered = true;
|
||||
}
|
||||
});
|
||||
console.log('Set initial cards');
|
||||
return startSuit;
|
||||
}
|
||||
|
||||
/** Generate rules between runes **/
|
||||
Game.prototype.generateRules = function () {
|
||||
var rules = ObjectStorage['rules'];
|
||||
if (!rules) {
|
||||
var elements = this.elements;
|
||||
// generate rules and store them with a hash of inredients
|
||||
// the rule will be an object with reactants, catalysts, conditions, results
|
||||
// todo make a strcture that's more like a tree with progression etc
|
||||
// todo add duds, misleading ones, explosions wildcards
|
||||
// todo make this theory based?
|
||||
// todo simulation
|
||||
var rules = {};
|
||||
for (var k = 0; k < this.elements.length * 20; k++) {
|
||||
// make a rules
|
||||
var rule = {
|
||||
reactants: [],
|
||||
catalysts: [],
|
||||
conditions: [],
|
||||
results: [],
|
||||
inputs: []
|
||||
}
|
||||
var numOfIngredients = 2 + Math.round(Math.random() * 2);
|
||||
for (var i = 0; i < numOfIngredients; i++) {
|
||||
var j = Math.round(Math.random() * (elements.length - 1));
|
||||
rule.reactants.push(elements[j].key);
|
||||
}
|
||||
|
||||
if (Math.random() < 0.1) {
|
||||
var j = Math.round(Math.random() * (elements.length - 1));
|
||||
rule.catalysts.push(elements[j].key);
|
||||
/**
|
||||
* Make the values sequential for given card names
|
||||
* @param {Array} names - String names e.g. ['King','Queen']
|
||||
* @param {Object} rules - Rules
|
||||
* @return {Object} - modified Rules
|
||||
*/
|
||||
function orderValues(names, rules, reverse) {
|
||||
var namedCards = _.filter(elements, function (c) {
|
||||
return names.indexOf(c.name) > -1;
|
||||
});
|
||||
var uNamedCardVals = _.uniq(_.map(namedCards, 'value'));
|
||||
var maxVal = _.max(uNamedCardVals);
|
||||
var initialValue = rules.value[uNamedCardVals[0]];
|
||||
for (var i = 0; i < uNamedCardVals.length; i++) {
|
||||
var v = uNamedCardVals[i];
|
||||
if (reverse)
|
||||
rules.value[v] = initialValue + maxVal - v;
|
||||
else
|
||||
rules.value[v] = initialValue + v;
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
var rules = ObjectStorage.load('rules');
|
||||
if (!rules) {
|
||||
|
||||
var startSuit = this.initialElements();
|
||||
|
||||
var elements = this.elements;
|
||||
var attrs = ["key", "name", "value", "suit", "color", "royal", "face", "number"];
|
||||
var rules = {};
|
||||
|
||||
// first lets apply random values to each attribute
|
||||
for (var i = 0; i < attrs.length; i++) {
|
||||
var attr = attrs[i];
|
||||
rules[attr] = {};
|
||||
var uniqVals = _.uniq(_.map(elements, attr));
|
||||
for (var j = 0; j < uniqVals.length; j++) {
|
||||
var v = uniqVals[j];
|
||||
// E.g. rules.suit.black=4, rules.name.Queen=10 etc
|
||||
rules[attr][v] = Math.round(Math.random() * 104);
|
||||
}
|
||||
var numOfresults = Math.round(Math.random() * 3);
|
||||
for (var i = 0; i < numOfresults; i++) {
|
||||
var j = Math.round(Math.random() * (elements.length - 1));
|
||||
rule.results.push(elements[j].key);
|
||||
}
|
||||
rule.inputs = [].concat(rule.reactants, rule.catalysts)
|
||||
rule.reactants.sort()
|
||||
rule.results.sort()
|
||||
rule.catalysts.sort()
|
||||
rule.inputs.sort();
|
||||
// index byhash of sorted array of reactants
|
||||
rules[rule.inputs] = rule
|
||||
}
|
||||
|
||||
// now lets overide some attrbutes with a bit more order
|
||||
|
||||
// number cards should be in sequence as should face cards
|
||||
// _.uniq(_.map(_.filter(cards,{face:'true'}),'value'))
|
||||
var royals = ["Jack", "Knight", "Queen", "King"];
|
||||
var numbers = ["Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"];
|
||||
// lets randomly add the ace to the top or bottom
|
||||
if (Math.random() > 0.5) {
|
||||
royals.push("Ace");
|
||||
} else {
|
||||
numbers.push("Ace");
|
||||
}
|
||||
orderValues(royals, rules);
|
||||
orderValues(numbers, rules);
|
||||
|
||||
// and make the startingSuit 0 for a simpler set of initial rules
|
||||
rules.suit[startSuit] = 0;
|
||||
|
||||
// and finally get the joker a change for a negative
|
||||
rules.value[16] = Math.random(Math.random() * 20 - 10);
|
||||
|
||||
|
||||
|
||||
console.log('Reset and made new rules');
|
||||
|
||||
}
|
||||
ObjectStorage['rules'] = rules;
|
||||
ObjectStorage.save('rules', rules);
|
||||
return rules;
|
||||
},
|
||||
Game.prototype.save = function () {
|
||||
// Save every object's state to local storage
|
||||
for (var key in this.allObjects) {
|
||||
ObjectStorage.save(key, this.allObjects[key].state);
|
||||
/**
|
||||
* Test the rules
|
||||
* @param {array} inputKeys - e.g ["🂤", "🂤"]
|
||||
* @return {Object} rule with {inputs,reactants,results}
|
||||
*/
|
||||
Game.prototype.testRules = function (inputKeys) {
|
||||
var self = this;
|
||||
var attrs = ["value", "suit"]; // attrs we use, possible expand later
|
||||
|
||||
|
||||
// work out total for this combo
|
||||
var total = 0;
|
||||
for (var i = 0; i < inputKeys.length; i++) {
|
||||
var key = inputKeys[i];
|
||||
var element = _.find(self.elements, {
|
||||
key: key
|
||||
});
|
||||
for (var j = 0; j < attrs.length; j++) {
|
||||
var attr = attrs[j];
|
||||
// add appropriate value for this card's attribute
|
||||
// e.g. total+=rules.suit["spade]
|
||||
total += self.rules[attr][element[attr]];
|
||||
}
|
||||
}
|
||||
|
||||
// you keep you results and thus get more cards unless the total is
|
||||
// <5
|
||||
var maxValue = 14; //=_(self.elements).map('value').map(function(v){return parseInt(v);}).max()
|
||||
var divisor = Math.round(maxValue * 3); // ~66% chance of dud if they don't understand rules
|
||||
var value = total % maxValue;
|
||||
var resultElem = _.find(self.elements, {
|
||||
value: value
|
||||
});
|
||||
var reactants = resultElem ? inputKeys : [];
|
||||
var results = resultElem ? [resultElem.key] : [];
|
||||
// TODO add penalty for duds? like more cards
|
||||
|
||||
return {
|
||||
results: results,
|
||||
inputs: inputKeys,
|
||||
conditions: [],
|
||||
catalysts: [],
|
||||
reactants: reactants
|
||||
};
|
||||
};
|
||||
Game.prototype.save = function () {
|
||||
// Save every object's state to local storage
|
||||
for (var key in this.allObjects) {
|
||||
ObjectStorage.save(key, this.allObjects[key].state);
|
||||
}
|
||||
};
|
||||
|
||||
return Game;
|
||||
}(Helpers, GameObjects, ObjectStorage));
|
||||
|
||||
Reference in New Issue
Block a user