Last active
February 6, 2019 09:48
-
-
Save Sheep-y/fc822d26fb47828599dce47accf99906 to your computer and use it in GitHub Desktop.
Puella Magi Magia Record Pickup Chance Calculator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* For Puella Magi Magia Record. Developed with node.js. | |
Calculate the odds of getting 1 to 4 pickup character (4 stars magi) from a pickup card pool. | |
A random 4 stars magi is guarenteed after 99 misses, which is reset if you get one early. | |
Excel file with chart is available at https://drive.google.com/open?id=1GSJMw-lOM1u7DMVT-Gi_lsxgJS4kLfE_ | |
Example output at 60% pickup: | |
Draw @ Percentile of 4 pickups | |
236 @ 10.023 | |
308 @ 25.24 | |
400 @ 50.035 | |
514 @ 75.007 | |
638 @ 90.046 | |
This means 10% players should get 4 pickups at 236 draws, 25% at 308 draws, 50% at 400 draws etc. */ | |
// Drop = 4 stars magi drop per card (1%), pick = chance of dropping a wanted pickup (60%*drop). | |
const drop = 0.01, pick = 0.6 * drop, reset = drop - pick, miss = 1 - drop, maxSlot = 4, draw = 5000; | |
const ary = (h,w) => new Array( h ).fill().map( _ => new Float64Array( w ) ), adder = (p,v) => p + v; | |
const world = ary( maxSlot, 100 ), sum = ary( maxSlot, draw ); | |
world[0][0] = 100; // Starts at 0 slot 0 draw = 100% | |
world[maxSlot] = new Float64Array( 1 ); // Final slot need not care or calculate accumulated draw. | |
for ( let i = 0 ; i < draw ; i++ ) { | |
for ( let slot = sum.length-1 ; slot >= 0 ; slot-- ) { // Draw a card! | |
const row = world[slot], nextRow = world[ slot+1 ]; | |
let zero = row[99] * reset / drop; // Guaranteed card is not pickup. T-T | |
nextRow[0] += row[99] * pick / drop; // Guaranteed card is pickup! ^o^ | |
for ( let accu = 99 ; accu > 0 ; accu-- ) { | |
const chance = row[ accu-1 ]; | |
nextRow[0] += chance * pick; // Pickup get! *v* | |
zero += chance * reset; // Hit but not pickup >_< | |
row[accu] = chance * miss; // Nothing. o_o | |
} | |
row[0] = zero; | |
} | |
let check = sum[ maxSlot-1 ][i] = world[ maxSlot ][0]; // Consolidate chances. | |
for ( let slot = maxSlot-1 ; slot > 0 ; slot-- ) | |
sum[ slot-1 ][i] = check += world[slot].reduce( adder ); | |
check += world[0].reduce( adder ); // Add zero slot chances. | |
if ( check <= 99.999 || check >= 100.001 ) // Then check that chances add up to 100%. | |
return console.error( `Error: Sum of chance is ${check} after draw ${i}. Expected 100.` ); | |
} | |
console.log( `Card chance ${pick+reset}, Pickup chance ${pick/(pick+reset)}, Chances at ${draw} draws` ); | |
//console.log( 'Chance check' ); // For debug. Shows heads and tails of the slot x miss chance matrix. | |
//for ( let slot = maxSlot-1 ; slot >= 0 ; slot-- ) | |
// console.log( `${world[slot][0]} ${world[slot][1]} ... ${world[slot][98]} ${world[slot][99]}` ); | |
for ( let slot = 0 ; slot < maxSlot ; slot++ ) { | |
console.log( `\nDraw @ Percentile of ${slot+1} pickups` ); | |
let step = 5, gateway = step, row = sum[slot], mean = 0; | |
for ( let i = 0 ; i < draw ; i++ ) { | |
if ( row[i] < gateway ) continue; | |
console.log( ` ${i+1}`.substr( -4 ) + ` @ ${Math.round(row[i]*1000)/1000}` ); | |
gateway += step; | |
if ( gateway === 100 ) break; | |
i--; // Retry current i until row[i] < gateway. | |
} | |
for ( let i = 1 ; i < draw ; ) // Sum up mean draw | |
mean += ( row[i] - row[i-1] ) * ++i; | |
console.log( ` ${Math.round(mean/100)}`.substr( -4 ) + ' = Mean' ); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment