diff --git a/README.md b/README.md index 8985876..fbb8373 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,27 @@ For more advanced usage, scopes can be nested. var result = dice.roll("[takes.priority] + [nested.value]", scope); result == 10; // because we look for an exact match of property name first +Statistics +========== + +If you want some analysis for your rolls, you can get a result set created with +some basic stats tagged in. + +Using `dice.statistics(rollString, scope, samples)` returns an object: + +```javascript + { + 'results': [dice_roll_result], // The result set generated + 'mean': number, // The average of result set generated + 'min': number, // The smallest value in the result set + 'max': number, // The largest value in the result set + 'min_possible': number, // The smallest value that could have + // been generated. + 'max_possible': number, // The largest value that could have + // been generated. + } +``` + Contributing ============ diff --git a/build/dice.js b/build/dice.js index 797cd8d..4031ae5 100644 --- a/build/dice.js +++ b/build/dice.js @@ -49,6 +49,7 @@ module.exports={ var dice = { parse: require('./parser').parse, eval: require('./evaluate').eval, + ops: require('./evaluate').ops, version: require('../package').version }; @@ -75,14 +76,93 @@ dice.statistics = function(str, scope, samples){ var mean = resultSet.reduce(function(n, acc){ return n + acc; }, 0) / samples; var min = resultSet.reduce(function(n, acc){ return n < acc ? n : acc; }, resultSet[0]); var max = resultSet.reduce(function(n, acc){ return n > acc ? n : acc; }, resultSet[0]); + + var parsed = dice.parse(str); + + var minMaxPossible = determine_min_max_possible(parsed, scope); + return { 'results': resultSet, 'mean': mean, 'min': parseInt(min.toFixed()), - 'max': parseInt(max.toFixed()) + 'max': parseInt(max.toFixed()), + 'min_possible': minMaxPossible[0], + 'max_possible': minMaxPossible[1] }; }; +function determine_min_max_possible(opObject, scope){ + if(opObject.op == 'static'){ + return [opObject.value, opObject.value]; + } + if(opObject.op == 'lookup'){ + var lookup = dice.ops.lookup.call(opObject, scope); + return [lookup(scope), lookup(scope)]; + } + if(opObject.op == 'floor'){ + var minmax = determine_min_max_possible(opObject.args[0], scope); + return [Math.floor(minmax[0]), Math.floor(minmax[1])]; + } + if(opObject.op == 'ceil'){ + var minmax = determine_min_max_possible(opObject.args[0], scope); + return [Math.ceil(minmax[0]), Math.ceil(minmax[1])]; + } + if(opObject.op == 'round'){ + var minmax = determine_min_max_possible(opObject.args[0], scope); + return [Math.round(minmax[0]), Math.round(minmax[1])]; + } + if(opObject.op == 'd'){ + var multipleMinMax = determine_min_max_possible(opObject.args[0], scope); + var randPartMinMax = determine_min_max_possible(opObject.args[1], scope); + var min = randPartMinMax[0] * multipleMinMax[0]; + var max = randPartMinMax[1] * multipleMinMax[1]; + return [min, max]; + } + if(opObject.op == 'w'){ + var multipleMinMax = determine_min_max_possible(opObject.args[0], scope); + var randPartMinMax = determine_min_max_possible(opObject.args[1], scope); + var min = randPartMinMax[0] * multipleMinMax[0]; + var max = randPartMinMax[1] * multipleMinMax[1]; + return [min, max]; + } + if(opObject.op == 'random'){ + var minMinMax = determine_min_max_possible(opObject.args[0], scope); + var maxMinMax = determine_min_max_possible(opObject.args[1], scope); + return [minMinMax[0], maxMinMax[1]]; + } + if(opObject.op == '+'){ + var leftMinMax = determine_min_max_possible(opObject.args[0], scope); + var rightMinMax = determine_min_max_possible(opObject.args[1], scope); + var min = leftMinMax[0] + rightMinMax[0]; + var max = leftMinMax[1] + rightMinMax[1]; + return [min, max]; + } + if(opObject.op == '-'){ + var leftMinMax = determine_min_max_possible(opObject.args[0], scope); + var rightMinMax = determine_min_max_possible(opObject.args[1], scope); + var min = leftMinMax[0] - rightMinMax[0]; + var max = leftMinMax[1] - rightMinMax[1]; + return [min, max]; + } + if(opObject.op == '*'){ + var leftMinMax = determine_min_max_possible(opObject.args[0], scope); + var rightMinMax = determine_min_max_possible(opObject.args[1], scope); + var min = leftMinMax[0] * rightMinMax[0]; + var max = leftMinMax[1] * rightMinMax[1]; + return [min, max]; + } + if(opObject.op == '/'){ + var leftMinMax = determine_min_max_possible(opObject.args[0], scope); + var rightMinMax = determine_min_max_possible(opObject.args[1], scope); + var min = leftMinMax[0] / rightMinMax[1]; + var max = leftMinMax[1] / rightMinMax[0]; + return [min, max]; + } + if(opObject.op == 'paren_express'){ + return determine_min_max_possible(opObject.args[0], scope); + } +} + function stringify_expression(evaled_op){ var sub = stringify(evaled_op.expression); var prefix = evaled_op.op[0]; diff --git a/build/dice.min.js b/build/dice.min.js index 640464d..f301a34 100644 --- a/build/dice.min.js +++ b/build/dice.min.js @@ -1,23 +1,25 @@ -(function(B){"object"===typeof exports&&"undefined"!==typeof module?module.exports=B():"function"===typeof define&&define.amd?define([],B):("undefined"!==typeof window?window:"undefined"!==typeof global?global:"undefined"!==typeof self?self:this).dice=B()})(function(){return function r(q,n,u){function f(c,g){if(!n[c]){if(!q[c]){var b="function"==typeof require&&require;if(!g&&b)return b(c,!0);if(h)return h(c,!0);b=Error("Cannot find module '"+c+"'");throw b.code="MODULE_NOT_FOUND",b;}b=n[c]={exports:{}}; -q[c][0].call(b.exports,function(g){var b=q[c][1][g];return f(b?b:g)},b,b.exports,r,q,n,u)}return n[c].exports}for(var h="function"==typeof require&&require,b=0;bb?c:b},f[0]);return{results:f,mean:c,min:parseInt(g.toFixed()),max:parseInt(b.toFixed())}};h.stringify=f;for(var b in h)n[b]=h[b];return h},{"../package":1,"./evaluate":3,"./parser":4}],3:[function(r,q,n){function u(b){var c=[];c[b]=!0;for(b=0;bs&&(s=e,C=[]),C.push(a))}function g(){return q()}function q(){var a,c,f,b;a=e;c=w();c!==d?(f=D(),f!==d?(b=p(),b!==d?a=c={op:f,args:[c,b]}:(e=a,a=d)):(e=a,a=d)):(e=a,a=d);a===d&&(a=c=p(),a===d&&(a=c=k()));return a}function k(){var a,m,b;a=e; -40===f.charCodeAt(e)?(m=T,e++):(m=d,0===l&&c(U));m!==d?(m=t(),m!==d?(m=q(),m!==d?(b=t(),b!==d?(41===f.charCodeAt(e)?(b=V,e++):(b=d,0===l&&c(W)),b!==d?a=m={op:"paren_express",args:[m]}:(e=a,a=d)):(e=a,a=d)):(e=a,a=d)):(e=a,a=d)):(e=a,a=d);return a}function r(){var a,m;a=e;m=t();m!==d?(42===f.charCodeAt(e)?(m=X,e++):(m=d,0===l&&c(Y)),m!==d?(m=t(),m!==d?a="*":(e=a,a=d)):(e=a,a=d)):(e=a,a=d);a===d&&(a=e,m=t(),m!==d?(47===f.charCodeAt(e)?(m=Z,e++):(m=d,0===l&&c($)),m!==d?(m=t(),m!==d?a="/":(e=a,a=d)): -(e=a,a=d)):(e=a,a=d));return a}function w(){var a,c,f,b;a=e;c=E();c!==d?(f=r(),f!==d?(b=w(),b!==d?a=c={op:f,args:[c,b]}:(e=a,a=d)):(e=a,a=d)):(e=a,a=d);a===d&&(a=e,c=k(),c!==d?(f=r(),f!==d?(b=w(),b!==d?a=c={op:f,args:[c,b]}:(e=a,a=d)):(e=a,a=d)):(e=a,a=d),a===d&&(a=c=E(),a===d&&(a=c=k())));return a}function p(){var a,c,f,b;a=e;c=w();c!==d?(f=D(),f!==d?(b=p(),b!==d?a=c={op:f,args:[c,b]}:(e=a,a=d)):(e=a,a=d)):(e=a,a=d);a===d&&(a=c=w(),a===d&&(a=c=k()));return a}function D(){var a,b;a=e;b=t();b!==d? -(43===f.charCodeAt(e)?(b=aa,e++):(b=d,0===l&&c(ba)),b!==d?(b=t(),b!==d?a="+":(e=a,a=d)):(e=a,a=d)):(e=a,a=d);a===d&&(a=e,b=t(),b!==d?(45===f.charCodeAt(e)?(b=F,e++):(b=d,0===l&&c(G)),b!==d?(b=t(),b!==d?a="-":(e=a,a=d)):(e=a,a=d)):(e=a,a=d));return a}function E(){var a,c,b,f;a=e;c=x();c!==d?(b=H(),b!==d?(f=I(),f!==d?a=c={op:b,args:[c,f]}:(e=a,a=d)):(e=a,a=d)):(e=a,a=d);a===d&&(a=e,c=H(),c!==d?(b=I(),b!==d?a=c={op:c,args:[{op:"static",value:1},b]}:(e=a,a=d)):(e=a,a=d),a===d&&(c=J(),c!==d&&(c={op:"d", -args:[{op:"static",value:1},c]}),a=c,a===d&&(a=c=x())));return a}function H(){var a;100===f.charCodeAt(e)?(a=ca,e++):(a=d,0===l&&c(da));a===d&&(119===f.charCodeAt(e)?(a=ea,e++):(a=d,0===l&&c(fa)));return a}function I(){var a;a=J();a===d&&(a=x(),a!==d&&(a={op:"random",args:[{op:"static",args:[],value:1},a]}));return a}function J(){var a,b,g;a=e;b=x();b!==d?(f.substr(e,2)===K?(g=K,e+=2):(g=d,0===l&&c(ga)),g!==d?(g=x(),g!==d?a=b={op:"random",args:[b,g]}:(e=a,a=d)):(e=a,a=d)):(e=a,a=d);return a}function t(){var a, -b;a=[];L.test(f.charAt(e))?(b=f.charAt(e),e++):(b=d,0===l&&c(M));for(;b!==d;)a.push(b),L.test(f.charAt(e))?(b=f.charAt(e),e++):(b=d,0===l&&c(M));return a}function x(){var a,b,g;l++;g=[];z.test(f.charAt(e))?(b=f.charAt(e),e++):(b=d,0===l&&c(A));if(b!==d)for(;b!==d;)g.push(b),z.test(f.charAt(e))?(b=f.charAt(e),e++):(b=d,0===l&&c(A));else g=d;g!==d&&(g=parseInt(g.join(""),10));a=g;if(a===d)if(a=e,45===f.charCodeAt(e)?(g=F,e++):(g=d,0===l&&c(G)),g!==d){b=[];z.test(f.charAt(e))?(g=f.charAt(e),e++):(g= -d,0===l&&c(A));if(g!==d)for(;g!==d;)b.push(g),z.test(f.charAt(e))?(g=f.charAt(e),e++):(g=d,0===l&&c(A));else b=d;b!==d?a=g=-1*parseInt(b.join(""),10):(e=a,a=d)}else e=a,a=d;l--;a===d&&0===l&&c(ha);b=a;b!==d&&(b={op:"static",value:b});a=b;a===d&&(a=b=N(),a===d&&(a=e,b=O(),b!==d?(g=N(),g!==d?a=b={op:b,args:[g]}:(e=a,a=d)):(e=a,a=d),a===d&&(a=e,b=O(),b!==d?(g=k(),g!==d?a=b={op:b,args:g.args}:(e=a,a=d)):(e=a,a=d))));return a}function O(){var a;102===f.charCodeAt(e)?(a=ia,e++):(a=d,0===l&&c(ja));a!==d&& -(a="floor");a===d&&(114===f.charCodeAt(e)?(a=ka,e++):(a=d,0===l&&c(la)),a!==d&&(a="round"),a===d&&(99===f.charCodeAt(e)?(a=ma,e++):(a=d,0===l&&c(na)),a!==d&&(a="ceil")));return a}function N(){var a,b,g;a=e;91===f.charCodeAt(e)?(b=oa,e++):(b=d,0===l&&c(pa));if(b!==d){b=[];P.test(f.charAt(e))?(g=f.charAt(e),e++):(g=d,0===l&&c(Q));if(g!==d)for(;g!==d;)b.push(g),P.test(f.charAt(e))?(g=f.charAt(e),e++):(g=d,0===l&&c(Q));else b=d;b!==d?(93===f.charCodeAt(e)?(g=qa,e++):(g=d,0===l&&c(ra)),g!==d?a=b=b.join(""): -(e=a,a=d)):(e=a,a=d)}else e=a,a=d;a!==d&&(a={op:"lookup",value:a});return a}var v=1b.description? -1:0});ba?b:a},k[0]);b=m.parse(b);h=e(b,h);return{results:k,mean:g,min:parseInt(l.toFixed()),max:parseInt(p.toFixed()),min_possible:h[0],max_possible:h[1]}};m.stringify=q;for(var b in m)r[b]=m[b];return m},{"../package":1,"./evaluate":3,"./parser":4}],3:[function(u,t,r){function s(e){var b=[];b[e]=!0;for(e=0;ev&&(v=f,D=[]),D.push(d))}function a(){return h()}function h(){var d,b,a,e;d=f;b=l();b!==c?(a=r(),a!==c?(e=p(),e!==c?d=b={op:a,args:[b,e]}:(f=d,d=c)):(f=d,d=c)):(f=d,d=c);d===c&&(d= +b=p(),d===c&&(d=b=g()));return d}function g(){var d,a,g;d=f;40===e.charCodeAt(f)?(a=R,f++):(a=c,0===n&&b(S));a!==c?(a=w(),a!==c?(a=h(),a!==c?(g=w(),g!==c?(41===e.charCodeAt(f)?(g=T,f++):(g=c,0===n&&b(U)),g!==c?d=a={op:"paren_express",args:[a]}:(f=d,d=c)):(f=d,d=c)):(f=d,d=c)):(f=d,d=c)):(f=d,d=c);return d}function k(){var d,a;d=f;a=w();a!==c?(42===e.charCodeAt(f)?(a=V,f++):(a=c,0===n&&b(W)),a!==c?(a=w(),a!==c?d="*":(f=d,d=c)):(f=d,d=c)):(f=d,d=c);d===c&&(d=f,a=w(),a!==c?(47===e.charCodeAt(f)?(a=X, +f++):(a=c,0===n&&b(Y)),a!==c?(a=w(),a!==c?d="/":(f=d,d=c)):(f=d,d=c)):(f=d,d=c));return d}function l(){var d,a,b,e;d=f;a=t();a!==c?(b=k(),b!==c?(e=l(),e!==c?d=a={op:b,args:[a,e]}:(f=d,d=c)):(f=d,d=c)):(f=d,d=c);d===c&&(d=f,a=g(),a!==c?(b=k(),b!==c?(e=l(),e!==c?d=a={op:b,args:[a,e]}:(f=d,d=c)):(f=d,d=c)):(f=d,d=c),d===c&&(d=a=t(),d===c&&(d=a=g())));return d}function p(){var d,a,b,e;d=f;a=l();a!==c?(b=r(),b!==c?(e=p(),e!==c?d=a={op:b,args:[a,e]}:(f=d,d=c)):(f=d,d=c)):(f=d,d=c);d===c&&(d=a=l(),d===c&& +(d=a=g()));return d}function r(){var d,a;d=f;a=w();a!==c?(43===e.charCodeAt(f)?(a=Z,f++):(a=c,0===n&&b($)),a!==c?(a=w(),a!==c?d="+":(f=d,d=c)):(f=d,d=c)):(f=d,d=c);d===c&&(d=f,a=w(),a!==c?(45===e.charCodeAt(f)?(a=E,f++):(a=c,0===n&&b(F)),a!==c?(a=w(),a!==c?d="-":(f=d,d=c)):(f=d,d=c)):(f=d,d=c));return d}function t(){var d,a,b,e;d=f;a=y();a!==c?(b=u(),b!==c?(e=G(),e!==c?d=a={op:b,args:[a,e]}:(f=d,d=c)):(f=d,d=c)):(f=d,d=c);d===c&&(d=f,a=u(),a!==c?(b=G(),b!==c?d=a={op:a,args:[{op:"static",value:1}, +b]}:(f=d,d=c)):(f=d,d=c),d===c&&(a=H(),a!==c&&(a={op:"d",args:[{op:"static",value:1},a]}),d=a,d===c&&(d=a=y())));return d}function u(){var d;100===e.charCodeAt(f)?(d=aa,f++):(d=c,0===n&&b(ba));d===c&&(119===e.charCodeAt(f)?(d=ca,f++):(d=c,0===n&&b(da)));return d}function G(){var d;d=H();d===c&&(d=y(),d!==c&&(d={op:"random",args:[{op:"static",args:[],value:1},d]}));return d}function H(){var d,a,g;d=f;a=y();a!==c?(e.substr(f,2)===I?(g=I,f+=2):(g=c,0===n&&b(ea)),g!==c?(g=y(),g!==c?d=a={op:"random",args:[a, +g]}:(f=d,d=c)):(f=d,d=c)):(f=d,d=c);return d}function w(){var a,g;a=[];J.test(e.charAt(f))?(g=e.charAt(f),f++):(g=c,0===n&&b(K));for(;g!==c;)a.push(g),J.test(e.charAt(f))?(g=e.charAt(f),f++):(g=c,0===n&&b(K));return a}function y(){var a,h,k;n++;k=[];A.test(e.charAt(f))?(h=e.charAt(f),f++):(h=c,0===n&&b(B));if(h!==c)for(;h!==c;)k.push(h),A.test(e.charAt(f))?(h=e.charAt(f),f++):(h=c,0===n&&b(B));else k=c;k!==c&&(k=parseInt(k.join(""),10));a=k;if(a===c)if(a=f,45===e.charCodeAt(f)?(k=E,f++):(k=c,0=== +n&&b(F)),k!==c){h=[];A.test(e.charAt(f))?(k=e.charAt(f),f++):(k=c,0===n&&b(B));if(k!==c)for(;k!==c;)h.push(k),A.test(e.charAt(f))?(k=e.charAt(f),f++):(k=c,0===n&&b(B));else h=c;h!==c?a=k=-1*parseInt(h.join(""),10):(f=a,a=c)}else f=a,a=c;n--;a===c&&0===n&&b(fa);h=a;h!==c&&(h={op:"static",value:h});a=h;a===c&&(a=h=L(),a===c&&(a=f,h=M(),h!==c?(k=L(),k!==c?a=h={op:h,args:[k]}:(f=a,a=c)):(f=a,a=c),a===c&&(a=f,h=M(),h!==c?(k=g(),k!==c?a=h={op:h,args:k.args}:(f=a,a=c)):(f=a,a=c))));return a}function M(){var a; +102===e.charCodeAt(f)?(a=ga,f++):(a=c,0===n&&b(ha));a!==c&&(a="floor");a===c&&(114===e.charCodeAt(f)?(a=ia,f++):(a=c,0===n&&b(ja)),a!==c&&(a="round"),a===c&&(99===e.charCodeAt(f)?(a=ka,f++):(a=c,0===n&&b(la)),a!==c&&(a="ceil")));return a}function L(){var a,g,h;a=f;91===e.charCodeAt(f)?(g=ma,f++):(g=c,0===n&&b(na));if(g!==c){g=[];N.test(e.charAt(f))?(h=e.charAt(f),f++):(h=c,0===n&&b(O));if(h!==c)for(;h!==c;)g.push(h),N.test(e.charAt(f))?(h=e.charAt(f),f++):(h=c,0===n&&b(O));else g=c;g!==c?(93===e.charCodeAt(f)? +(h=oa,f++):(h=c,0===n&&b(pa)),h!==c?a=g=g.join(""):(f=a,a=c)):(f=a,a=c)}else f=a,a=c;a!==c&&(a={op:"lookup",value:a});return a}var x=1b.description?1:0});b acc ? n : acc; }, resultSet[0]); + + var parsed = dice.parse(str); + + var minMaxPossible = determine_min_max_possible(parsed, scope); + return { 'results': resultSet, 'mean': mean, 'min': parseInt(min.toFixed()), - 'max': parseInt(max.toFixed()) + 'max': parseInt(max.toFixed()), + 'min_possible': minMaxPossible[0], + 'max_possible': minMaxPossible[1] }; }; +function determine_min_max_possible(opObject, scope){ + if(opObject.op == 'static'){ + return [opObject.value, opObject.value]; + } + if(opObject.op == 'lookup'){ + var lookup = dice.ops.lookup.call(opObject, scope); + return [lookup(scope), lookup(scope)]; + } + if(opObject.op == 'floor'){ + var minmax = determine_min_max_possible(opObject.args[0], scope); + return [Math.floor(minmax[0]), Math.floor(minmax[1])]; + } + if(opObject.op == 'ceil'){ + var minmax = determine_min_max_possible(opObject.args[0], scope); + return [Math.ceil(minmax[0]), Math.ceil(minmax[1])]; + } + if(opObject.op == 'round'){ + var minmax = determine_min_max_possible(opObject.args[0], scope); + return [Math.round(minmax[0]), Math.round(minmax[1])]; + } + if(opObject.op == 'd'){ + var multipleMinMax = determine_min_max_possible(opObject.args[0], scope); + var randPartMinMax = determine_min_max_possible(opObject.args[1], scope); + var min = randPartMinMax[0] * multipleMinMax[0]; + var max = randPartMinMax[1] * multipleMinMax[1]; + return [min, max]; + } + if(opObject.op == 'w'){ + var multipleMinMax = determine_min_max_possible(opObject.args[0], scope); + var randPartMinMax = determine_min_max_possible(opObject.args[1], scope); + var min = randPartMinMax[0] * multipleMinMax[0]; + var max = randPartMinMax[1] * multipleMinMax[1]; + return [min, max]; + } + if(opObject.op == 'random'){ + var minMinMax = determine_min_max_possible(opObject.args[0], scope); + var maxMinMax = determine_min_max_possible(opObject.args[1], scope); + return [minMinMax[0], maxMinMax[1]]; + } + if(opObject.op == '+'){ + var leftMinMax = determine_min_max_possible(opObject.args[0], scope); + var rightMinMax = determine_min_max_possible(opObject.args[1], scope); + var min = leftMinMax[0] + rightMinMax[0]; + var max = leftMinMax[1] + rightMinMax[1]; + return [min, max]; + } + if(opObject.op == '-'){ + var leftMinMax = determine_min_max_possible(opObject.args[0], scope); + var rightMinMax = determine_min_max_possible(opObject.args[1], scope); + var min = leftMinMax[0] - rightMinMax[0]; + var max = leftMinMax[1] - rightMinMax[1]; + return [min, max]; + } + if(opObject.op == '*'){ + var leftMinMax = determine_min_max_possible(opObject.args[0], scope); + var rightMinMax = determine_min_max_possible(opObject.args[1], scope); + var min = leftMinMax[0] * rightMinMax[0]; + var max = leftMinMax[1] * rightMinMax[1]; + return [min, max]; + } + if(opObject.op == '/'){ + var leftMinMax = determine_min_max_possible(opObject.args[0], scope); + var rightMinMax = determine_min_max_possible(opObject.args[1], scope); + var min = leftMinMax[0] / rightMinMax[1]; + var max = leftMinMax[1] / rightMinMax[0]; + return [min, max]; + } + if(opObject.op == 'paren_express'){ + return determine_min_max_possible(opObject.args[0], scope); + } +} + function stringify_expression(evaled_op){ var sub = stringify(evaled_op.expression); var prefix = evaled_op.op[0]; diff --git a/tests/dice.spec.js b/tests/dice.spec.js index c39e629..2c6d251 100644 --- a/tests/dice.spec.js +++ b/tests/dice.spec.js @@ -246,5 +246,44 @@ describe("Dice", function(){ }); }); + + describe("simple statisitcs tests", function(){ + + var name_base = "provides min_possible and max_possible for "; + var scope = { + "v1": 1, + "v10": 10, + "v2": 2 + }; + var inputs = [ + {str: "d20", min: 1, max: 20}, + {str: "[v1]d20", min: 1, max: 20}, + {str: "3d6", min: 3, max: 18}, + {str: "2d6 + 1d20", min: 3, max: 32}, + {str: "1d4..10", min: 4, max: 10}, + {str: "2d6 + 7", min: 9, max: 19}, + {str: "2d[v2]..6 + [v1]", min: 5, max: 13}, + {str: "2d6 * 3", min: 6, max: 36}, + // max is dirived by taking highest possible numerator / lowest possiblbe denominator + // while min is smallest possible numberator / highest possible denominator + {str: "3d6 / 2d[v10]", min: 0.15, max: 9}, + // 2d6 * 3 + 1 / 2d6 + 1 + // 6..36 + (1/2..1/12) + 1 + {str: "[v2]d6 * 3 + [v1] / f(5 / 2)d6 + 1", min: 7 + (1/12), max: 37.5}, + {str: "f(2d10)w10", min: 2, max: 200}, + {str: "3 + r(7 / 2)d10", min: 7, max: 43}, + {str: "3dc(3 / 2)..7", min: 6, max: 21} + ]; + inputs.map(function(opts){ + it(name_base + opts.str, function(){ + var stats = dice.statistics(opts.str, scope, 1); + expect(stats.min_possible).toEqual(opts.min); + expect(stats.max_possible).toEqual(opts.max); + }); + }); + + + }); + });