@allemandi/gacha-engine 0.3.4 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -10
- package/dist/gacha-engine.d.ts +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.module.js +1 -1
- package/dist/index.module.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -107,7 +107,7 @@ const pools = [
|
|
|
107
107
|
{
|
|
108
108
|
rarity: 'SSR',
|
|
109
109
|
items: [
|
|
110
|
-
{ name: '
|
|
110
|
+
{ name: 'Superior Rat', weight: 0.003, rateUp: true },
|
|
111
111
|
{ name: 'Dumpster King', weight: 0.002 }
|
|
112
112
|
]
|
|
113
113
|
},
|
|
@@ -129,30 +129,27 @@ const engine = new GachaEngine({ mode: 'flatRate', pools });
|
|
|
129
129
|
|
|
130
130
|
console.log('Roll x5:', engine.roll(5).join(', '));
|
|
131
131
|
|
|
132
|
-
const dropRate = engine.getItemDropRate('
|
|
133
|
-
console.log('Drop rate for
|
|
132
|
+
const dropRate = engine.getItemDropRate('Superior Rat');
|
|
133
|
+
console.log('Drop rate for Superior Rat:', (dropRate * 100) + '%');
|
|
134
134
|
// 0.3%
|
|
135
135
|
|
|
136
|
-
const cumulative = engine.getCumulativeProbabilityForItem('
|
|
136
|
+
const cumulative = engine.getCumulativeProbabilityForItem('Superior Rat', 500);
|
|
137
137
|
console.log('Chance after 500 rolls:', (cumulative * 100).toFixed(1) + '%');
|
|
138
138
|
// ~78.5%
|
|
139
139
|
|
|
140
|
-
const rollsFor50 = engine.getRollsForTargetProbability('
|
|
140
|
+
const rollsFor50 = engine.getRollsForTargetProbability('Superior Rat', 0.5);
|
|
141
141
|
console.log('Rolls for 50% chance:', rollsFor50);
|
|
142
142
|
// ~231
|
|
143
143
|
|
|
144
144
|
console.log('Rate-up items:', engine.getRateUpItems().join(', '));
|
|
145
|
-
//
|
|
146
|
-
|
|
147
|
-
console.log('All items:', engine.getAllItems().join(', '));
|
|
148
|
-
// God-Tier Rat, Dumpster King, Sleepy Chef, Unknown Student
|
|
145
|
+
// Superior Rat
|
|
149
146
|
```
|
|
150
147
|
|
|
151
148
|
**UMD (Browser, Weighted Mode)**
|
|
152
149
|
```html
|
|
153
150
|
<script src="https://unpkg.com/@allemandi/gacha-engine"></script>
|
|
154
151
|
<script>
|
|
155
|
-
const { GachaEngine } =
|
|
152
|
+
const { GachaEngine } = AllemandiGachaEngine;
|
|
156
153
|
|
|
157
154
|
const engine = new GachaEngine({
|
|
158
155
|
mode: 'weighted',
|
package/dist/gacha-engine.d.ts
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function t(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,a=Array(e);r<e;r++)a[r]=t[r];return a}function e(e,r){var a="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(a)return(a=a.call(e)).next.bind(a);if(Array.isArray(e)||(a=function(e,r){if(e){if("string"==typeof e)return t(e,r);var a={}.toString.call(e).slice(8,-1);return"Object"===a&&e.constructor&&(a=e.constructor.name),"Map"===a||"Set"===a?Array.from(e):"Arguments"===a||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(a)?t(e,r):void 0}}(e))||r&&e&&"number"==typeof e.length){a&&(e=a);var n=0;return function(){return n>=e.length?{done:!0}:{done:!1,value:e[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function r(){return r=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var a in r)({}).hasOwnProperty.call(r,a)&&(t[a]=r[a])}return t},r.apply(null,arguments)}var a,n=/*#__PURE__*/function(){function t(t){if(this.mode=void 0,this.pools=[],this.rarityRatesScaled={},this.flatRateMap=new Map,this.dropRateCacheScaled=new Map,this.mode=t.mode,"weighted"===t.mode){var r=t;this.pools=r.pools,this.rarityRatesScaled=this.scaleRarityRates(r.rarityRates),this.validateConfig(r.rarityRates)}else{if("flatRate"!==t.mode)throw new Error("Unknown gacha mode: "+this.mode);for(var
|
|
1
|
+
function t(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,a=Array(e);r<e;r++)a[r]=t[r];return a}function e(e,r){var a="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(a)return(a=a.call(e)).next.bind(a);if(Array.isArray(e)||(a=function(e,r){if(e){if("string"==typeof e)return t(e,r);var a={}.toString.call(e).slice(8,-1);return"Object"===a&&e.constructor&&(a=e.constructor.name),"Map"===a||"Set"===a?Array.from(e):"Arguments"===a||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(a)?t(e,r):void 0}}(e))||r&&e&&"number"==typeof e.length){a&&(e=a);var n=0;return function(){return n>=e.length?{done:!0}:{done:!1,value:e[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function r(){return r=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var a in r)({}).hasOwnProperty.call(r,a)&&(t[a]=r[a])}return t},r.apply(null,arguments)}var a,n=/*#__PURE__*/function(){function t(t){if(this.mode=void 0,this.pools=[],this.rarityRatesScaled={},this.flatRateMap=new Map,this.dropRateCacheScaled=new Map,this.flatRateRateUpItems=[],this.mode=t.mode,"weighted"===t.mode){var r=t;this.pools=r.pools,this.rarityRatesScaled=this.scaleRarityRates(r.rarityRates),this.validateConfig(r.rarityRates)}else{if("flatRate"!==t.mode)throw new Error("Unknown gacha mode: "+this.mode);var a=t;this.pools=a.pools;for(var n,i=e(a.pools);!(n=i()).done;)for(var o,s=e(n.value.items);!(o=s()).done;){var l=o.value;if(l.weight<0)throw new Error('FlatRate item "'+l.name+'" must have non-negative weight');this.flatRateMap.set(l.name,l.weight),l.rateUp&&this.flatRateRateUpItems.push(l.name)}var h=Array.from(this.flatRateMap.values()).reduce(function(t,e){return t+e},0);if(Math.abs(h-1)>1e-6)throw new Error("FlatRate item rates must sum to 1.0, but got "+h)}}var a=t.prototype;return a.scaleRarityRates=function(t){for(var e={},r=0,a=Object.entries(t);r<a.length;r++){var n=a[r],i=n[0],o=n[1];if(o<0||o>1)throw new Error('Rarity rate for "'+i+'" must be between 0 and 1, got '+o);e[i]=this.toScaled(o)}return e},a.toScaled=function(e){if(e>t.MAX_SAFE_SCALE/t.SCALE)throw new Error("Probability "+e+" too large for safe integer arithmetic");return Math.round(e*t.SCALE)},a.fromScaled=function(e){return e/t.SCALE},a.validateConfig=function(t){var r=new Set(Object.keys(this.rarityRatesScaled)),a=new Set(this.pools.map(function(t){return t.rarity})),n=Array.from(a).filter(function(t){return!r.has(t)});if(n.length>0)throw new Error("Missing rarity rates for: "+n.join(", "));var i=Object.values(t).reduce(function(t,e){return t+e},0);if(Math.abs(i-1)>1e-10)throw new Error("Rarity rates must sum to 1.0, got "+i);for(var o,s=e(this.pools);!(o=s()).done;){var l=o.value;if(0===l.items.length)throw new Error('Rarity "'+l.rarity+'" has no items');if(l.items.reduce(function(t,e){return t+e.weight},0)<=0)throw new Error('Rarity "'+l.rarity+'" has zero total weight');for(var h,u=e(l.items);!(h=u()).done;){var f=h.value;if(f.weight<0)throw new Error('Item "'+f.name+'" weight must be non-negative, got '+f.weight)}if(!l.items.some(function(t){return t.weight>0}))throw new Error('Rarity "'+l.rarity+'" must have at least one item with positive weight')}},a.getItemDropRate=function(r){if("flatRate"===this.mode)return this.flatRateMap.get(r)||0;if(this.dropRateCacheScaled.has(r))return this.fromScaled(this.dropRateCacheScaled.get(r));for(var a,n=e(this.pools);!(a=n()).done;){var i=a.value,o=i.items.find(function(t){return t.name===r});if(o){if(0===o.weight)return this.dropRateCacheScaled.set(r,0),0;var s=i.items.reduce(function(t,e){return t+e.weight},0),l=this.rarityRatesScaled[i.rarity],h=this.toScaled(o.weight),u=this.toScaled(s),f=Math.round(h*l/t.SCALE),c=Math.round(f*t.SCALE/u);return this.dropRateCacheScaled.set(r,c),this.fromScaled(c)}}throw new Error('Item "'+r+'" not found')},a.getCumulativeProbabilityForItem=function(t,e){var r=this.getItemDropRate(t);return 0===r?0:r>=1?1:1-Math.pow(1-r,e)},a.getRollsForTargetProbability=function(t,e){if(e<=0)return 0;if(e>=1)return 1;var r=this.getItemDropRate(t);return r<=0?Infinity:Math.ceil(Math.log(1-e)/Math.log(1-r))},a.getRateUpItems=function(){return"weighted"===this.mode?this.pools.flatMap(function(t){return t.items.filter(function(t){return t.rateUp}).map(function(t){return t.name})}):this.flatRateRateUpItems},a.getAllItemDropRates=function(){var t=this;return"flatRate"===this.mode?Array.from(this.flatRateMap.entries()).map(function(t){return{name:t[0],dropRate:t[1],rarity:"flatRate"}}):this.pools.flatMap(function(e){return e.items.map(function(r){return{name:r.name,dropRate:t.getItemDropRate(r.name),rarity:e.rarity}})})},a.roll=function(t){var r=this;void 0===t&&(t=1);for(var a=[],n=function(){if("flatRate"===r.mode)for(var t,n=Math.random(),i=0,o=e(r.flatRateMap.entries());!(t=o()).done;){var s=t.value;if(n<(i+=s[1])){a.push(s[0]);break}}else{var l=r.selectRarity(),h=r.pools.find(function(t){return t.rarity===l}),u=r.selectItemFromPool(h);a.push(u.name)}},i=0;i<t;i++)n();return a},a.selectRarity=function(){for(var e=Math.floor(Math.random()*t.SCALE),r=0,a=0,n=Object.entries(this.rarityRatesScaled);a<n.length;a++){var i=n[a];if(e<(r+=i[1]))return i[0]}return Object.keys(this.rarityRatesScaled)[0]},a.selectItemFromPool=function(t){for(var a,n=this,i=t.items.filter(function(t){return t.weight>0}),o=i.map(function(t){return r({},t,{scaledWeight:n.toScaled(t.weight)})}),s=o.reduce(function(t,e){return t+e.scaledWeight},0),l=Math.floor(Math.random()*s),h=0,u=e(o);!(a=u()).done;){var f=a.value;if(l<(h+=f.scaledWeight))return{name:f.name,weight:f.weight}}return i[0]},a.getDebugInfo=function(){for(var e={},a=0,n=Object.entries(this.rarityRatesScaled);a<n.length;a++){var i=n[a];e[i[0]]=this.fromScaled(i[1])}return{scale:t.SCALE,rarityRatesScaled:r({},this.rarityRatesScaled),rarityRatesFloat:e}},t}();a=n,n.SCALE=1e6,n.MAX_SAFE_SCALE=Math.floor(Number.MAX_SAFE_INTEGER/a.SCALE),exports.GachaEngine=n;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/gacha-engine.ts"],"sourcesContent":["import {\n RarityInput,\n GachaEngineConfig,\n WeightedGachaEngineConfig,\n FlatRateGachaEngineConfig,\n} from './types';\n\nexport class GachaEngine {\n private static readonly SCALE = 1_000_000;\n private static readonly MAX_SAFE_SCALE = Math.floor(Number.MAX_SAFE_INTEGER / GachaEngine.SCALE);\n\n private mode: 'weighted' | 'flatRate';\n private pools: RarityInput[] = [];\n private rarityRatesScaled: Record<string, number> = {};\n private flatRateMap: Map<string, number> = new Map();\n private dropRateCacheScaled = new Map<string, number>();\n\n constructor(config: GachaEngineConfig) {\n this.mode = config.mode;\n\n if (config.mode === 'weighted') {\n const weightedConfig = config as WeightedGachaEngineConfig;\n this.pools = weightedConfig.pools;\n this.rarityRatesScaled = this.scaleRarityRates(weightedConfig.rarityRates);\n this.validateConfig(weightedConfig.rarityRates);\n } else if (config.mode === 'flatRate') {\n const flatConfig = config as FlatRateGachaEngineConfig;\n for (const pool of flatConfig.pools) {\n for (const item of pool.items) {\n if (item.weight < 0) {\n throw new Error(`FlatRate item \"${item.name}\" must have non-negative weight`);\n }\n this.flatRateMap.set(item.name, item.weight); // Here, interpreted as direct probability\n }\n }\n const total = Array.from(this.flatRateMap.values()).reduce((sum, v) => sum + v, 0);\n if (Math.abs(total - 1.0) > 1e-6) {\n throw new Error(`FlatRate item rates must sum to 1.0, but got ${total}`);\n }\n } else {\n throw new Error(`Unknown gacha mode: ${this.mode}`);\n }\n }\n\n private scaleRarityRates(rarityRates: Record<string, number>): Record<string, number> {\n const scaled: Record<string, number> = {};\n for (const [rarity, rate] of Object.entries(rarityRates)) {\n if (rate < 0 || rate > 1) {\n throw new Error(`Rarity rate for \"${rarity}\" must be between 0 and 1, got ${rate}`);\n }\n scaled[rarity] = this.toScaled(rate);\n }\n return scaled;\n }\n\n private toScaled(probability: number): number {\n if (probability > GachaEngine.MAX_SAFE_SCALE / GachaEngine.SCALE) {\n throw new Error(`Probability ${probability} too large for safe integer arithmetic`);\n }\n return Math.round(probability * GachaEngine.SCALE);\n }\n\n private fromScaled(scaledInt: number): number {\n return scaledInt / GachaEngine.SCALE;\n }\n\n private validateConfig(originalRates: Record<string, number>): void {\n const configuredRarities = new Set(Object.keys(this.rarityRatesScaled));\n const usedRarities = new Set(this.pools.map(p => p.rarity));\n const missing = Array.from(usedRarities).filter(r => !configuredRarities.has(r));\n\n if (missing.length > 0) {\n throw new Error(`Missing rarity rates for: ${missing.join(', ')}`);\n }\n\n const totalRate = Object.values(originalRates).reduce((sum, rate) => sum + rate, 0);\n if (Math.abs(totalRate - 1.0) > 1e-10) {\n throw new Error(`Rarity rates must sum to 1.0, got ${totalRate}`);\n }\n\n for (const pool of this.pools) {\n if (pool.items.length === 0) {\n throw new Error(`Rarity \"${pool.rarity}\" has no items`);\n }\n\n const totalWeight = pool.items.reduce((sum, i) => sum + i.weight, 0);\n if (totalWeight <= 0) {\n throw new Error(`Rarity \"${pool.rarity}\" has zero total weight`);\n }\n\n for (const item of pool.items) {\n if (item.weight < 0) {\n throw new Error(`Item \"${item.name}\" weight must be non-negative, got ${item.weight}`);\n }\n }\n\n if (!pool.items.some(i => i.weight > 0)) {\n throw new Error(`Rarity \"${pool.rarity}\" must have at least one item with positive weight`);\n }\n }\n }\n\n getItemDropRate(name: string): number {\n if (this.mode === 'flatRate') {\n return this.flatRateMap.get(name) || 0;\n }\n\n if (this.dropRateCacheScaled.has(name)) {\n return this.fromScaled(this.dropRateCacheScaled.get(name)!);\n }\n\n for (const pool of this.pools) {\n const item = pool.items.find(i => i.name === name);\n if (item) {\n if (item.weight === 0) {\n this.dropRateCacheScaled.set(name, 0);\n return 0;\n }\n\n const totalPoolWeight = pool.items.reduce((sum, i) => sum + i.weight, 0);\n const baseRarityRateScaled = this.rarityRatesScaled[pool.rarity];\n const itemWeightScaled = this.toScaled(item.weight);\n const totalWeightScaled = this.toScaled(totalPoolWeight);\n const numeratorScaled = Math.round((itemWeightScaled * baseRarityRateScaled) / GachaEngine.SCALE);\n const rateScaled = Math.round((numeratorScaled * GachaEngine.SCALE) / totalWeightScaled);\n\n this.dropRateCacheScaled.set(name, rateScaled);\n return this.fromScaled(rateScaled);\n }\n }\n\n throw new Error(`Item \"${name}\" not found`);\n }\n\n getCumulativeProbabilityForItem(name: string, rolls: number): number {\n const rate = this.getItemDropRate(name);\n if (rate === 0) return 0;\n if (rate >= 1) return 1;\n\n const cumulativeFailProbability = Math.pow(1 - rate, rolls);\n return 1 - cumulativeFailProbability;\n }\n\n getRollsForTargetProbability(name: string, targetProbability: number): number {\n if (targetProbability <= 0) return 0;\n if (targetProbability >= 1) return 1;\n\n const rate = this.getItemDropRate(name);\n if (rate <= 0) return Infinity;\n return Math.ceil(Math.log(1 - targetProbability) / Math.log(1 - rate));\n }\n\n getRateUpItems(): string[] {\n if (this.mode === 'weighted') {\n return this.pools.flatMap(p => p.items.filter(i => i.rateUp).map(i => i.name));\n } else {\n if (this.pools.length > 0) {\n return this.pools.flatMap(p => p.items.filter(i => i.rateUp).map(i => i.name));\n }\n return [];\n }\n}\n\n\n getAllItemDropRates(): { name: string; dropRate: number; rarity: string }[] {\n if (this.mode === 'flatRate') {\n return Array.from(this.flatRateMap.entries()).map(([name, dropRate]) => ({\n name,\n dropRate,\n rarity: 'flatRate',\n }));\n }\n\n return this.pools.flatMap(p =>\n p.items.map(i => ({\n name: i.name,\n dropRate: this.getItemDropRate(i.name),\n rarity: p.rarity,\n }))\n );\n }\n\n roll(count: number = 1): string[] {\n const results: string[] = [];\n for (let i = 0; i < count; i++) {\n if (this.mode === 'flatRate') {\n const rand = Math.random();\n let cumulative = 0;\n for (const [name, rate] of this.flatRateMap.entries()) {\n cumulative += rate;\n if (rand < cumulative) {\n results.push(name);\n break;\n }\n }\n } else {\n const rarity = this.selectRarity();\n const pool = this.pools.find(p => p.rarity === rarity)!;\n const item = this.selectItemFromPool(pool);\n results.push(item.name);\n }\n }\n return results;\n }\n\n private selectRarity(): string {\n const rand = Math.floor(Math.random() * GachaEngine.SCALE);\n let cumulative = 0;\n\n for (const [rarity, scaledRate] of Object.entries(this.rarityRatesScaled)) {\n cumulative += scaledRate;\n if (rand < cumulative) return rarity;\n }\n\n return Object.keys(this.rarityRatesScaled)[0];\n }\n\n private selectItemFromPool(pool: RarityInput): { name: string; weight: number } {\n const items = pool.items.filter(i => i.weight > 0);\n const scaledItems = items.map(i => ({\n ...i,\n scaledWeight: this.toScaled(i.weight),\n }));\n\n const totalScaledWeight = scaledItems.reduce((sum, i) => sum + i.scaledWeight, 0);\n const rand = Math.floor(Math.random() * totalScaledWeight);\n let cumulative = 0;\n\n for (const item of scaledItems) {\n cumulative += item.scaledWeight;\n if (rand < cumulative) {\n return { name: item.name, weight: item.weight };\n }\n }\n\n return items[0]; // Fallback\n }\n\n getDebugInfo(): {\n scale: number;\n rarityRatesScaled: Record<string, number>;\n rarityRatesFloat: Record<string, number>;\n } {\n const rarityRatesFloat: Record<string, number> = {};\n for (const [rarity, scaledRate] of Object.entries(this.rarityRatesScaled)) {\n rarityRatesFloat[rarity] = this.fromScaled(scaledRate);\n }\n\n return {\n scale: GachaEngine.SCALE,\n rarityRatesScaled: { ...this.rarityRatesScaled },\n rarityRatesFloat,\n };\n }\n}\n"],"names":["GachaEngine","config","this","mode","pools","rarityRatesScaled","flatRateMap","Map","dropRateCacheScaled","weightedConfig","scaleRarityRates","rarityRates","validateConfig","Error","_step","_iterator","_createForOfIteratorHelperLoose","done","_step2","_iterator2","value","items","item","weight","name","set","total","Array","from","values","reduce","sum","v","Math","abs","_proto","prototype","scaled","_i","_Object$entries","Object","entries","length","_Object$entries$_i","rarity","rate","toScaled","probability","MAX_SAFE_SCALE","SCALE","round","fromScaled","scaledInt","originalRates","configuredRarities","Set","keys","usedRarities","map","p","missing","filter","r","has","join","totalRate","_iterator3","_step3","pool","i","_iterator4","_step4","some","getItemDropRate","get","_iterator5","_step5","find","totalPoolWeight","baseRarityRateScaled","itemWeightScaled","totalWeightScaled","numeratorScaled","rateScaled","getCumulativeProbabilityForItem","rolls","pow","getRollsForTargetProbability","targetProbability","Infinity","ceil","log","getRateUpItems","flatMap","rateUp","getAllItemDropRates","_this","_ref","dropRate","roll","count","_this2","results","_loop","_step6","rand","random","cumulative","_iterator6","_step6$value","push","selectRarity","selectItemFromPool","floor","_i2","_Object$entries2","_Object$entries2$_i","_this3","_step7","scaledItems","_extends","scaledWeight","totalScaledWeight","_iterator7","getDebugInfo","rarityRatesFloat","_i3","_Object$entries3","_Object$entries3$_i","scale","Number","MAX_SAFE_INTEGER"],"mappings":"kgCAOaA,eAAW,WAUtB,SAAAA,EAAYC,GAGV,GAHmCC,KAN7BC,UAAI,EAAAD,KACJE,MAAuB,GACvBC,KAAAA,kBAA4C,CAAA,EAAEH,KAC9CI,YAAmC,IAAIC,IAAKL,KAC5CM,oBAAsB,IAAID,IAGhCL,KAAKC,KAAOF,EAAOE,KAEC,aAAhBF,EAAOE,KAAqB,CAC9B,IAAMM,EAAiBR,EACvBC,KAAKE,MAAQK,EAAeL,MAC5BF,KAAKG,kBAAoBH,KAAKQ,iBAAiBD,EAAeE,aAC9DT,KAAKU,eAAeH,EAAeE,YACrC,KAAO,IAAoB,aAAhBV,EAAOE,KAehB,MAAM,IAAIU,6BAA6BX,KAAKC,MAb5C,IADA,IACmCW,EAAnCC,EAAAC,EADmBf,EACWG,SAAKU,EAAAC,KAAAE,MACjC,IADS,IACoBC,EAA7BC,EAAAH,EADaF,EAAAM,MACWC,SAAKH,EAAAC,KAAAF,MAAE,CAApB,IAAAK,EAAIJ,EAAAE,MACb,GAAIE,EAAKC,OAAS,EAChB,MAAU,IAAAV,MAAK,kBAAmBS,EAAKE,KAAqC,mCAE9EtB,KAAKI,YAAYmB,IAAIH,EAAKE,KAAMF,EAAKC,OACvC,CAEF,IAAMG,EAAQC,MAAMC,KAAK1B,KAAKI,YAAYuB,UAAUC,OAAO,SAACC,EAAKC,UAAMD,EAAMC,CAAC,EAAE,GAChF,GAAIC,KAAKC,IAAIR,EAAQ,GAAO,KAC1B,MAAM,IAAIb,MAAsDa,gDAAAA,EAIpE,CACF,CAAC,IAAAS,EAAAnC,EAAAoC,iBAAAD,EAEOzB,iBAAA,SAAiBC,GAEvB,IADA,IAAM0B,EAAiC,CAAE,EACzCC,EAAAC,EAAAA,EAA6BC,OAAOC,QAAQ9B,GAAY2B,EAAAC,EAAAG,OAAAJ,IAAE,CAArD,IAAAK,EAAAJ,EAAAD,GAAOM,EAAMD,EAAA,GAAEE,EAAIF,EAAA,GACtB,GAAIE,EAAO,GAAKA,EAAO,EACrB,MAAU,IAAAhC,MAAK,oBAAqB+B,EAAwCC,kCAAAA,GAE9ER,EAAOO,GAAU1C,KAAK4C,SAASD,EACjC,CACA,OAAOR,CACT,EAACF,EAEOW,SAAA,SAASC,GACf,GAAIA,EAAc/C,EAAYgD,eAAiBhD,EAAYiD,MACzD,UAAUpC,MAAqBkC,eAAAA,EAAmD,0CAEpF,OAAOd,KAAKiB,MAAMH,EAAc/C,EAAYiD,MAC9C,EAACd,EAEOgB,WAAA,SAAWC,GACjB,OAAOA,EAAYpD,EAAYiD,KACjC,EAACd,EAEOvB,eAAA,SAAeyC,GACrB,IAAMC,EAAqB,IAAIC,IAAIf,OAAOgB,KAAKtD,KAAKG,oBAC9CoD,EAAe,IAAIF,IAAIrD,KAAKE,MAAMsD,IAAI,SAAAC,GAAC,OAAIA,EAAEf,MAAM,IACnDgB,EAAUjC,MAAMC,KAAK6B,GAAcI,OAAO,SAAAC,GAAK,OAACR,EAAmBS,IAAID,EAAE,GAE/E,GAAIF,EAAQlB,OAAS,EACnB,MAAM,IAAI7B,MAAmC+C,6BAAAA,EAAQI,KAAK,OAG5D,IAAMC,EAAYzB,OAAOX,OAAOwB,GAAevB,OAAO,SAACC,EAAKc,GAAS,OAAAd,EAAMc,CAAI,EAAE,GACjF,GAAIZ,KAAKC,IAAI+B,EAAY,GAAO,MAC9B,UAAUpD,MAA2CoD,qCAAAA,GAGvD,IAAAC,IAA6BC,EAA7BD,EAAAlD,EAAmBd,KAAKE,SAAK+D,EAAAD,KAAAjD,MAAE,CAApB,IAAAmD,EAAID,EAAA/C,MACb,GAA0B,IAAtBgD,EAAK/C,MAAMqB,OACb,MAAU,IAAA7B,MAAiBuD,WAAAA,EAAKxB,OAAsB,kBAIxD,GADoBwB,EAAK/C,MAAMS,OAAO,SAACC,EAAKsC,GAAM,OAAAtC,EAAMsC,EAAE9C,MAAM,EAAE,IAC/C,EACjB,MAAM,IAAIV,MAAiBuD,WAAAA,EAAKxB,OAAM,2BAGxC,IAAA0B,IAA6BC,EAA7BD,EAAAtD,EAAmBoD,EAAK/C,SAAKkD,EAAAD,KAAArD,MAAE,CAApB,IAAAK,EAAIiD,EAAAnD,MACb,GAAIE,EAAKC,OAAS,EAChB,MAAU,IAAAV,MAAK,SAAUS,EAAKE,KAA0CF,sCAAAA,EAAKC,OAEjF,CAEA,IAAK6C,EAAK/C,MAAMmD,KAAK,SAAAH,GAAK,OAAAA,EAAE9C,OAAS,CAAC,GACpC,MAAM,IAAIV,MAAK,WAAYuD,EAAKxB,OAAM,qDAE1C,CACF,EAACT,EAEDsC,gBAAA,SAAgBjD,GACd,GAAkB,aAAdtB,KAAKC,KACP,OAAOD,KAAKI,YAAYoE,IAAIlD,IAAS,EAGvC,GAAItB,KAAKM,oBAAoBuD,IAAIvC,GAC/B,OAAOtB,KAAKiD,WAAWjD,KAAKM,oBAAoBkE,IAAIlD,IAGtD,IAAAmD,IAA6BC,EAA7BD,EAAA3D,EAAmBd,KAAKE,SAAKwE,EAAAD,KAAA1D,MAAE,CAApB,IAAAmD,EAAIQ,EAAAxD,MACPE,EAAO8C,EAAK/C,MAAMwD,KAAK,SAAAR,GAAK,OAAAA,EAAE7C,OAASA,CAAI,GACjD,GAAIF,EAAM,CACR,GAAoB,IAAhBA,EAAKC,OAEP,OADArB,KAAKM,oBAAoBiB,IAAID,EAAM,GAC5B,EAGT,IAAMsD,EAAkBV,EAAK/C,MAAMS,OAAO,SAACC,EAAKsC,GAAM,OAAAtC,EAAMsC,EAAE9C,MAAM,EAAE,GAChEwD,EAAuB7E,KAAKG,kBAAkB+D,EAAKxB,QACnDoC,EAAmB9E,KAAK4C,SAASxB,EAAKC,QACtC0D,EAAoB/E,KAAK4C,SAASgC,GAClCI,EAAkBjD,KAAKiB,MAAO8B,EAAmBD,EAAwB/E,EAAYiD,OACrFkC,EAAalD,KAAKiB,MAAOgC,EAAkBlF,EAAYiD,MAASgC,GAGtE,OADA/E,KAAKM,oBAAoBiB,IAAID,EAAM2D,GAC5BjF,KAAKiD,WAAWgC,EACzB,CACF,CAEA,MAAM,IAAItE,MAAeW,SAAAA,EAAiB,cAC5C,EAACW,EAEDiD,gCAAA,SAAgC5D,EAAc6D,GAC5C,IAAMxC,EAAO3C,KAAKuE,gBAAgBjD,GAClC,OAAa,IAATqB,EAAmB,EACnBA,GAAQ,EAAW,EAGhB,EAD2BZ,KAAKqD,IAAI,EAAIzC,EAAMwC,EAEvD,EAAClD,EAEDoD,6BAAA,SAA6B/D,EAAcgE,GACzC,GAAIA,GAAqB,EAAG,OAAQ,EACpC,GAAIA,GAAqB,EAAG,OAAQ,EAEpC,IAAM3C,EAAO3C,KAAKuE,gBAAgBjD,GAClC,OAAIqB,GAAQ,EAAU4C,SACfxD,KAAKyD,KAAKzD,KAAK0D,IAAI,EAAIH,GAAqBvD,KAAK0D,IAAI,EAAI9C,GAClE,EAACV,EAEFyD,eAAA,WACC,MAAkB,aAAd1F,KAAKC,MAGHD,KAAKE,MAAMsC,OAAS,EAFbxC,KAACE,MAAMyF,QAAQ,SAAAlC,GAAK,OAAAA,EAAEtC,MAAMwC,OAAO,SAAAQ,GAAC,OAAIA,EAAEyB,MAAM,GAAEpC,IAAI,SAAAW,UAAKA,EAAE7C,IAAI,EAAC,GAKtE,EAEX,EAACW,EAGC4D,oBAAA,WAAmB,IAAAC,EAAA9F,KACjB,MAAkB,aAAdA,KAAKC,KACAwB,MAAMC,KAAK1B,KAAKI,YAAYmC,WAAWiB,IAAI,SAAAuC,GAAgB,MAAO,CACvEzE,KADsDyE,EAAA,GAEtDC,SAFgED,EAAA,GAGhErD,OAAQ,WACT,GAGQ1C,KAACE,MAAMyF,QAAQ,SAAAlC,GAAC,OACzBA,EAAEtC,MAAMqC,IAAI,SAAAW,GAAC,MAAK,CAChB7C,KAAM6C,EAAE7C,KACR0E,SAAUF,EAAKvB,gBAAgBJ,EAAE7C,MACjCoB,OAAQe,EAAEf,OACX,EAAE,EAEP,EAACT,EAEDgE,KAAA,SAAKC,GAAiB,IAAAC,EAAAnG,cAAjBkG,IAAAA,EAAgB,GAEnB,IADA,IAAME,EAAoB,GAAGC,EAAA,WAE3B,GAAkB,aAAdF,EAAKlG,KAGP,IAFA,IAEqDqG,EAF/CC,EAAOxE,KAAKyE,SACdC,EAAa,EACjBC,EAAA5F,EAA2BqF,EAAK/F,YAAYmC,aAAS+D,EAAAI,KAAA3F,MAAE,CAAA,IAAA4F,EAAAL,EAAApF,MAErD,GAAIqF,GADJE,GADoBE,EACpBF,IACuB,CACrBL,EAAQQ,KAHID,EAAEhE,IAId,KACF,CACF,KACK,CACL,IAAMD,EAASyD,EAAKU,eACd3C,EAAOiC,EAAKjG,MAAMyE,KAAK,SAAAlB,GAAK,OAAAA,EAAEf,SAAWA,CAAM,GAC/CtB,EAAO+E,EAAKW,mBAAmB5C,GACrCkC,EAAQQ,KAAKxF,EAAKE,KACpB,CACF,EAjBS6C,EAAI,EAAGA,EAAI+B,EAAO/B,IAAGkC,IAkB9B,OAAOD,CACT,EAACnE,EAEO4E,aAAA,WAIN,IAHA,IAAMN,EAAOxE,KAAKgF,MAAMhF,KAAKyE,SAAW1G,EAAYiD,OAChD0D,EAAa,EAEjBO,EAAAC,EAAAA,EAAmC3E,OAAOC,QAAQvC,KAAKG,mBAAkB6G,EAAAC,EAAAzE,OAAAwE,IAAE,CAAtE,IAAAE,EAAAD,EAAAD,GAEH,GAAIT,GADJE,GAD4BS,EAC5BT,IACuB,OAFPS,EAAA,EAGlB,CAEA,OAAO5E,OAAOgB,KAAKtD,KAAKG,mBAAmB,EAC7C,EAAC8B,EAEO6E,mBAAA,SAAmB5C,GAWzB,IAX0CiD,IAWZC,EAXYD,EAC1CnH,KAAMmB,EAAQ+C,EAAK/C,MAAMwC,OAAO,SAAAQ,GAAK,OAAAA,EAAE9C,OAAS,CAAC,GAC3CgG,EAAclG,EAAMqC,IAAI,SAAAW,GAACmD,OAAAA,KAC1BnD,EAAC,CACJoD,aAAcJ,EAAKvE,SAASuB,EAAE9C,SAAO,GAGjCmG,EAAoBH,EAAYzF,OAAO,SAACC,EAAKsC,GAAC,OAAKtC,EAAMsC,EAAEoD,YAAY,EAAE,GACzEhB,EAAOxE,KAAKgF,MAAMhF,KAAKyE,SAAWgB,GACpCf,EAAa,EAEjBgB,EAAA3G,EAAmBuG,KAAWD,EAAAK,KAAA1G,MAAE,CAArB,IAAAK,EAAIgG,EAAAlG,MAEb,GAAIqF,GADJE,GAAcrF,EAAKmG,cAEjB,MAAO,CAAEjG,KAAMF,EAAKE,KAAMD,OAAQD,EAAKC,OAE3C,CAEA,OAAOF,EAAM,EACf,EAACc,EAEDyF,aAAA,WAME,IADA,IAAMC,EAA2C,CAAA,EACjDC,EAAAC,EAAAA,EAAmCvF,OAAOC,QAAQvC,KAAKG,mBAAkByH,EAAAC,EAAArF,OAAAoF,IAAE,CAAtE,IAAAE,EAAAD,EAAAD,GACHD,EADgBG,EAAA,IACW9H,KAAKiD,WADJ6E,EAAA,GAE9B,CAEA,MAAO,CACLC,MAAOjI,EAAYiD,MACnB5C,kBAAiBmH,EAAA,CAAA,EAAOtH,KAAKG,mBAC7BwH,iBAAAA,EAEJ,EAAC7H,CAAA,CAtPqB,KAAXA,EAAAA,EACaiD,MAAQ,IADrBjD,EAEagD,eAAiBf,KAAKgF,MAAMiB,OAAOC,iBAAmBnI,EAAYiD"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/gacha-engine.ts"],"sourcesContent":["import {\n RarityInput,\n GachaEngineConfig,\n WeightedGachaEngineConfig,\n FlatRateGachaEngineConfig,\n} from './types';\n\nexport class GachaEngine {\n private static readonly SCALE = 1_000_000;\n private static readonly MAX_SAFE_SCALE = Math.floor(Number.MAX_SAFE_INTEGER / GachaEngine.SCALE);\n\n private mode: 'weighted' | 'flatRate';\n private pools: RarityInput[] = [];\n private rarityRatesScaled: Record<string, number> = {};\n private flatRateMap: Map<string, number> = new Map();\n private dropRateCacheScaled = new Map<string, number>();\n private flatRateRateUpItems: string[] = [];\n\n constructor(config: GachaEngineConfig) {\n this.mode = config.mode;\n\n if (config.mode === 'weighted') {\n const weightedConfig = config as WeightedGachaEngineConfig;\n this.pools = weightedConfig.pools;\n this.rarityRatesScaled = this.scaleRarityRates(weightedConfig.rarityRates);\n this.validateConfig(weightedConfig.rarityRates);\n } else if (config.mode === 'flatRate') {\n const flatConfig = config as FlatRateGachaEngineConfig;\n this.pools = flatConfig.pools; // Keep pools for reference\n\n for (const pool of flatConfig.pools) {\n for (const item of pool.items) {\n if (item.weight < 0) {\n throw new Error(`FlatRate item \"${item.name}\" must have non-negative weight`);\n }\n this.flatRateMap.set(item.name, item.weight); // direct probability\n if (item.rateUp) {\n this.flatRateRateUpItems.push(item.name);\n }\n }\n }\n const total = Array.from(this.flatRateMap.values()).reduce((sum, v) => sum + v, 0);\n if (Math.abs(total - 1.0) > 1e-6) {\n throw new Error(`FlatRate item rates must sum to 1.0, but got ${total}`);\n }\n } else {\n throw new Error(`Unknown gacha mode: ${this.mode}`);\n }\n }\n\n private scaleRarityRates(rarityRates: Record<string, number>): Record<string, number> {\n const scaled: Record<string, number> = {};\n for (const [rarity, rate] of Object.entries(rarityRates)) {\n if (rate < 0 || rate > 1) {\n throw new Error(`Rarity rate for \"${rarity}\" must be between 0 and 1, got ${rate}`);\n }\n scaled[rarity] = this.toScaled(rate);\n }\n return scaled;\n }\n\n private toScaled(probability: number): number {\n if (probability > GachaEngine.MAX_SAFE_SCALE / GachaEngine.SCALE) {\n throw new Error(`Probability ${probability} too large for safe integer arithmetic`);\n }\n return Math.round(probability * GachaEngine.SCALE);\n }\n\n private fromScaled(scaledInt: number): number {\n return scaledInt / GachaEngine.SCALE;\n }\n\n private validateConfig(originalRates: Record<string, number>): void {\n const configuredRarities = new Set(Object.keys(this.rarityRatesScaled));\n const usedRarities = new Set(this.pools.map(p => p.rarity));\n const missing = Array.from(usedRarities).filter(r => !configuredRarities.has(r));\n\n if (missing.length > 0) {\n throw new Error(`Missing rarity rates for: ${missing.join(', ')}`);\n }\n\n const totalRate = Object.values(originalRates).reduce((sum, rate) => sum + rate, 0);\n if (Math.abs(totalRate - 1.0) > 1e-10) {\n throw new Error(`Rarity rates must sum to 1.0, got ${totalRate}`);\n }\n\n for (const pool of this.pools) {\n if (pool.items.length === 0) {\n throw new Error(`Rarity \"${pool.rarity}\" has no items`);\n }\n\n const totalWeight = pool.items.reduce((sum, i) => sum + i.weight, 0);\n if (totalWeight <= 0) {\n throw new Error(`Rarity \"${pool.rarity}\" has zero total weight`);\n }\n\n for (const item of pool.items) {\n if (item.weight < 0) {\n throw new Error(`Item \"${item.name}\" weight must be non-negative, got ${item.weight}`);\n }\n }\n\n if (!pool.items.some(i => i.weight > 0)) {\n throw new Error(`Rarity \"${pool.rarity}\" must have at least one item with positive weight`);\n }\n }\n }\n\n getItemDropRate(name: string): number {\n if (this.mode === 'flatRate') {\n return this.flatRateMap.get(name) || 0;\n }\n\n if (this.dropRateCacheScaled.has(name)) {\n return this.fromScaled(this.dropRateCacheScaled.get(name)!);\n }\n\n for (const pool of this.pools) {\n const item = pool.items.find(i => i.name === name);\n if (item) {\n if (item.weight === 0) {\n this.dropRateCacheScaled.set(name, 0);\n return 0;\n }\n\n const totalPoolWeight = pool.items.reduce((sum, i) => sum + i.weight, 0);\n const baseRarityRateScaled = this.rarityRatesScaled[pool.rarity];\n const itemWeightScaled = this.toScaled(item.weight);\n const totalWeightScaled = this.toScaled(totalPoolWeight);\n const numeratorScaled = Math.round((itemWeightScaled * baseRarityRateScaled) / GachaEngine.SCALE);\n const rateScaled = Math.round((numeratorScaled * GachaEngine.SCALE) / totalWeightScaled);\n\n this.dropRateCacheScaled.set(name, rateScaled);\n return this.fromScaled(rateScaled);\n }\n }\n\n throw new Error(`Item \"${name}\" not found`);\n }\n\n getCumulativeProbabilityForItem(name: string, rolls: number): number {\n const rate = this.getItemDropRate(name);\n if (rate === 0) return 0;\n if (rate >= 1) return 1;\n\n const cumulativeFailProbability = Math.pow(1 - rate, rolls);\n return 1 - cumulativeFailProbability;\n }\n\n getRollsForTargetProbability(name: string, targetProbability: number): number {\n if (targetProbability <= 0) return 0;\n if (targetProbability >= 1) return 1;\n\n const rate = this.getItemDropRate(name);\n if (rate <= 0) return Infinity;\n return Math.ceil(Math.log(1 - targetProbability) / Math.log(1 - rate));\n }\n\n getRateUpItems(): string[] {\n if (this.mode === 'weighted') {\n return this.pools.flatMap(p => p.items.filter(i => i.rateUp).map(i => i.name));\n } else {\n return this.flatRateRateUpItems;\n }\n }\n\n getAllItemDropRates(): { name: string; dropRate: number; rarity: string }[] {\n if (this.mode === 'flatRate') {\n return Array.from(this.flatRateMap.entries()).map(([name, dropRate]) => ({\n name,\n dropRate,\n rarity: 'flatRate',\n }));\n }\n\n return this.pools.flatMap(p =>\n p.items.map(i => ({\n name: i.name,\n dropRate: this.getItemDropRate(i.name),\n rarity: p.rarity,\n }))\n );\n }\n\n roll(count: number = 1): string[] {\n const results: string[] = [];\n for (let i = 0; i < count; i++) {\n if (this.mode === 'flatRate') {\n const rand = Math.random();\n let cumulative = 0;\n for (const [name, rate] of this.flatRateMap.entries()) {\n cumulative += rate;\n if (rand < cumulative) {\n results.push(name);\n break;\n }\n }\n } else {\n const rarity = this.selectRarity();\n const pool = this.pools.find(p => p.rarity === rarity)!;\n const item = this.selectItemFromPool(pool);\n results.push(item.name);\n }\n }\n return results;\n }\n\n private selectRarity(): string {\n const rand = Math.floor(Math.random() * GachaEngine.SCALE);\n let cumulative = 0;\n\n for (const [rarity, scaledRate] of Object.entries(this.rarityRatesScaled)) {\n cumulative += scaledRate;\n if (rand < cumulative) return rarity;\n }\n\n return Object.keys(this.rarityRatesScaled)[0];\n }\n\n private selectItemFromPool(pool: RarityInput): { name: string; weight: number } {\n const items = pool.items.filter(i => i.weight > 0);\n const scaledItems = items.map(i => ({\n ...i,\n scaledWeight: this.toScaled(i.weight),\n }));\n\n const totalScaledWeight = scaledItems.reduce((sum, i) => sum + i.scaledWeight, 0);\n const rand = Math.floor(Math.random() * totalScaledWeight);\n let cumulative = 0;\n\n for (const item of scaledItems) {\n cumulative += item.scaledWeight;\n if (rand < cumulative) {\n return { name: item.name, weight: item.weight };\n }\n }\n\n return items[0]; // Fallback\n }\n\n getDebugInfo(): {\n scale: number;\n rarityRatesScaled: Record<string, number>;\n rarityRatesFloat: Record<string, number>;\n } {\n const rarityRatesFloat: Record<string, number> = {};\n for (const [rarity, scaledRate] of Object.entries(this.rarityRatesScaled)) {\n rarityRatesFloat[rarity] = this.fromScaled(scaledRate);\n }\n\n return {\n scale: GachaEngine.SCALE,\n rarityRatesScaled: { ...this.rarityRatesScaled },\n rarityRatesFloat,\n };\n }\n}\n"],"names":["GachaEngine","config","this","mode","pools","rarityRatesScaled","flatRateMap","Map","dropRateCacheScaled","flatRateRateUpItems","weightedConfig","scaleRarityRates","rarityRates","validateConfig","Error","flatConfig","_iterator","_step","_createForOfIteratorHelperLoose","done","_step2","_iterator2","value","items","item","weight","name","set","rateUp","push","total","Array","from","values","reduce","sum","v","Math","abs","_proto","prototype","scaled","_i","_Object$entries","Object","entries","length","_Object$entries$_i","rarity","rate","toScaled","probability","MAX_SAFE_SCALE","SCALE","round","fromScaled","scaledInt","originalRates","configuredRarities","Set","keys","usedRarities","map","p","missing","filter","r","has","join","totalRate","_step3","_iterator3","pool","i","_iterator4","_step4","some","getItemDropRate","get","_iterator5","_step5","find","totalPoolWeight","baseRarityRateScaled","itemWeightScaled","totalWeightScaled","numeratorScaled","rateScaled","getCumulativeProbabilityForItem","rolls","pow","getRollsForTargetProbability","targetProbability","Infinity","ceil","log","getRateUpItems","flatMap","getAllItemDropRates","_this","_ref","dropRate","roll","count","_this2","results","_loop","_step6","rand","random","cumulative","_iterator6","_step6$value","selectRarity","selectItemFromPool","floor","_i2","_Object$entries2","_Object$entries2$_i","_this3","_step7","scaledItems","_extends","scaledWeight","totalScaledWeight","_iterator7","getDebugInfo","rarityRatesFloat","_i3","_Object$entries3","_Object$entries3$_i","scale","Number","MAX_SAFE_INTEGER"],"mappings":"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"}
|
package/dist/index.module.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function t(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,a=Array(e);r<e;r++)a[r]=t[r];return a}function e(e,r){var a="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(a)return(a=a.call(e)).next.bind(a);if(Array.isArray(e)||(a=function(e,r){if(e){if("string"==typeof e)return t(e,r);var a={}.toString.call(e).slice(8,-1);return"Object"===a&&e.constructor&&(a=e.constructor.name),"Map"===a||"Set"===a?Array.from(e):"Arguments"===a||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(a)?t(e,r):void 0}}(e))||r&&e&&"number"==typeof e.length){a&&(e=a);var n=0;return function(){return n>=e.length?{done:!0}:{done:!1,value:e[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function r(){return r=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var a in r)({}).hasOwnProperty.call(r,a)&&(t[a]=r[a])}return t},r.apply(null,arguments)}var a,n=/*#__PURE__*/function(){function t(t){if(this.mode=void 0,this.pools=[],this.rarityRatesScaled={},this.flatRateMap=new Map,this.dropRateCacheScaled=new Map,this.mode=t.mode,"weighted"===t.mode){var r=t;this.pools=r.pools,this.rarityRatesScaled=this.scaleRarityRates(r.rarityRates),this.validateConfig(r.rarityRates)}else{if("flatRate"!==t.mode)throw new Error("Unknown gacha mode: "+this.mode);for(var
|
|
1
|
+
function t(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,a=Array(e);r<e;r++)a[r]=t[r];return a}function e(e,r){var a="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(a)return(a=a.call(e)).next.bind(a);if(Array.isArray(e)||(a=function(e,r){if(e){if("string"==typeof e)return t(e,r);var a={}.toString.call(e).slice(8,-1);return"Object"===a&&e.constructor&&(a=e.constructor.name),"Map"===a||"Set"===a?Array.from(e):"Arguments"===a||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(a)?t(e,r):void 0}}(e))||r&&e&&"number"==typeof e.length){a&&(e=a);var n=0;return function(){return n>=e.length?{done:!0}:{done:!1,value:e[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function r(){return r=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var a in r)({}).hasOwnProperty.call(r,a)&&(t[a]=r[a])}return t},r.apply(null,arguments)}var a,n=/*#__PURE__*/function(){function t(t){if(this.mode=void 0,this.pools=[],this.rarityRatesScaled={},this.flatRateMap=new Map,this.dropRateCacheScaled=new Map,this.flatRateRateUpItems=[],this.mode=t.mode,"weighted"===t.mode){var r=t;this.pools=r.pools,this.rarityRatesScaled=this.scaleRarityRates(r.rarityRates),this.validateConfig(r.rarityRates)}else{if("flatRate"!==t.mode)throw new Error("Unknown gacha mode: "+this.mode);var a=t;this.pools=a.pools;for(var n,i=e(a.pools);!(n=i()).done;)for(var o,s=e(n.value.items);!(o=s()).done;){var l=o.value;if(l.weight<0)throw new Error('FlatRate item "'+l.name+'" must have non-negative weight');this.flatRateMap.set(l.name,l.weight),l.rateUp&&this.flatRateRateUpItems.push(l.name)}var u=Array.from(this.flatRateMap.values()).reduce(function(t,e){return t+e},0);if(Math.abs(u-1)>1e-6)throw new Error("FlatRate item rates must sum to 1.0, but got "+u)}}var a=t.prototype;return a.scaleRarityRates=function(t){for(var e={},r=0,a=Object.entries(t);r<a.length;r++){var n=a[r],i=n[0],o=n[1];if(o<0||o>1)throw new Error('Rarity rate for "'+i+'" must be between 0 and 1, got '+o);e[i]=this.toScaled(o)}return e},a.toScaled=function(e){if(e>t.MAX_SAFE_SCALE/t.SCALE)throw new Error("Probability "+e+" too large for safe integer arithmetic");return Math.round(e*t.SCALE)},a.fromScaled=function(e){return e/t.SCALE},a.validateConfig=function(t){var r=new Set(Object.keys(this.rarityRatesScaled)),a=new Set(this.pools.map(function(t){return t.rarity})),n=Array.from(a).filter(function(t){return!r.has(t)});if(n.length>0)throw new Error("Missing rarity rates for: "+n.join(", "));var i=Object.values(t).reduce(function(t,e){return t+e},0);if(Math.abs(i-1)>1e-10)throw new Error("Rarity rates must sum to 1.0, got "+i);for(var o,s=e(this.pools);!(o=s()).done;){var l=o.value;if(0===l.items.length)throw new Error('Rarity "'+l.rarity+'" has no items');if(l.items.reduce(function(t,e){return t+e.weight},0)<=0)throw new Error('Rarity "'+l.rarity+'" has zero total weight');for(var u,h=e(l.items);!(u=h()).done;){var f=u.value;if(f.weight<0)throw new Error('Item "'+f.name+'" weight must be non-negative, got '+f.weight)}if(!l.items.some(function(t){return t.weight>0}))throw new Error('Rarity "'+l.rarity+'" must have at least one item with positive weight')}},a.getItemDropRate=function(r){if("flatRate"===this.mode)return this.flatRateMap.get(r)||0;if(this.dropRateCacheScaled.has(r))return this.fromScaled(this.dropRateCacheScaled.get(r));for(var a,n=e(this.pools);!(a=n()).done;){var i=a.value,o=i.items.find(function(t){return t.name===r});if(o){if(0===o.weight)return this.dropRateCacheScaled.set(r,0),0;var s=i.items.reduce(function(t,e){return t+e.weight},0),l=this.rarityRatesScaled[i.rarity],u=this.toScaled(o.weight),h=this.toScaled(s),f=Math.round(u*l/t.SCALE),c=Math.round(f*t.SCALE/h);return this.dropRateCacheScaled.set(r,c),this.fromScaled(c)}}throw new Error('Item "'+r+'" not found')},a.getCumulativeProbabilityForItem=function(t,e){var r=this.getItemDropRate(t);return 0===r?0:r>=1?1:1-Math.pow(1-r,e)},a.getRollsForTargetProbability=function(t,e){if(e<=0)return 0;if(e>=1)return 1;var r=this.getItemDropRate(t);return r<=0?Infinity:Math.ceil(Math.log(1-e)/Math.log(1-r))},a.getRateUpItems=function(){return"weighted"===this.mode?this.pools.flatMap(function(t){return t.items.filter(function(t){return t.rateUp}).map(function(t){return t.name})}):this.flatRateRateUpItems},a.getAllItemDropRates=function(){var t=this;return"flatRate"===this.mode?Array.from(this.flatRateMap.entries()).map(function(t){return{name:t[0],dropRate:t[1],rarity:"flatRate"}}):this.pools.flatMap(function(e){return e.items.map(function(r){return{name:r.name,dropRate:t.getItemDropRate(r.name),rarity:e.rarity}})})},a.roll=function(t){var r=this;void 0===t&&(t=1);for(var a=[],n=function(){if("flatRate"===r.mode)for(var t,n=Math.random(),i=0,o=e(r.flatRateMap.entries());!(t=o()).done;){var s=t.value;if(n<(i+=s[1])){a.push(s[0]);break}}else{var l=r.selectRarity(),u=r.pools.find(function(t){return t.rarity===l}),h=r.selectItemFromPool(u);a.push(h.name)}},i=0;i<t;i++)n();return a},a.selectRarity=function(){for(var e=Math.floor(Math.random()*t.SCALE),r=0,a=0,n=Object.entries(this.rarityRatesScaled);a<n.length;a++){var i=n[a];if(e<(r+=i[1]))return i[0]}return Object.keys(this.rarityRatesScaled)[0]},a.selectItemFromPool=function(t){for(var a,n=this,i=t.items.filter(function(t){return t.weight>0}),o=i.map(function(t){return r({},t,{scaledWeight:n.toScaled(t.weight)})}),s=o.reduce(function(t,e){return t+e.scaledWeight},0),l=Math.floor(Math.random()*s),u=0,h=e(o);!(a=h()).done;){var f=a.value;if(l<(u+=f.scaledWeight))return{name:f.name,weight:f.weight}}return i[0]},a.getDebugInfo=function(){for(var e={},a=0,n=Object.entries(this.rarityRatesScaled);a<n.length;a++){var i=n[a];e[i[0]]=this.fromScaled(i[1])}return{scale:t.SCALE,rarityRatesScaled:r({},this.rarityRatesScaled),rarityRatesFloat:e}},t}();a=n,n.SCALE=1e6,n.MAX_SAFE_SCALE=Math.floor(Number.MAX_SAFE_INTEGER/a.SCALE);export{n as GachaEngine};
|
|
2
2
|
//# sourceMappingURL=index.module.js.map
|
package/dist/index.module.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.module.js","sources":["../src/gacha-engine.ts"],"sourcesContent":["import {\n RarityInput,\n GachaEngineConfig,\n WeightedGachaEngineConfig,\n FlatRateGachaEngineConfig,\n} from './types';\n\nexport class GachaEngine {\n private static readonly SCALE = 1_000_000;\n private static readonly MAX_SAFE_SCALE = Math.floor(Number.MAX_SAFE_INTEGER / GachaEngine.SCALE);\n\n private mode: 'weighted' | 'flatRate';\n private pools: RarityInput[] = [];\n private rarityRatesScaled: Record<string, number> = {};\n private flatRateMap: Map<string, number> = new Map();\n private dropRateCacheScaled = new Map<string, number>();\n\n constructor(config: GachaEngineConfig) {\n this.mode = config.mode;\n\n if (config.mode === 'weighted') {\n const weightedConfig = config as WeightedGachaEngineConfig;\n this.pools = weightedConfig.pools;\n this.rarityRatesScaled = this.scaleRarityRates(weightedConfig.rarityRates);\n this.validateConfig(weightedConfig.rarityRates);\n } else if (config.mode === 'flatRate') {\n const flatConfig = config as FlatRateGachaEngineConfig;\n for (const pool of flatConfig.pools) {\n for (const item of pool.items) {\n if (item.weight < 0) {\n throw new Error(`FlatRate item \"${item.name}\" must have non-negative weight`);\n }\n this.flatRateMap.set(item.name, item.weight); // Here, interpreted as direct probability\n }\n }\n const total = Array.from(this.flatRateMap.values()).reduce((sum, v) => sum + v, 0);\n if (Math.abs(total - 1.0) > 1e-6) {\n throw new Error(`FlatRate item rates must sum to 1.0, but got ${total}`);\n }\n } else {\n throw new Error(`Unknown gacha mode: ${this.mode}`);\n }\n }\n\n private scaleRarityRates(rarityRates: Record<string, number>): Record<string, number> {\n const scaled: Record<string, number> = {};\n for (const [rarity, rate] of Object.entries(rarityRates)) {\n if (rate < 0 || rate > 1) {\n throw new Error(`Rarity rate for \"${rarity}\" must be between 0 and 1, got ${rate}`);\n }\n scaled[rarity] = this.toScaled(rate);\n }\n return scaled;\n }\n\n private toScaled(probability: number): number {\n if (probability > GachaEngine.MAX_SAFE_SCALE / GachaEngine.SCALE) {\n throw new Error(`Probability ${probability} too large for safe integer arithmetic`);\n }\n return Math.round(probability * GachaEngine.SCALE);\n }\n\n private fromScaled(scaledInt: number): number {\n return scaledInt / GachaEngine.SCALE;\n }\n\n private validateConfig(originalRates: Record<string, number>): void {\n const configuredRarities = new Set(Object.keys(this.rarityRatesScaled));\n const usedRarities = new Set(this.pools.map(p => p.rarity));\n const missing = Array.from(usedRarities).filter(r => !configuredRarities.has(r));\n\n if (missing.length > 0) {\n throw new Error(`Missing rarity rates for: ${missing.join(', ')}`);\n }\n\n const totalRate = Object.values(originalRates).reduce((sum, rate) => sum + rate, 0);\n if (Math.abs(totalRate - 1.0) > 1e-10) {\n throw new Error(`Rarity rates must sum to 1.0, got ${totalRate}`);\n }\n\n for (const pool of this.pools) {\n if (pool.items.length === 0) {\n throw new Error(`Rarity \"${pool.rarity}\" has no items`);\n }\n\n const totalWeight = pool.items.reduce((sum, i) => sum + i.weight, 0);\n if (totalWeight <= 0) {\n throw new Error(`Rarity \"${pool.rarity}\" has zero total weight`);\n }\n\n for (const item of pool.items) {\n if (item.weight < 0) {\n throw new Error(`Item \"${item.name}\" weight must be non-negative, got ${item.weight}`);\n }\n }\n\n if (!pool.items.some(i => i.weight > 0)) {\n throw new Error(`Rarity \"${pool.rarity}\" must have at least one item with positive weight`);\n }\n }\n }\n\n getItemDropRate(name: string): number {\n if (this.mode === 'flatRate') {\n return this.flatRateMap.get(name) || 0;\n }\n\n if (this.dropRateCacheScaled.has(name)) {\n return this.fromScaled(this.dropRateCacheScaled.get(name)!);\n }\n\n for (const pool of this.pools) {\n const item = pool.items.find(i => i.name === name);\n if (item) {\n if (item.weight === 0) {\n this.dropRateCacheScaled.set(name, 0);\n return 0;\n }\n\n const totalPoolWeight = pool.items.reduce((sum, i) => sum + i.weight, 0);\n const baseRarityRateScaled = this.rarityRatesScaled[pool.rarity];\n const itemWeightScaled = this.toScaled(item.weight);\n const totalWeightScaled = this.toScaled(totalPoolWeight);\n const numeratorScaled = Math.round((itemWeightScaled * baseRarityRateScaled) / GachaEngine.SCALE);\n const rateScaled = Math.round((numeratorScaled * GachaEngine.SCALE) / totalWeightScaled);\n\n this.dropRateCacheScaled.set(name, rateScaled);\n return this.fromScaled(rateScaled);\n }\n }\n\n throw new Error(`Item \"${name}\" not found`);\n }\n\n getCumulativeProbabilityForItem(name: string, rolls: number): number {\n const rate = this.getItemDropRate(name);\n if (rate === 0) return 0;\n if (rate >= 1) return 1;\n\n const cumulativeFailProbability = Math.pow(1 - rate, rolls);\n return 1 - cumulativeFailProbability;\n }\n\n getRollsForTargetProbability(name: string, targetProbability: number): number {\n if (targetProbability <= 0) return 0;\n if (targetProbability >= 1) return 1;\n\n const rate = this.getItemDropRate(name);\n if (rate <= 0) return Infinity;\n return Math.ceil(Math.log(1 - targetProbability) / Math.log(1 - rate));\n }\n\n getRateUpItems(): string[] {\n if (this.mode === 'weighted') {\n return this.pools.flatMap(p => p.items.filter(i => i.rateUp).map(i => i.name));\n } else {\n if (this.pools.length > 0) {\n return this.pools.flatMap(p => p.items.filter(i => i.rateUp).map(i => i.name));\n }\n return [];\n }\n}\n\n\n getAllItemDropRates(): { name: string; dropRate: number; rarity: string }[] {\n if (this.mode === 'flatRate') {\n return Array.from(this.flatRateMap.entries()).map(([name, dropRate]) => ({\n name,\n dropRate,\n rarity: 'flatRate',\n }));\n }\n\n return this.pools.flatMap(p =>\n p.items.map(i => ({\n name: i.name,\n dropRate: this.getItemDropRate(i.name),\n rarity: p.rarity,\n }))\n );\n }\n\n roll(count: number = 1): string[] {\n const results: string[] = [];\n for (let i = 0; i < count; i++) {\n if (this.mode === 'flatRate') {\n const rand = Math.random();\n let cumulative = 0;\n for (const [name, rate] of this.flatRateMap.entries()) {\n cumulative += rate;\n if (rand < cumulative) {\n results.push(name);\n break;\n }\n }\n } else {\n const rarity = this.selectRarity();\n const pool = this.pools.find(p => p.rarity === rarity)!;\n const item = this.selectItemFromPool(pool);\n results.push(item.name);\n }\n }\n return results;\n }\n\n private selectRarity(): string {\n const rand = Math.floor(Math.random() * GachaEngine.SCALE);\n let cumulative = 0;\n\n for (const [rarity, scaledRate] of Object.entries(this.rarityRatesScaled)) {\n cumulative += scaledRate;\n if (rand < cumulative) return rarity;\n }\n\n return Object.keys(this.rarityRatesScaled)[0];\n }\n\n private selectItemFromPool(pool: RarityInput): { name: string; weight: number } {\n const items = pool.items.filter(i => i.weight > 0);\n const scaledItems = items.map(i => ({\n ...i,\n scaledWeight: this.toScaled(i.weight),\n }));\n\n const totalScaledWeight = scaledItems.reduce((sum, i) => sum + i.scaledWeight, 0);\n const rand = Math.floor(Math.random() * totalScaledWeight);\n let cumulative = 0;\n\n for (const item of scaledItems) {\n cumulative += item.scaledWeight;\n if (rand < cumulative) {\n return { name: item.name, weight: item.weight };\n }\n }\n\n return items[0]; // Fallback\n }\n\n getDebugInfo(): {\n scale: number;\n rarityRatesScaled: Record<string, number>;\n rarityRatesFloat: Record<string, number>;\n } {\n const rarityRatesFloat: Record<string, number> = {};\n for (const [rarity, scaledRate] of Object.entries(this.rarityRatesScaled)) {\n rarityRatesFloat[rarity] = this.fromScaled(scaledRate);\n }\n\n return {\n scale: GachaEngine.SCALE,\n rarityRatesScaled: { ...this.rarityRatesScaled },\n rarityRatesFloat,\n };\n }\n}\n"],"names":["GachaEngine","config","this","mode","pools","rarityRatesScaled","flatRateMap","Map","dropRateCacheScaled","weightedConfig","scaleRarityRates","rarityRates","validateConfig","Error","_step","_iterator","_createForOfIteratorHelperLoose","done","_step2","_iterator2","value","items","item","weight","name","set","total","Array","from","values","reduce","sum","v","Math","abs","_proto","prototype","scaled","_i","_Object$entries","Object","entries","length","_Object$entries$_i","rarity","rate","toScaled","probability","MAX_SAFE_SCALE","SCALE","round","fromScaled","scaledInt","originalRates","configuredRarities","Set","keys","usedRarities","map","p","missing","filter","r","has","join","totalRate","_iterator3","_step3","pool","i","_iterator4","_step4","some","getItemDropRate","get","_iterator5","_step5","find","totalPoolWeight","baseRarityRateScaled","itemWeightScaled","totalWeightScaled","numeratorScaled","rateScaled","getCumulativeProbabilityForItem","rolls","pow","getRollsForTargetProbability","targetProbability","Infinity","ceil","log","getRateUpItems","flatMap","rateUp","getAllItemDropRates","_this","_ref","dropRate","roll","count","_this2","results","_loop","_step6","rand","random","cumulative","_iterator6","_step6$value","push","selectRarity","selectItemFromPool","floor","_i2","_Object$entries2","_Object$entries2$_i","_this3","_step7","scaledItems","_extends","scaledWeight","totalScaledWeight","_iterator7","getDebugInfo","rarityRatesFloat","_i3","_Object$entries3","_Object$entries3$_i","scale","Number","MAX_SAFE_INTEGER"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.module.js","sources":["../src/gacha-engine.ts"],"sourcesContent":["import {\n RarityInput,\n GachaEngineConfig,\n WeightedGachaEngineConfig,\n FlatRateGachaEngineConfig,\n} from './types';\n\nexport class GachaEngine {\n private static readonly SCALE = 1_000_000;\n private static readonly MAX_SAFE_SCALE = Math.floor(Number.MAX_SAFE_INTEGER / GachaEngine.SCALE);\n\n private mode: 'weighted' | 'flatRate';\n private pools: RarityInput[] = [];\n private rarityRatesScaled: Record<string, number> = {};\n private flatRateMap: Map<string, number> = new Map();\n private dropRateCacheScaled = new Map<string, number>();\n private flatRateRateUpItems: string[] = [];\n\n constructor(config: GachaEngineConfig) {\n this.mode = config.mode;\n\n if (config.mode === 'weighted') {\n const weightedConfig = config as WeightedGachaEngineConfig;\n this.pools = weightedConfig.pools;\n this.rarityRatesScaled = this.scaleRarityRates(weightedConfig.rarityRates);\n this.validateConfig(weightedConfig.rarityRates);\n } else if (config.mode === 'flatRate') {\n const flatConfig = config as FlatRateGachaEngineConfig;\n this.pools = flatConfig.pools; // Keep pools for reference\n\n for (const pool of flatConfig.pools) {\n for (const item of pool.items) {\n if (item.weight < 0) {\n throw new Error(`FlatRate item \"${item.name}\" must have non-negative weight`);\n }\n this.flatRateMap.set(item.name, item.weight); // direct probability\n if (item.rateUp) {\n this.flatRateRateUpItems.push(item.name);\n }\n }\n }\n const total = Array.from(this.flatRateMap.values()).reduce((sum, v) => sum + v, 0);\n if (Math.abs(total - 1.0) > 1e-6) {\n throw new Error(`FlatRate item rates must sum to 1.0, but got ${total}`);\n }\n } else {\n throw new Error(`Unknown gacha mode: ${this.mode}`);\n }\n }\n\n private scaleRarityRates(rarityRates: Record<string, number>): Record<string, number> {\n const scaled: Record<string, number> = {};\n for (const [rarity, rate] of Object.entries(rarityRates)) {\n if (rate < 0 || rate > 1) {\n throw new Error(`Rarity rate for \"${rarity}\" must be between 0 and 1, got ${rate}`);\n }\n scaled[rarity] = this.toScaled(rate);\n }\n return scaled;\n }\n\n private toScaled(probability: number): number {\n if (probability > GachaEngine.MAX_SAFE_SCALE / GachaEngine.SCALE) {\n throw new Error(`Probability ${probability} too large for safe integer arithmetic`);\n }\n return Math.round(probability * GachaEngine.SCALE);\n }\n\n private fromScaled(scaledInt: number): number {\n return scaledInt / GachaEngine.SCALE;\n }\n\n private validateConfig(originalRates: Record<string, number>): void {\n const configuredRarities = new Set(Object.keys(this.rarityRatesScaled));\n const usedRarities = new Set(this.pools.map(p => p.rarity));\n const missing = Array.from(usedRarities).filter(r => !configuredRarities.has(r));\n\n if (missing.length > 0) {\n throw new Error(`Missing rarity rates for: ${missing.join(', ')}`);\n }\n\n const totalRate = Object.values(originalRates).reduce((sum, rate) => sum + rate, 0);\n if (Math.abs(totalRate - 1.0) > 1e-10) {\n throw new Error(`Rarity rates must sum to 1.0, got ${totalRate}`);\n }\n\n for (const pool of this.pools) {\n if (pool.items.length === 0) {\n throw new Error(`Rarity \"${pool.rarity}\" has no items`);\n }\n\n const totalWeight = pool.items.reduce((sum, i) => sum + i.weight, 0);\n if (totalWeight <= 0) {\n throw new Error(`Rarity \"${pool.rarity}\" has zero total weight`);\n }\n\n for (const item of pool.items) {\n if (item.weight < 0) {\n throw new Error(`Item \"${item.name}\" weight must be non-negative, got ${item.weight}`);\n }\n }\n\n if (!pool.items.some(i => i.weight > 0)) {\n throw new Error(`Rarity \"${pool.rarity}\" must have at least one item with positive weight`);\n }\n }\n }\n\n getItemDropRate(name: string): number {\n if (this.mode === 'flatRate') {\n return this.flatRateMap.get(name) || 0;\n }\n\n if (this.dropRateCacheScaled.has(name)) {\n return this.fromScaled(this.dropRateCacheScaled.get(name)!);\n }\n\n for (const pool of this.pools) {\n const item = pool.items.find(i => i.name === name);\n if (item) {\n if (item.weight === 0) {\n this.dropRateCacheScaled.set(name, 0);\n return 0;\n }\n\n const totalPoolWeight = pool.items.reduce((sum, i) => sum + i.weight, 0);\n const baseRarityRateScaled = this.rarityRatesScaled[pool.rarity];\n const itemWeightScaled = this.toScaled(item.weight);\n const totalWeightScaled = this.toScaled(totalPoolWeight);\n const numeratorScaled = Math.round((itemWeightScaled * baseRarityRateScaled) / GachaEngine.SCALE);\n const rateScaled = Math.round((numeratorScaled * GachaEngine.SCALE) / totalWeightScaled);\n\n this.dropRateCacheScaled.set(name, rateScaled);\n return this.fromScaled(rateScaled);\n }\n }\n\n throw new Error(`Item \"${name}\" not found`);\n }\n\n getCumulativeProbabilityForItem(name: string, rolls: number): number {\n const rate = this.getItemDropRate(name);\n if (rate === 0) return 0;\n if (rate >= 1) return 1;\n\n const cumulativeFailProbability = Math.pow(1 - rate, rolls);\n return 1 - cumulativeFailProbability;\n }\n\n getRollsForTargetProbability(name: string, targetProbability: number): number {\n if (targetProbability <= 0) return 0;\n if (targetProbability >= 1) return 1;\n\n const rate = this.getItemDropRate(name);\n if (rate <= 0) return Infinity;\n return Math.ceil(Math.log(1 - targetProbability) / Math.log(1 - rate));\n }\n\n getRateUpItems(): string[] {\n if (this.mode === 'weighted') {\n return this.pools.flatMap(p => p.items.filter(i => i.rateUp).map(i => i.name));\n } else {\n return this.flatRateRateUpItems;\n }\n }\n\n getAllItemDropRates(): { name: string; dropRate: number; rarity: string }[] {\n if (this.mode === 'flatRate') {\n return Array.from(this.flatRateMap.entries()).map(([name, dropRate]) => ({\n name,\n dropRate,\n rarity: 'flatRate',\n }));\n }\n\n return this.pools.flatMap(p =>\n p.items.map(i => ({\n name: i.name,\n dropRate: this.getItemDropRate(i.name),\n rarity: p.rarity,\n }))\n );\n }\n\n roll(count: number = 1): string[] {\n const results: string[] = [];\n for (let i = 0; i < count; i++) {\n if (this.mode === 'flatRate') {\n const rand = Math.random();\n let cumulative = 0;\n for (const [name, rate] of this.flatRateMap.entries()) {\n cumulative += rate;\n if (rand < cumulative) {\n results.push(name);\n break;\n }\n }\n } else {\n const rarity = this.selectRarity();\n const pool = this.pools.find(p => p.rarity === rarity)!;\n const item = this.selectItemFromPool(pool);\n results.push(item.name);\n }\n }\n return results;\n }\n\n private selectRarity(): string {\n const rand = Math.floor(Math.random() * GachaEngine.SCALE);\n let cumulative = 0;\n\n for (const [rarity, scaledRate] of Object.entries(this.rarityRatesScaled)) {\n cumulative += scaledRate;\n if (rand < cumulative) return rarity;\n }\n\n return Object.keys(this.rarityRatesScaled)[0];\n }\n\n private selectItemFromPool(pool: RarityInput): { name: string; weight: number } {\n const items = pool.items.filter(i => i.weight > 0);\n const scaledItems = items.map(i => ({\n ...i,\n scaledWeight: this.toScaled(i.weight),\n }));\n\n const totalScaledWeight = scaledItems.reduce((sum, i) => sum + i.scaledWeight, 0);\n const rand = Math.floor(Math.random() * totalScaledWeight);\n let cumulative = 0;\n\n for (const item of scaledItems) {\n cumulative += item.scaledWeight;\n if (rand < cumulative) {\n return { name: item.name, weight: item.weight };\n }\n }\n\n return items[0]; // Fallback\n }\n\n getDebugInfo(): {\n scale: number;\n rarityRatesScaled: Record<string, number>;\n rarityRatesFloat: Record<string, number>;\n } {\n const rarityRatesFloat: Record<string, number> = {};\n for (const [rarity, scaledRate] of Object.entries(this.rarityRatesScaled)) {\n rarityRatesFloat[rarity] = this.fromScaled(scaledRate);\n }\n\n return {\n scale: GachaEngine.SCALE,\n rarityRatesScaled: { ...this.rarityRatesScaled },\n rarityRatesFloat,\n };\n }\n}\n"],"names":["GachaEngine","config","this","mode","pools","rarityRatesScaled","flatRateMap","Map","dropRateCacheScaled","flatRateRateUpItems","weightedConfig","scaleRarityRates","rarityRates","validateConfig","Error","flatConfig","_iterator","_step","_createForOfIteratorHelperLoose","done","_step2","_iterator2","value","items","item","weight","name","set","rateUp","push","total","Array","from","values","reduce","sum","v","Math","abs","_proto","prototype","scaled","_i","_Object$entries","Object","entries","length","_Object$entries$_i","rarity","rate","toScaled","probability","MAX_SAFE_SCALE","SCALE","round","fromScaled","scaledInt","originalRates","configuredRarities","Set","keys","usedRarities","map","p","missing","filter","r","has","join","totalRate","_step3","_iterator3","pool","i","_iterator4","_step4","some","getItemDropRate","get","_iterator5","_step5","find","totalPoolWeight","baseRarityRateScaled","itemWeightScaled","totalWeightScaled","numeratorScaled","rateScaled","getCumulativeProbabilityForItem","rolls","pow","getRollsForTargetProbability","targetProbability","Infinity","ceil","log","getRateUpItems","flatMap","getAllItemDropRates","_this","_ref","dropRate","roll","count","_this2","results","_loop","_step6","rand","random","cumulative","_iterator6","_step6$value","selectRarity","selectItemFromPool","floor","_i2","_Object$entries2","_Object$entries2$_i","_this3","_step7","scaledItems","_extends","scaledWeight","totalScaledWeight","_iterator7","getDebugInfo","rarityRatesFloat","_i3","_Object$entries3","_Object$entries3$_i","scale","Number","MAX_SAFE_INTEGER"],"mappings":"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"}
|
package/dist/index.umd.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t||self).AllemandiGachaEngine={})}(this,function(t){function e(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,a=Array(e);r<e;r++)a[r]=t[r];return a}function r(t,r){var a="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(a)return(a=a.call(t)).next.bind(a);if(Array.isArray(t)||(a=function(t,r){if(t){if("string"==typeof t)return e(t,r);var a={}.toString.call(t).slice(8,-1);return"Object"===a&&t.constructor&&(a=t.constructor.name),"Map"===a||"Set"===a?Array.from(t):"Arguments"===a||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(a)?e(t,r):void 0}}(t))||r&&t&&"number"==typeof t.length){a&&(t=a);var n=0;return function(){return n>=t.length?{done:!0}:{done:!1,value:t[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function a(){return a=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var a in r)({}).hasOwnProperty.call(r,a)&&(t[a]=r[a])}return t},a.apply(null,arguments)}var n,i=/*#__PURE__*/function(){function t(t){if(this.mode=void 0,this.pools=[],this.rarityRatesScaled={},this.flatRateMap=new Map,this.dropRateCacheScaled=new Map,this.mode=t.mode,"weighted"===t.mode){var e=t;this.pools=e.pools,this.rarityRatesScaled=this.scaleRarityRates(e.rarityRates),this.validateConfig(e.rarityRates)}else{if("flatRate"!==t.mode)throw new Error("Unknown gacha mode: "+this.mode);for(var
|
|
1
|
+
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t||self).AllemandiGachaEngine={})}(this,function(t){function e(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,a=Array(e);r<e;r++)a[r]=t[r];return a}function r(t,r){var a="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(a)return(a=a.call(t)).next.bind(a);if(Array.isArray(t)||(a=function(t,r){if(t){if("string"==typeof t)return e(t,r);var a={}.toString.call(t).slice(8,-1);return"Object"===a&&t.constructor&&(a=t.constructor.name),"Map"===a||"Set"===a?Array.from(t):"Arguments"===a||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(a)?e(t,r):void 0}}(t))||r&&t&&"number"==typeof t.length){a&&(t=a);var n=0;return function(){return n>=t.length?{done:!0}:{done:!1,value:t[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function a(){return a=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var a in r)({}).hasOwnProperty.call(r,a)&&(t[a]=r[a])}return t},a.apply(null,arguments)}var n,i=/*#__PURE__*/function(){function t(t){if(this.mode=void 0,this.pools=[],this.rarityRatesScaled={},this.flatRateMap=new Map,this.dropRateCacheScaled=new Map,this.flatRateRateUpItems=[],this.mode=t.mode,"weighted"===t.mode){var e=t;this.pools=e.pools,this.rarityRatesScaled=this.scaleRarityRates(e.rarityRates),this.validateConfig(e.rarityRates)}else{if("flatRate"!==t.mode)throw new Error("Unknown gacha mode: "+this.mode);var a=t;this.pools=a.pools;for(var n,i=r(a.pools);!(n=i()).done;)for(var o,s=r(n.value.items);!(o=s()).done;){var l=o.value;if(l.weight<0)throw new Error('FlatRate item "'+l.name+'" must have non-negative weight');this.flatRateMap.set(l.name,l.weight),l.rateUp&&this.flatRateRateUpItems.push(l.name)}var f=Array.from(this.flatRateMap.values()).reduce(function(t,e){return t+e},0);if(Math.abs(f-1)>1e-6)throw new Error("FlatRate item rates must sum to 1.0, but got "+f)}}var e=t.prototype;return e.scaleRarityRates=function(t){for(var e={},r=0,a=Object.entries(t);r<a.length;r++){var n=a[r],i=n[0],o=n[1];if(o<0||o>1)throw new Error('Rarity rate for "'+i+'" must be between 0 and 1, got '+o);e[i]=this.toScaled(o)}return e},e.toScaled=function(e){if(e>t.MAX_SAFE_SCALE/t.SCALE)throw new Error("Probability "+e+" too large for safe integer arithmetic");return Math.round(e*t.SCALE)},e.fromScaled=function(e){return e/t.SCALE},e.validateConfig=function(t){var e=new Set(Object.keys(this.rarityRatesScaled)),a=new Set(this.pools.map(function(t){return t.rarity})),n=Array.from(a).filter(function(t){return!e.has(t)});if(n.length>0)throw new Error("Missing rarity rates for: "+n.join(", "));var i=Object.values(t).reduce(function(t,e){return t+e},0);if(Math.abs(i-1)>1e-10)throw new Error("Rarity rates must sum to 1.0, got "+i);for(var o,s=r(this.pools);!(o=s()).done;){var l=o.value;if(0===l.items.length)throw new Error('Rarity "'+l.rarity+'" has no items');if(l.items.reduce(function(t,e){return t+e.weight},0)<=0)throw new Error('Rarity "'+l.rarity+'" has zero total weight');for(var f,u=r(l.items);!(f=u()).done;){var h=f.value;if(h.weight<0)throw new Error('Item "'+h.name+'" weight must be non-negative, got '+h.weight)}if(!l.items.some(function(t){return t.weight>0}))throw new Error('Rarity "'+l.rarity+'" must have at least one item with positive weight')}},e.getItemDropRate=function(e){if("flatRate"===this.mode)return this.flatRateMap.get(e)||0;if(this.dropRateCacheScaled.has(e))return this.fromScaled(this.dropRateCacheScaled.get(e));for(var a,n=r(this.pools);!(a=n()).done;){var i=a.value,o=i.items.find(function(t){return t.name===e});if(o){if(0===o.weight)return this.dropRateCacheScaled.set(e,0),0;var s=i.items.reduce(function(t,e){return t+e.weight},0),l=this.rarityRatesScaled[i.rarity],f=this.toScaled(o.weight),u=this.toScaled(s),h=Math.round(f*l/t.SCALE),c=Math.round(h*t.SCALE/u);return this.dropRateCacheScaled.set(e,c),this.fromScaled(c)}}throw new Error('Item "'+e+'" not found')},e.getCumulativeProbabilityForItem=function(t,e){var r=this.getItemDropRate(t);return 0===r?0:r>=1?1:1-Math.pow(1-r,e)},e.getRollsForTargetProbability=function(t,e){if(e<=0)return 0;if(e>=1)return 1;var r=this.getItemDropRate(t);return r<=0?Infinity:Math.ceil(Math.log(1-e)/Math.log(1-r))},e.getRateUpItems=function(){return"weighted"===this.mode?this.pools.flatMap(function(t){return t.items.filter(function(t){return t.rateUp}).map(function(t){return t.name})}):this.flatRateRateUpItems},e.getAllItemDropRates=function(){var t=this;return"flatRate"===this.mode?Array.from(this.flatRateMap.entries()).map(function(t){return{name:t[0],dropRate:t[1],rarity:"flatRate"}}):this.pools.flatMap(function(e){return e.items.map(function(r){return{name:r.name,dropRate:t.getItemDropRate(r.name),rarity:e.rarity}})})},e.roll=function(t){var e=this;void 0===t&&(t=1);for(var a=[],n=function(){if("flatRate"===e.mode)for(var t,n=Math.random(),i=0,o=r(e.flatRateMap.entries());!(t=o()).done;){var s=t.value;if(n<(i+=s[1])){a.push(s[0]);break}}else{var l=e.selectRarity(),f=e.pools.find(function(t){return t.rarity===l}),u=e.selectItemFromPool(f);a.push(u.name)}},i=0;i<t;i++)n();return a},e.selectRarity=function(){for(var e=Math.floor(Math.random()*t.SCALE),r=0,a=0,n=Object.entries(this.rarityRatesScaled);a<n.length;a++){var i=n[a];if(e<(r+=i[1]))return i[0]}return Object.keys(this.rarityRatesScaled)[0]},e.selectItemFromPool=function(t){for(var e,n=this,i=t.items.filter(function(t){return t.weight>0}),o=i.map(function(t){return a({},t,{scaledWeight:n.toScaled(t.weight)})}),s=o.reduce(function(t,e){return t+e.scaledWeight},0),l=Math.floor(Math.random()*s),f=0,u=r(o);!(e=u()).done;){var h=e.value;if(l<(f+=h.scaledWeight))return{name:h.name,weight:h.weight}}return i[0]},e.getDebugInfo=function(){for(var e={},r=0,n=Object.entries(this.rarityRatesScaled);r<n.length;r++){var i=n[r];e[i[0]]=this.fromScaled(i[1])}return{scale:t.SCALE,rarityRatesScaled:a({},this.rarityRatesScaled),rarityRatesFloat:e}},t}();n=i,i.SCALE=1e6,i.MAX_SAFE_SCALE=Math.floor(Number.MAX_SAFE_INTEGER/n.SCALE),t.GachaEngine=i});
|
|
2
2
|
//# sourceMappingURL=index.umd.js.map
|
package/dist/index.umd.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.umd.js","sources":["../src/gacha-engine.ts"],"sourcesContent":["import {\n RarityInput,\n GachaEngineConfig,\n WeightedGachaEngineConfig,\n FlatRateGachaEngineConfig,\n} from './types';\n\nexport class GachaEngine {\n private static readonly SCALE = 1_000_000;\n private static readonly MAX_SAFE_SCALE = Math.floor(Number.MAX_SAFE_INTEGER / GachaEngine.SCALE);\n\n private mode: 'weighted' | 'flatRate';\n private pools: RarityInput[] = [];\n private rarityRatesScaled: Record<string, number> = {};\n private flatRateMap: Map<string, number> = new Map();\n private dropRateCacheScaled = new Map<string, number>();\n\n constructor(config: GachaEngineConfig) {\n this.mode = config.mode;\n\n if (config.mode === 'weighted') {\n const weightedConfig = config as WeightedGachaEngineConfig;\n this.pools = weightedConfig.pools;\n this.rarityRatesScaled = this.scaleRarityRates(weightedConfig.rarityRates);\n this.validateConfig(weightedConfig.rarityRates);\n } else if (config.mode === 'flatRate') {\n const flatConfig = config as FlatRateGachaEngineConfig;\n for (const pool of flatConfig.pools) {\n for (const item of pool.items) {\n if (item.weight < 0) {\n throw new Error(`FlatRate item \"${item.name}\" must have non-negative weight`);\n }\n this.flatRateMap.set(item.name, item.weight); // Here, interpreted as direct probability\n }\n }\n const total = Array.from(this.flatRateMap.values()).reduce((sum, v) => sum + v, 0);\n if (Math.abs(total - 1.0) > 1e-6) {\n throw new Error(`FlatRate item rates must sum to 1.0, but got ${total}`);\n }\n } else {\n throw new Error(`Unknown gacha mode: ${this.mode}`);\n }\n }\n\n private scaleRarityRates(rarityRates: Record<string, number>): Record<string, number> {\n const scaled: Record<string, number> = {};\n for (const [rarity, rate] of Object.entries(rarityRates)) {\n if (rate < 0 || rate > 1) {\n throw new Error(`Rarity rate for \"${rarity}\" must be between 0 and 1, got ${rate}`);\n }\n scaled[rarity] = this.toScaled(rate);\n }\n return scaled;\n }\n\n private toScaled(probability: number): number {\n if (probability > GachaEngine.MAX_SAFE_SCALE / GachaEngine.SCALE) {\n throw new Error(`Probability ${probability} too large for safe integer arithmetic`);\n }\n return Math.round(probability * GachaEngine.SCALE);\n }\n\n private fromScaled(scaledInt: number): number {\n return scaledInt / GachaEngine.SCALE;\n }\n\n private validateConfig(originalRates: Record<string, number>): void {\n const configuredRarities = new Set(Object.keys(this.rarityRatesScaled));\n const usedRarities = new Set(this.pools.map(p => p.rarity));\n const missing = Array.from(usedRarities).filter(r => !configuredRarities.has(r));\n\n if (missing.length > 0) {\n throw new Error(`Missing rarity rates for: ${missing.join(', ')}`);\n }\n\n const totalRate = Object.values(originalRates).reduce((sum, rate) => sum + rate, 0);\n if (Math.abs(totalRate - 1.0) > 1e-10) {\n throw new Error(`Rarity rates must sum to 1.0, got ${totalRate}`);\n }\n\n for (const pool of this.pools) {\n if (pool.items.length === 0) {\n throw new Error(`Rarity \"${pool.rarity}\" has no items`);\n }\n\n const totalWeight = pool.items.reduce((sum, i) => sum + i.weight, 0);\n if (totalWeight <= 0) {\n throw new Error(`Rarity \"${pool.rarity}\" has zero total weight`);\n }\n\n for (const item of pool.items) {\n if (item.weight < 0) {\n throw new Error(`Item \"${item.name}\" weight must be non-negative, got ${item.weight}`);\n }\n }\n\n if (!pool.items.some(i => i.weight > 0)) {\n throw new Error(`Rarity \"${pool.rarity}\" must have at least one item with positive weight`);\n }\n }\n }\n\n getItemDropRate(name: string): number {\n if (this.mode === 'flatRate') {\n return this.flatRateMap.get(name) || 0;\n }\n\n if (this.dropRateCacheScaled.has(name)) {\n return this.fromScaled(this.dropRateCacheScaled.get(name)!);\n }\n\n for (const pool of this.pools) {\n const item = pool.items.find(i => i.name === name);\n if (item) {\n if (item.weight === 0) {\n this.dropRateCacheScaled.set(name, 0);\n return 0;\n }\n\n const totalPoolWeight = pool.items.reduce((sum, i) => sum + i.weight, 0);\n const baseRarityRateScaled = this.rarityRatesScaled[pool.rarity];\n const itemWeightScaled = this.toScaled(item.weight);\n const totalWeightScaled = this.toScaled(totalPoolWeight);\n const numeratorScaled = Math.round((itemWeightScaled * baseRarityRateScaled) / GachaEngine.SCALE);\n const rateScaled = Math.round((numeratorScaled * GachaEngine.SCALE) / totalWeightScaled);\n\n this.dropRateCacheScaled.set(name, rateScaled);\n return this.fromScaled(rateScaled);\n }\n }\n\n throw new Error(`Item \"${name}\" not found`);\n }\n\n getCumulativeProbabilityForItem(name: string, rolls: number): number {\n const rate = this.getItemDropRate(name);\n if (rate === 0) return 0;\n if (rate >= 1) return 1;\n\n const cumulativeFailProbability = Math.pow(1 - rate, rolls);\n return 1 - cumulativeFailProbability;\n }\n\n getRollsForTargetProbability(name: string, targetProbability: number): number {\n if (targetProbability <= 0) return 0;\n if (targetProbability >= 1) return 1;\n\n const rate = this.getItemDropRate(name);\n if (rate <= 0) return Infinity;\n return Math.ceil(Math.log(1 - targetProbability) / Math.log(1 - rate));\n }\n\n getRateUpItems(): string[] {\n if (this.mode === 'weighted') {\n return this.pools.flatMap(p => p.items.filter(i => i.rateUp).map(i => i.name));\n } else {\n if (this.pools.length > 0) {\n return this.pools.flatMap(p => p.items.filter(i => i.rateUp).map(i => i.name));\n }\n return [];\n }\n}\n\n\n getAllItemDropRates(): { name: string; dropRate: number; rarity: string }[] {\n if (this.mode === 'flatRate') {\n return Array.from(this.flatRateMap.entries()).map(([name, dropRate]) => ({\n name,\n dropRate,\n rarity: 'flatRate',\n }));\n }\n\n return this.pools.flatMap(p =>\n p.items.map(i => ({\n name: i.name,\n dropRate: this.getItemDropRate(i.name),\n rarity: p.rarity,\n }))\n );\n }\n\n roll(count: number = 1): string[] {\n const results: string[] = [];\n for (let i = 0; i < count; i++) {\n if (this.mode === 'flatRate') {\n const rand = Math.random();\n let cumulative = 0;\n for (const [name, rate] of this.flatRateMap.entries()) {\n cumulative += rate;\n if (rand < cumulative) {\n results.push(name);\n break;\n }\n }\n } else {\n const rarity = this.selectRarity();\n const pool = this.pools.find(p => p.rarity === rarity)!;\n const item = this.selectItemFromPool(pool);\n results.push(item.name);\n }\n }\n return results;\n }\n\n private selectRarity(): string {\n const rand = Math.floor(Math.random() * GachaEngine.SCALE);\n let cumulative = 0;\n\n for (const [rarity, scaledRate] of Object.entries(this.rarityRatesScaled)) {\n cumulative += scaledRate;\n if (rand < cumulative) return rarity;\n }\n\n return Object.keys(this.rarityRatesScaled)[0];\n }\n\n private selectItemFromPool(pool: RarityInput): { name: string; weight: number } {\n const items = pool.items.filter(i => i.weight > 0);\n const scaledItems = items.map(i => ({\n ...i,\n scaledWeight: this.toScaled(i.weight),\n }));\n\n const totalScaledWeight = scaledItems.reduce((sum, i) => sum + i.scaledWeight, 0);\n const rand = Math.floor(Math.random() * totalScaledWeight);\n let cumulative = 0;\n\n for (const item of scaledItems) {\n cumulative += item.scaledWeight;\n if (rand < cumulative) {\n return { name: item.name, weight: item.weight };\n }\n }\n\n return items[0]; // Fallback\n }\n\n getDebugInfo(): {\n scale: number;\n rarityRatesScaled: Record<string, number>;\n rarityRatesFloat: Record<string, number>;\n } {\n const rarityRatesFloat: Record<string, number> = {};\n for (const [rarity, scaledRate] of Object.entries(this.rarityRatesScaled)) {\n rarityRatesFloat[rarity] = this.fromScaled(scaledRate);\n }\n\n return {\n scale: GachaEngine.SCALE,\n rarityRatesScaled: { ...this.rarityRatesScaled },\n rarityRatesFloat,\n };\n }\n}\n"],"names":["GachaEngine","config","this","mode","pools","rarityRatesScaled","flatRateMap","Map","dropRateCacheScaled","weightedConfig","scaleRarityRates","rarityRates","validateConfig","Error","_step","_iterator","_createForOfIteratorHelperLoose","done","_step2","_iterator2","value","items","item","weight","name","set","total","Array","from","values","reduce","sum","v","Math","abs","_proto","prototype","scaled","_i","_Object$entries","Object","entries","length","_Object$entries$_i","rarity","rate","toScaled","probability","MAX_SAFE_SCALE","SCALE","round","fromScaled","scaledInt","originalRates","configuredRarities","Set","keys","usedRarities","map","p","missing","filter","r","has","join","totalRate","_iterator3","_step3","pool","i","_iterator4","_step4","some","getItemDropRate","get","_iterator5","_step5","find","totalPoolWeight","baseRarityRateScaled","itemWeightScaled","totalWeightScaled","numeratorScaled","rateScaled","getCumulativeProbabilityForItem","rolls","pow","getRollsForTargetProbability","targetProbability","Infinity","ceil","log","getRateUpItems","flatMap","rateUp","getAllItemDropRates","_this","_ref","dropRate","roll","count","_this2","results","_loop","_step6","rand","random","cumulative","_iterator6","_step6$value","push","selectRarity","selectItemFromPool","floor","_i2","_Object$entries2","_Object$entries2$_i","_this3","_step7","scaledItems","_extends","scaledWeight","totalScaledWeight","_iterator7","getDebugInfo","rarityRatesFloat","_i3","_Object$entries3","_Object$entries3$_i","scale","Number","MAX_SAFE_INTEGER"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.umd.js","sources":["../src/gacha-engine.ts"],"sourcesContent":["import {\n RarityInput,\n GachaEngineConfig,\n WeightedGachaEngineConfig,\n FlatRateGachaEngineConfig,\n} from './types';\n\nexport class GachaEngine {\n private static readonly SCALE = 1_000_000;\n private static readonly MAX_SAFE_SCALE = Math.floor(Number.MAX_SAFE_INTEGER / GachaEngine.SCALE);\n\n private mode: 'weighted' | 'flatRate';\n private pools: RarityInput[] = [];\n private rarityRatesScaled: Record<string, number> = {};\n private flatRateMap: Map<string, number> = new Map();\n private dropRateCacheScaled = new Map<string, number>();\n private flatRateRateUpItems: string[] = [];\n\n constructor(config: GachaEngineConfig) {\n this.mode = config.mode;\n\n if (config.mode === 'weighted') {\n const weightedConfig = config as WeightedGachaEngineConfig;\n this.pools = weightedConfig.pools;\n this.rarityRatesScaled = this.scaleRarityRates(weightedConfig.rarityRates);\n this.validateConfig(weightedConfig.rarityRates);\n } else if (config.mode === 'flatRate') {\n const flatConfig = config as FlatRateGachaEngineConfig;\n this.pools = flatConfig.pools; // Keep pools for reference\n\n for (const pool of flatConfig.pools) {\n for (const item of pool.items) {\n if (item.weight < 0) {\n throw new Error(`FlatRate item \"${item.name}\" must have non-negative weight`);\n }\n this.flatRateMap.set(item.name, item.weight); // direct probability\n if (item.rateUp) {\n this.flatRateRateUpItems.push(item.name);\n }\n }\n }\n const total = Array.from(this.flatRateMap.values()).reduce((sum, v) => sum + v, 0);\n if (Math.abs(total - 1.0) > 1e-6) {\n throw new Error(`FlatRate item rates must sum to 1.0, but got ${total}`);\n }\n } else {\n throw new Error(`Unknown gacha mode: ${this.mode}`);\n }\n }\n\n private scaleRarityRates(rarityRates: Record<string, number>): Record<string, number> {\n const scaled: Record<string, number> = {};\n for (const [rarity, rate] of Object.entries(rarityRates)) {\n if (rate < 0 || rate > 1) {\n throw new Error(`Rarity rate for \"${rarity}\" must be between 0 and 1, got ${rate}`);\n }\n scaled[rarity] = this.toScaled(rate);\n }\n return scaled;\n }\n\n private toScaled(probability: number): number {\n if (probability > GachaEngine.MAX_SAFE_SCALE / GachaEngine.SCALE) {\n throw new Error(`Probability ${probability} too large for safe integer arithmetic`);\n }\n return Math.round(probability * GachaEngine.SCALE);\n }\n\n private fromScaled(scaledInt: number): number {\n return scaledInt / GachaEngine.SCALE;\n }\n\n private validateConfig(originalRates: Record<string, number>): void {\n const configuredRarities = new Set(Object.keys(this.rarityRatesScaled));\n const usedRarities = new Set(this.pools.map(p => p.rarity));\n const missing = Array.from(usedRarities).filter(r => !configuredRarities.has(r));\n\n if (missing.length > 0) {\n throw new Error(`Missing rarity rates for: ${missing.join(', ')}`);\n }\n\n const totalRate = Object.values(originalRates).reduce((sum, rate) => sum + rate, 0);\n if (Math.abs(totalRate - 1.0) > 1e-10) {\n throw new Error(`Rarity rates must sum to 1.0, got ${totalRate}`);\n }\n\n for (const pool of this.pools) {\n if (pool.items.length === 0) {\n throw new Error(`Rarity \"${pool.rarity}\" has no items`);\n }\n\n const totalWeight = pool.items.reduce((sum, i) => sum + i.weight, 0);\n if (totalWeight <= 0) {\n throw new Error(`Rarity \"${pool.rarity}\" has zero total weight`);\n }\n\n for (const item of pool.items) {\n if (item.weight < 0) {\n throw new Error(`Item \"${item.name}\" weight must be non-negative, got ${item.weight}`);\n }\n }\n\n if (!pool.items.some(i => i.weight > 0)) {\n throw new Error(`Rarity \"${pool.rarity}\" must have at least one item with positive weight`);\n }\n }\n }\n\n getItemDropRate(name: string): number {\n if (this.mode === 'flatRate') {\n return this.flatRateMap.get(name) || 0;\n }\n\n if (this.dropRateCacheScaled.has(name)) {\n return this.fromScaled(this.dropRateCacheScaled.get(name)!);\n }\n\n for (const pool of this.pools) {\n const item = pool.items.find(i => i.name === name);\n if (item) {\n if (item.weight === 0) {\n this.dropRateCacheScaled.set(name, 0);\n return 0;\n }\n\n const totalPoolWeight = pool.items.reduce((sum, i) => sum + i.weight, 0);\n const baseRarityRateScaled = this.rarityRatesScaled[pool.rarity];\n const itemWeightScaled = this.toScaled(item.weight);\n const totalWeightScaled = this.toScaled(totalPoolWeight);\n const numeratorScaled = Math.round((itemWeightScaled * baseRarityRateScaled) / GachaEngine.SCALE);\n const rateScaled = Math.round((numeratorScaled * GachaEngine.SCALE) / totalWeightScaled);\n\n this.dropRateCacheScaled.set(name, rateScaled);\n return this.fromScaled(rateScaled);\n }\n }\n\n throw new Error(`Item \"${name}\" not found`);\n }\n\n getCumulativeProbabilityForItem(name: string, rolls: number): number {\n const rate = this.getItemDropRate(name);\n if (rate === 0) return 0;\n if (rate >= 1) return 1;\n\n const cumulativeFailProbability = Math.pow(1 - rate, rolls);\n return 1 - cumulativeFailProbability;\n }\n\n getRollsForTargetProbability(name: string, targetProbability: number): number {\n if (targetProbability <= 0) return 0;\n if (targetProbability >= 1) return 1;\n\n const rate = this.getItemDropRate(name);\n if (rate <= 0) return Infinity;\n return Math.ceil(Math.log(1 - targetProbability) / Math.log(1 - rate));\n }\n\n getRateUpItems(): string[] {\n if (this.mode === 'weighted') {\n return this.pools.flatMap(p => p.items.filter(i => i.rateUp).map(i => i.name));\n } else {\n return this.flatRateRateUpItems;\n }\n }\n\n getAllItemDropRates(): { name: string; dropRate: number; rarity: string }[] {\n if (this.mode === 'flatRate') {\n return Array.from(this.flatRateMap.entries()).map(([name, dropRate]) => ({\n name,\n dropRate,\n rarity: 'flatRate',\n }));\n }\n\n return this.pools.flatMap(p =>\n p.items.map(i => ({\n name: i.name,\n dropRate: this.getItemDropRate(i.name),\n rarity: p.rarity,\n }))\n );\n }\n\n roll(count: number = 1): string[] {\n const results: string[] = [];\n for (let i = 0; i < count; i++) {\n if (this.mode === 'flatRate') {\n const rand = Math.random();\n let cumulative = 0;\n for (const [name, rate] of this.flatRateMap.entries()) {\n cumulative += rate;\n if (rand < cumulative) {\n results.push(name);\n break;\n }\n }\n } else {\n const rarity = this.selectRarity();\n const pool = this.pools.find(p => p.rarity === rarity)!;\n const item = this.selectItemFromPool(pool);\n results.push(item.name);\n }\n }\n return results;\n }\n\n private selectRarity(): string {\n const rand = Math.floor(Math.random() * GachaEngine.SCALE);\n let cumulative = 0;\n\n for (const [rarity, scaledRate] of Object.entries(this.rarityRatesScaled)) {\n cumulative += scaledRate;\n if (rand < cumulative) return rarity;\n }\n\n return Object.keys(this.rarityRatesScaled)[0];\n }\n\n private selectItemFromPool(pool: RarityInput): { name: string; weight: number } {\n const items = pool.items.filter(i => i.weight > 0);\n const scaledItems = items.map(i => ({\n ...i,\n scaledWeight: this.toScaled(i.weight),\n }));\n\n const totalScaledWeight = scaledItems.reduce((sum, i) => sum + i.scaledWeight, 0);\n const rand = Math.floor(Math.random() * totalScaledWeight);\n let cumulative = 0;\n\n for (const item of scaledItems) {\n cumulative += item.scaledWeight;\n if (rand < cumulative) {\n return { name: item.name, weight: item.weight };\n }\n }\n\n return items[0]; // Fallback\n }\n\n getDebugInfo(): {\n scale: number;\n rarityRatesScaled: Record<string, number>;\n rarityRatesFloat: Record<string, number>;\n } {\n const rarityRatesFloat: Record<string, number> = {};\n for (const [rarity, scaledRate] of Object.entries(this.rarityRatesScaled)) {\n rarityRatesFloat[rarity] = this.fromScaled(scaledRate);\n }\n\n return {\n scale: GachaEngine.SCALE,\n rarityRatesScaled: { ...this.rarityRatesScaled },\n rarityRatesFloat,\n };\n }\n}\n"],"names":["GachaEngine","config","this","mode","pools","rarityRatesScaled","flatRateMap","Map","dropRateCacheScaled","flatRateRateUpItems","weightedConfig","scaleRarityRates","rarityRates","validateConfig","Error","flatConfig","_iterator","_step","_createForOfIteratorHelperLoose","done","_step2","_iterator2","value","items","item","weight","name","set","rateUp","push","total","Array","from","values","reduce","sum","v","Math","abs","_proto","prototype","scaled","_i","_Object$entries","Object","entries","length","_Object$entries$_i","rarity","rate","toScaled","probability","MAX_SAFE_SCALE","SCALE","round","fromScaled","scaledInt","originalRates","configuredRarities","Set","keys","usedRarities","map","p","missing","filter","r","has","join","totalRate","_step3","_iterator3","pool","i","_iterator4","_step4","some","getItemDropRate","get","_iterator5","_step5","find","totalPoolWeight","baseRarityRateScaled","itemWeightScaled","totalWeightScaled","numeratorScaled","rateScaled","getCumulativeProbabilityForItem","rolls","pow","getRollsForTargetProbability","targetProbability","Infinity","ceil","log","getRateUpItems","flatMap","getAllItemDropRates","_this","_ref","dropRate","roll","count","_this2","results","_loop","_step6","rand","random","cumulative","_iterator6","_step6$value","selectRarity","selectItemFromPool","floor","_i2","_Object$entries2","_Object$entries2$_i","_this3","_step7","scaledItems","_extends","scaledWeight","totalScaledWeight","_iterator7","getDebugInfo","rarityRatesFloat","_i3","_Object$entries3","_Object$entries3$_i","scale","Number","MAX_SAFE_INTEGER"],"mappings":"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"}
|
package/package.json
CHANGED