sbc-rating-calculator
Version:
A JavaScript library for calculating Squad Building Challenge (SBC) team ratings and finding optimal squad configurations for UT
3 lines (2 loc) • 7.44 kB
JavaScript
!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).SBCRatingCalculator={})}(this,(function(t){"use strict";var n,i,e,a,s,o;var r=function(){if(o)return s;o=1;const{SolverHelper:t}=(i||(i=1,n={SolverHelper:class{static getMultisubsetsCount(t,n){return 0===n||0===t?0===n?1:0:this.factorial(t+n-1)/(this.factorial(t-1)*this.factorial(n))}static factorial(t){if(t<0)return 0;if(0===t||1===t)return 1;let n=1;for(let i=2;i<=t;i++)n*=i;return n}static getRating(t){if(!t||0===t.length)return 0;const n=[...t];for(;n.length<11;)n.push(0);const i=n.reduce(((t,n)=>t+n),0),e=i/11,a=i+n.reduce(((t,n)=>n>e?t+(n-e):t),0),s=Math.round(a);return Math.floor(s/11)}static getPrice(t,n){return t.reduce(((t,i)=>t+(n[i]||0)),0)}static getMultisubsets(t,n){return this.multisubsetsImpl(t,n)}static*multisubsetsImpl(t,n){if(0===n)yield[];else if(t.length>0){const[i,...e]=t;for(let t=0;t<=n;t++)yield*this.prependNTimes(i,this.multisubsetsImpl(e,n-t),t)}}static*prependNTimes(t,n,i){const e=Array(i).fill(t);for(let t of n)yield[...e,...t]}static validateInputs(t){const{targetRating:n,existingRatings:i,availableRatings:e,squadSize:a}=t,s=[];return("number"!=typeof n||n<45||n>99)&&s.push("Target rating must be a number between 45 and 99"),Array.isArray(i)?i.forEach(((t,n)=>{("number"!=typeof t||t<45||t>99)&&s.push(`Invalid rating at index ${n}: ${t}`)})):s.push("Existing ratings must be an array"),Array.isArray(e)?e.forEach(((t,n)=>{("number"!=typeof t||t<45||t>99)&&s.push(`Invalid available rating at index ${n}: ${t}`)})):s.push("Available ratings must be an array"),("number"!=typeof a||a<1||a>23)&&s.push("Squad size must be a number between 1 and 23"),i&&a&&i.length>a&&s.push("Existing ratings exceed squad size"),{valid:0===s.length,errors:s}}static getUniqueRatings(t){return[...new Set(t)].sort(((t,n)=>t-n))}static countRatings(t){return t.reduce(((t,n)=>(t[n]=(t[n]||0)+1,t)),{})}}}),n),{getOptimalCombinations:r,isCombinationPossible:u,combinationToArray:l,calculateCombinationPoints:c}=function(){if(a)return e;a=1;const t={80:[{82:1,81:2,80:8},{83:1,80:10},{82:2,80:9},{81:4,80:7},{84:1,79:10},{82:3,79:8}],81:[{82:3,81:8},{83:1,81:10},{84:1,80:10},{82:5,80:6},{83:2,80:9},{85:1,79:10}],82:[{83:2,82:9},{84:1,82:10},{83:4,81:7},{85:1,81:10},{84:2,81:9},{86:1,80:10}],83:[{83:9,82:2},{84:1,83:6,82:4},{85:1,82:10},{84:2,83:7,82:2},{86:1,82:10},{84:3,82:8}],84:[{84:11},{85:1,84:8,83:2},{86:1,83:10},{85:2,84:7,83:2},{87:1,83:10},{85:3,83:8}],85:[{85:11},{86:1,85:8,84:2},{87:1,84:10},{86:2,85:7,84:2},{88:1,84:10},{86:3,84:8}],86:[{86:11},{87:1,86:8,85:2},{88:1,85:10},{87:2,86:7,85:2},{89:1,85:10},{87:3,85:8}],87:[{87:11},{88:1,87:8,86:2},{89:1,86:10},{88:2,87:7,86:2},{90:1,86:10},{88:3,86:8}],88:[{88:11},{89:1,88:8,87:2},{90:1,87:10},{89:2,88:7,87:2},{91:1,87:10},{89:3,87:8}],89:[{89:11},{90:1,89:8,88:2},{91:1,88:10},{90:2,89:7,88:2},{92:1,88:10},{90:3,88:8}],90:[{90:11},{91:1,90:8,89:2},{92:1,89:10},{91:2,90:7,89:2},{93:1,89:10},{91:3,89:8}],91:[{91:11},{92:1,91:8,90:2},{93:1,90:10},{92:2,91:7,90:2},{94:1,90:10},{92:3,90:8}],92:[{92:11},{93:1,92:8,91:2},{94:1,91:10},{93:2,92:7,91:2},{95:1,91:10},{93:3,91:8}]};return e={OPTIMAL_SBC_COMBINATIONS:t,getOptimalCombinations:function(n){return n<80||n>92?[]:t[n]||[]},isCombinationPossible:function(t,n){for(const[i,e]of Object.entries(t))if((n[parseInt(i)]||0)<e)return!1;return!0},combinationToArray:function(t){const n=[];for(const[i,e]of Object.entries(t))for(let t=0;t<e;t++)n.push(parseInt(i));return n},calculateCombinationPoints:function(t){let n=0;for(const[i,e]of Object.entries(t))n+=parseInt(i)*e;return n}}}();function g(n,i,e,a=!0){try{const{targetRating:s,existingRatings:o,ratingsToTry:r,priceByRating:u}=n;let l=[];if(s>99||s<45)return{solutionsFound:0,solutions:[]};const c=i-o.length;if(c<=0){const n=t.getRating(o);return n>=s?{solutionsFound:1,solutions:[{price:0,squad:[],actualRating:n,totalRatingPoints:o.reduce(((t,n)=>t+n),0),efficiency:0}]}:{solutionsFound:0,solutions:[]}}const g=t.countRatings(r),f=t.getMultisubsets(r,c);for(const n of f){const i=t.countRatings(n);let e=!0;for(const[t,n]of Object.entries(i))if((g[t]||0)<n){e=!1;break}if(!e)continue;const a=[...o,...n],r=t.getRating(a);if(r<s)continue;const c=n.reduce((function(t,n){return t[n]=(t[n]||0)+1,t}),{}),f=Object.keys(c).map((function(t){return{rating:+t,count:c[+t]}})),d=a.reduce(((t,n)=>t+n),0),p=t.getPrice(n,u),m=d/Math.max(r,1);l.push({price:p,squad:f,actualRating:r,totalRatingPoints:d,efficiency:m,combinationUsed:n})}return a?l.sort((function(t,n){return t.price!==n.price?t.price-n.price:t.totalRatingPoints-n.totalRatingPoints})):l.sort((function(t,n){return t.totalRatingPoints!==n.totalRatingPoints?t.totalRatingPoints-n.totalRatingPoints:t.price-n.price})),e&&e>0&&(l=l.slice(0,e)),{solutionsFound:l.length,solutions:l}}catch(t){return{error:t.message||"An error occurred",solutionsFound:0,solutions:[]}}}return s={SBCRatingCalculator:class{constructor(t={}){this.defaultSquadSize=t.defaultSquadSize||11,this.defaultMaxSolutions=t.defaultMaxSolutions||50}calculateTeamRating(n){return t.getRating(n)}findOptimalSolutions(n){const{targetRating:i,availableRatings:e=[],priceByRating:a={},maxSolutions:s=10}=n,o=r(i);if(0===o.length)return{solutionsFound:0,solutions:[],message:`No optimal combinations available for rating ${i}. Use findSquadSolutions for custom search.`};const g=t.countRatings(e),f=[];for(const n of o.slice(0,s))if(u(n,g)){const e=l(n),s=t.getPrice(e,a),o=c(n),r=Object.entries(n).map((([t,n])=>({rating:parseInt(t),count:n})));f.push({price:s,squad:r,actualRating:i,totalRatingPoints:o,efficiency:o/i,isOptimal:!0})}return{solutionsFound:f.length,solutions:f.sort(((t,n)=>t.totalRatingPoints-n.totalRatingPoints))}}findSquadSolutions(n){const{targetRating:i,existingRatings:e=[],availableRatings:a=[],priceByRating:s={},squadSize:o=this.defaultSquadSize,maxSolutions:r=this.defaultMaxSolutions,sortByPrice:u=!0,useOptimalCombinations:l=!0}=n;if(0===e.length&&l&&i>=80&&i<=92&&a.length>50){const t=this.findOptimalSolutions({targetRating:i,availableRatings:a,priceByRating:s,maxSolutions:r});if(t.solutionsFound>0)return t}const c=t.validateInputs({targetRating:i,existingRatings:e,availableRatings:a,squadSize:o});return c.valid?g({targetRating:i,existingRatings:e,ratingsToTry:a,priceByRating:s},o,r,u):{error:c.errors.join(", "),solutionsFound:0,solutions:[]}}findMostEfficientSolutions(t){return this.findSquadSolutions({...t,sortByPrice:!1})}calculateMinimumRatingNeeded(t,n,i,e=11){const a=11*t-n.reduce(((t,n)=>t+n),0);return Math.ceil(a/i)}validateSquad(t,n,i=11){if(t.length!==i)return{valid:!1,message:`Squad must have exactly ${i} players`,actualRating:null};const e=this.calculateTeamRating(t),a=e>=n;return{valid:a,actualRating:e,targetRating:n,message:a?`Squad achieves target rating (${e} >= ${n})`:`Squad rating too low (${e} < ${n})`}}getRatingStatistics(t){if(!t||0===t.length)return{min:0,max:0,average:0,median:0,count:0};const n=[...t].sort(((t,n)=>t-n)),i=t.length,e=t.reduce(((t,n)=>t+n),0),a=Math.round(e/i*100)/100,s=i%2==0?(n[i/2-1]+n[i/2])/2:n[Math.floor(i/2)];return{min:n[0],max:n[i-1],average:a,median:s,count:i}}},calculateSquadSolutions:g,SolverHelper:t}}(),u=r.default;t.default=u,Object.defineProperty(t,"__esModule",{value:!0})}));
//# sourceMappingURL=index.umd.min.js.map