( () => { var curves; const CANDY_SIZES = [ 'XS', 'S', 'M', 'L', 'XL' ]; const SIZE_TITLES = [ 'Extra Small', 'Small', 'Medium', 'Large', 'Extra Large' ]; const calcExpToLv = ( curve, n ) => ( n <= 1 ) ? 0 : curves[ curve ]( n ); const clamp = ( num, lb, ub ) => Math.max( lb, Math.min( num, ub ) ); const fmtNum = ( num ) => num.toString().replace( /\B(?=(\d{3})+(?!\d))/g, ',' ); const toCamel = ( str ) => str.toLowerCase().replace( /\s+([a-z])/g, ( _, chr ) => chr.toUpperCase() ); curves = { fast: function( n ) { return Math.floor( Math.pow( n, 3 ) * 4 / 5 ); }, slow: function( n ) { return Math.floor( Math.pow( n, 3 ) * 5 / 4 ); }, mediumFast: function( n ) { return Math.pow( n, 3 ); }, mediumSlow: function( n ) { return Math.floor( Math.pow( n, 3 ) * 6 / 5 - Math.pow( n, 2 ) * 15 + n * 100 - 140 ); }, erratic: function( n ) { if ( n < 50 ) { return Math.floor( Math.pow( n, 3 ) * ( 100 - n ) / 50 ); } else if ( 50 <= n && n <= 68 ) { return Math.floor( Math.pow( n, 3 ) * ( 150 - n ) / 100 ); } else if ( 68 < n && n < 98 ) { return Math.floor( Math.pow( n, 3 ) * ( 1911 - n * 10 ) / 1500 ); } return Math.floor( Math.pow( n, 3 ) * ( 160 - n ) / 100 ); }, fluctuating: function( n ) { if ( n < 15 ) { return Math.floor( Math.pow( n, 3 ) * ( 73 + n ) / 150 ); } else if ( 15 <= n && n < 36 ) { return Math.floor( Math.pow( n, 3 ) * ( 14 + n ) / 50 ); } return Math.floor( Math.pow( n, 3 ) * ( 64 + n ) / 100 ); } } function log( mssg = false ) { var $log = $( '#log' ); if ( mssg ) { $log.removeAttr( 'hidden' ) .text( mssg ); } else { $log.attr( 'hidden', '' ); } return $log; } function validate() { var currentLv, targetLv, disable = false; $( 'form [id^=result]' ).each( function() { $( this ).val( '-' ); } ); if ( !( $( '#curve' ).val().length ) ) { disable = 'Fill out the Pokémon species field.'; } else { currentLv = parseInt( $( '#current' ).val() ), targetLv = parseInt( $( '#target' ).val() ); if ( currentLv == targetLv ) { disable = 'Current Level cannot be equal to Target Level.'; } else if ( currentLv > targetLv ) { disable = 'Current Level cannot exceed Target Level.'; } } log( disable ); $( '[type=submit]' ).prop( 'disabled', disable.length > 0 ); } function testTimeout( start ) { var d, now = new Date(); d = ( now.getTime() - start.getTime() ) / 1000; if ( d > 60 ) throw new Error( 'timeout' ); } function optimize( problem ) { var lp, iocp, start, colname, colval, objval; start = new Date(); lp = glp_create_prob(); glp_read_lp_from_string( lp, null, problem ); glp_scale_prob( lp, GLP_SF_AUTO ); iocp = new IOCP( { presolve: GLP_ON } ); glp_intopt( lp, iocp ); try { objval = glp_mip_obj_val( lp ); testTimeout( start ); for( let i = 1; i <= glp_get_num_cols( lp ); i++ ){ colname = glp_get_col_name( lp, i ), colval = glp_mip_col_val( lp, i ); testTimeout( start ); $( '#result-exp-candy-' + colname ).val( colval ); objval -= colval; } return objval; } catch ( err ) { log( 'Timed out looking for a solution.' ); } } $( document ).ready( function() { // read candy MILP problem $.get( 'problem.txt', function( problemTemplate ) { var i, len; // read Pokémon names and experience curves $.getJSON( 'static/pokemon.json', function( pokemonData ) { var slug, slugs; // add each Pokémon to the datalist slugs = Object.keys( pokemonData ); len = slugs.length; for ( i = 0; i < len; i++ ) { slug = slugs[ i ]; $( '