Pokeball Simulator

PYTHON 249 bytes - 75 for bonuses = 174

My first try ever golfing.

import sys,random
y=sys.argv
d,b,f={10:1,1:1.5,15:2,7:1.5,13:255,-2:3.5,6:3,8:3,0:4,11:5},3*int(y[1]),"*shake*\n"
s=lambda:random.random()*(255*b)**.25<65536*((b-2)*int(y[3])*d[ord(y[2][0])-70]*2.5)**.25
if s():print f*3+"Click!" if s()and s()else f

Bonus for including selected balls: Safari, Sport, Lure, Net, Dusk, Dive, Fast, Quick

Giving me 8*5+6+5+4+3+4+4+4+5=75 bonus points

[edit] Round down to 12 fractional bits every time division is used by not using it

[edit2] optimize pokeball dictionary


Perl 1 (374 - 150 = 224 + MissingNo. bytes)

sub h{print "*shake*
";}($x,$h,$_,$c,$s)=split(/,/,<>);$G=$$%(/P/?256:/U/?151:201);$S=$G-($s==1?0:$s==1.5?12:25);
$F=255&int(int($h*255/(/G|S/?8:12))/(int($x/4)||1));sub c{for($i=0;$i<3;$i++){do h();}print "Click!
";exit;}
/M/||$S<0||$S<$c&&$F>$$*$$%255&&do c();$W=int(int($c*100/(/P/?255:/U/?150:200))*$F/255)+($s==1?0:$s==1.5?5:10);$W>9&&do h();$W>29&&do h();$W>69&&do h();

Argument list:

current hp, max hp, pokéball, catch rate, status, critical capture

Yes, I'm aware this completely breaks the rules, but I don't care. In case you haven't noticed, this is first Pokémon generation capture algorithm, with all its quirks (Great Balls are better than Ultra Balls, in certain conditions). This implements all features, including ones that aren't included (and I decided to include points for them anyway). Critical captures are ignored (but they are implemented - just that they don't affect the capture rate), newer Poké Balls load data of other Poké Balls.

Please note that while this answer is short, it breaks all the rules, so consider it just to be a fun answer, don't accept it. I was initially going to implement Gen5 algorithm in Perl 5, but I decided - why not have some fun. And yes, I actually compiled Perl 1, and this code works. If you run it in newer version of Perl, you may get warnings about deprecated use of do, but let's be honest - it's the only way to run functions in Perl 1. Perl 1 also has some quirks on its own (for example, I cannot move the line starting with /M/ to previous line - why? - I don't know).

Also, there are no random numbers in Perl 1, so hope you won't kill me for modulo of $$. It's the closest thing to the random number I could have found.

Edit: It appears that the old do call() syntax was removed in Perl 5.19.8. Make sure you use an older version of Perl to run this script, as it appears that Perl 5.20 won't be compatible with Perl 1 scripts.


PHP (746 763 bytes - all bonuses):

<?if(!$i=fgets(STDIN))die('');parse_str($i,$i);$b=array('poke'=>1,'great'=>1.5,'ultra'=>2,'master'=>255,'safari'=>1.5,'sport'=>1.5,'lure'=>3,'net'=>3,'dusk'=>3.5,'dive'=>3.5,'moon'=>4,'fast'=>4,'quick'=>5,'love'=>8);$s=array('sleep'=>2.5,'frozen'=>2.5,'paralyzed'=>1.5,'poisoned'=>1.5,'burnt'=>1.5,''=>1);$i=array_merge(array('ball'=>'poke','hp'=>array('max'=>25,'current'=>1),'status'=>2.5,'rate'=>255),$i);$l='strtolower';$r='mt_rand';$x='*shake*'.PHP_EOL;$c='Click!'.PHP_EOL;$a=(((3*$i[hp][max])-(2*$i[hp][current]))*$i[rate]*$b[$l($i[ball])])/(3*$i[hp][max])*(is_numeric($i[status])?$i[status]:$s[$l($i[status])]);$a=((pow(65536/(255/$a),0.25)*4096)<<0)/4096;if($r(0,1)>$a)die();echo$x;if($a>1)die($c);if($r(0,1)>$a)die();echo$x,$x;if($r(0,1)>$a)die();echo$c;

To use this, you have to provide the input as 'ball=poke&status=sleep' on STDIN.

The HP must be provided as 'hp[max]' or 'hp[current]'.

This code works, as tested here.

You can provide the status by it's name or the multiplier. (not required in the question).

Here is a readable version:

if(!$info=fgets(STDIN))die('');
parse_str($info,$info);
$balls=array(//list of pokeballs
    'poke'=>1,
    'great'=>1.5,
    'ultra'=>2,
    'master'=>255,
    'safari'=>1.5,
    'sport'=>1.5,
    'lure'=>3,
    'net'=>3,
    'dusk'=>3.5,
    'dive'=>3.5,
    'moon'=>4,
    'fast'=>4,
    'quick'=>5,
    'love'=>8
);
$status=array(//list of status
    'sleep'=>2.5,
    'frozen'=>2.5,
    'paralyzed'=>1.5,
    'poisoned'=>1.5,
    'burnt'=>1.5,
    ''=>1 //in case there is no status
);
$info=array_merge(//this will set the default values
    array(
        'ball'=>'poke',
        'hp'=>array('max'=>25,'current'=>1),
        'status'=>2.5,
        'rate'=>255
    ),
    $info
);
$a=(((3*$info['hp']['max'])-(2*$info['hp']['current']))*$info['rate']*$balls[strtolower($info['ball'])])/(3*$info['hp']['max'])*(is_numeric($info['status'])?$info['status']:$status[strtolower($info['status'])]);
$a=((pow(65536/(255/$a),0.25)*4096)<<0)/4096;//same as $a=floor(pow(65536/(255/$a),0.25)*4096)/4096;

if(mt_rand(0,1)>$a) die();//test 1
echo '*shake*',PHP_EOL;
if($a>1)die('Click!'.PHP_EOL);//if $a>1, catch it (critical catch)

if(mt_rand(0,1)>$a) die();//test 2
echo'*shake*',PHP_EOL,'*shake*',PHP_EOL;

if(mt_rand(0,1)>$a) die();//test 3
echo 'Click!',PHP_EOL;//passed all tests

I had to edit this because i was using a much higher precision than the required.

The fix was provided by TheConstructor.

Tags:

Code Golf