Skip to content

Instantly share code, notes, and snippets.

@Sheep-y
Last active February 6, 2019 09:48
Show Gist options
  • Save Sheep-y/fc822d26fb47828599dce47accf99906 to your computer and use it in GitHub Desktop.
Save Sheep-y/fc822d26fb47828599dce47accf99906 to your computer and use it in GitHub Desktop.
Puella Magi Magia Record Pickup Chance Calculator
/* 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