1. New to the forums? Check out our Mentorship Program!
    Our mentors will answer your questions and help you become a part of the community!
  2. Welcome to Smogon Forums! Please take a minute to read the rules.

IVs -> PID html/JavaScript Calculator

Discussion in 'Archives' started by mingot, Jun 2, 2009.

  1. mingot

    mingot free agent
    is a Site Staff Alumnusis a Battle Server Admin Alumnusis a Researcher Alumnusis a Smogon Media Contributor Alumnusis a Contributor Alumnusis an Administrator Alumnus

    Joined:
    Jun 15, 2008
    Messages:
    3,050
    Inspired by this exchange, I decided that I would take a crack at converting X-Acts very useful Java Applet (IVs to PID) to JavaScript, and hopefully kick off a series of useful calculators that can be put on site. Sarenji did all of the user interface work, including input and validation to turn my rough1routines into something usable. So thank you X-Act and Sarenji!

    To use, you may copy the information in the code block below into a file, and name it ivstopid.html, and open in a browser.

    Currently the this has been tested in IE6, IE8, Firefox 3, and Chrome.

    And here it is:

    HTML:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
        <head>
            <title>IVs to PID</title>
            <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
            <script type="text/javascript">
            <!--
                /////////////////////////////////////////////////////////////////
                //  RNG CODE BEGIN
                /////////////////////////////////////////////////////////////////
                //  ctor to define our lcrngr class.  Very simple, holds
                //  the current seed that the _get method will use to
                //  get the previous number.
                function lcrngr(seed)
                {
                    //  Set the initial seed of the RNG
                    this.seed = seed;
                }
                    
                //  Get the previous value        
                function lcrngr_get()
                {                              
                    this.seed = (((0xEEB90000 * this.seed | 0) + (0xEB65 * this.seed)) + 0x0A3561A1) & 0xFFFFFFFF;                                                                            
                    return this.seed >>> 16;                
                }
                lcrngr.prototype.lcrngr_get=lcrngr_get;
                /////////////////////////////////////////////////////////////////                        
                     
                /////////////////////////////////////////////////////////////////
                //  CALCULATION CODE BEGIN
                /////////////////////////////////////////////////////////////////
                //                
                function calculate(hp, atk, def, spa, spd, spe, nature, id)
                {    
                    //  Create our array that we are going to return which
                    //  will contain all of the information that we are
                    //  interested in.
                    var resultArray = [];                
                        
                    //  We need to test the last IV with the high bit both
                    //  cleared and set, as either can actually produce the
                    //  same end IVs.
                    var lastIvClear = 0;
                    var lastIvSet = 0;                
                    lastIvClear = spe + (spa << 5) + (spe << 10);                
                    lastIvSet = lastIvClear ^ 0x8000;        
                    
                    var firstIvClear = 0;
                    var firstIvSet = 0;                
                    firstIvClear = hp  + (atk << 5) + (def << 10);                
                    firstIvSet = firstIvClear ^ 0x8000;                                        
                    
                    for (var cnt = 0; cnt <= 0x1FFFE; cnt++)
                    {    
                        //  We need to test with the high bit cleared 
                        //  and set so we're just going to do them both
                        //  in a single loop.
                        var lastivTest = 0;
                        
                        if(cnt % 2 == 0)
                        {
                            lastivTest = lastIvClear;
                        }
                        else
                        {
                            lastivTest = lastIvSet;
                        }
                    
                        //  This is the seed for the string of RNG results
                        //  that we want to test for a match to supplied
                        //  IVs and nature.
                        var seedTest = (lastivTest << 16) + (cnt % 0xFFFF);
                    
                        //  We are going to check this one now, reversing
                        //  through and seeing if we get a nature match.
                        var rng = new lcrngr(seedTest);
                                            
                        //  Get the next two numbers, as we need them 
                        //  to create our IV comparison.               
                        var rng1 = rng.lcrngr_get();
                        var rng2 = rng.lcrngr_get();
                         
                        if(rng1 == firstIvSet || rng1 == firstIvClear)                                             
                        {                           
                            var rng3 = rng.lcrngr_get();
                            var rng4 = rng.lcrngr_get();
                            
                            //  Keep track of our starting seed, which is what
                            //  we can pass to a forward running RNG to recreate
                            //  this sequence.
                            var method1Seed = rng.seed;
                            rng.lcrngr_get();
                            var method234Seed = rng.seed;
                        
                            //  This means we have at least a partial match
                            //  for methods 1, 2, and 3.  Lets go through
                            //  each one of these and build a PID/Check the 
                            //  nature.
                            var method1pid = unsign((rng2 << 16) + rng3);                                            
                            
                            if(method1pid % 25 == nature)
                            {
                                var sid = rng2 ^ rng3 ^ id;
                                                
                                resultArray[resultArray.length] 
                                    = new seed("Method 1", unsign(method1Seed), method1pid, method1pid % 2, method1pid % 256, sid);                         
                            }
                            
                            var method2pid = unsign((rng3 << 16) + rng4);    
                            if(method2pid % 25 == nature)
                            {
                                var sid = rng3 ^ rng4 ^ id;
                                                
                                resultArray[resultArray.length] 
                                    = new seed("Method 2", unsign(method234Seed), method2pid, method2pid % 2, method2pid % 256, sid);                         
                            }
                            
                            var method3pid = unsign((rng2 << 16) + rng4);    
                            if(method3pid % 25 == nature)
                            {
                                var sid = rng2 ^ rng4 ^ id;
                                                
                                resultArray[resultArray.length] 
                                    = new seed("Method 3", unsign(method234Seed), method3pid, method3pid % 2, method3pid % 256, sid);                         
                            }                                                                
                        }                                                    
                                            
                        if(rng2 == firstIvSet || rng2 == firstIvClear) 
                        {
                            var rng3 = rng.lcrngr_get();
                            var rng4 = rng.lcrngr_get();
                            
                            //  Get the next RNG call that we need to create our seed
                            rng.lcrngr_get();
                            var method234Seed = rng.seed;
                        
                            var method4pid = unsign((rng3 << 16) + rng4);
                            
                            if(method4pid % 25 == nature)
                            {
                                var sid = rng3 ^ rng4 ^ id;
                            
                                resultArray[resultArray.length] 
                                    = new seed("Method 4", unsign(method234Seed), method4pid, method4pid % 2, method4pid % 256, sid);                            
                            }                            
                        }
                    }              
                                      
                    return resultArray;
                }
                            
                /////////////////////////////////////////////////////////////////
                //  SEED 
                /////////////////////////////////////////////////////////////////
                function seed(method, seed, pid, ability, gender, sid)
                {
                    this.method = method;
                    this.seed = seed;
                    this.pid = pid;
                    this.ability = ability;
                    this.gender = gender;
                    this.sid = sid;
                }
                                       
                function unsign(v)
                { 
                    return (v >>> 1) * 2 + (v & 1)             
                }    
                
                /////////////////////////////////////////////////////////////////
                //  DISPLAY / USER INTERFACE
                /////////////////////////////////////////////////////////////////
                //
                function calculateAndDisplay()
                {
                    //  Pull all of our values that we are going to pass
                    //  to the calculate function from our text boxes and
                    //  validate the values.
                    var hp  = parseInt(document.getElementById('TextHp').value);
                    var atk = parseInt(document.getElementById('TextAtk').value);
                    var def = parseInt(document.getElementById('TextDef').value);
                    var spa = parseInt(document.getElementById('TextSpA').value);
                    var spd = parseInt(document.getElementById('TextSpD').value);
                    var spe = parseInt(document.getElementById('TextSpe').value);
                    var nat = parseInt(document.getElementById('nature').value);
                    var idn = parseInt(document.getElementById('idnum').value);
                    
                    //alert("Hp: " + hp + "; Atk: " + atk + "; Def: " + def + "; SpA: " + spa + "; SpD " + spd + "; Spe: " + spe + "; Nature: " + nat + "; id: " + idn);
                    
                    var resultArray = calculate(hp, atk, def, spa, spd, spe, nat, idn);
                    
                    displayResults(resultArray);
                }
                
                function fixField(field, minValue, maxValue)
                {
                    if (field.value.search(/^[0-9]+$/) === -1)
                        field.value = minValue;
                    else if (field.value < minValue)
                        field.value = minValue;
                    else if (field.value > maxValue)
                        field.value = maxValue;
                }
                
                function displayResults(resultArray)
                {
                    var tbl = document.getElementById('resultTable');
                    
                    while(tbl.rows.length > 1)
                        tbl.deleteRow(tbl.rows.length - 1);
                    
                    for(i=0;i<resultArray.length;i++) 
                    {                                       
                        var lastRow = tbl.rows.length;                      
                        var iteration = lastRow;
                        var row = tbl.insertRow(lastRow);
                                                
                        var cellMethod = row.insertCell(0);
                        var textNode = document.createTextNode(resultArray[i].method);
                        cellMethod.appendChild(textNode);
                          
                        var cellSeed = row.insertCell(1);
                        var textNode = document.createTextNode(resultArray[i].seed.toString(16).toUpperCase());
                        cellSeed.appendChild(textNode);
                          
                        var cellPID = row.insertCell(2);
                        var textNode = document.createTextNode(resultArray[i].pid.toString(16).toUpperCase());
                        cellPID.appendChild(textNode);
                          
                        var cellAbility = row.insertCell(3);
                        var textNode = document.createTextNode(resultArray[i].ability.toString(16).toUpperCase());
                        cellAbility.appendChild(textNode);
                          
                        var cellGender = row.insertCell(4);
                        var textNode = document.createTextNode(resultArray[i].gender.toString());
                        cellGender.appendChild(textNode);
                          
                        var cellSID = row.insertCell(5);
                        var textNode = document.createTextNode(resultArray[i].sid.toString());
                        cellSID.appendChild(textNode);                                                                                                                      
                     }            
                }
                
                function hideError() {
                    document.getElementById('jserror').style.display = 'none'; 
                }
            // -->
            </script>
            <style type="text/css">
                body {
                    font-family: Verdana, serif;
                    color: #444;
                }
                table {
                    padding: 10px;
                    border: 1px solid black;
                    margin: 10px;
                }
                table#resultTable {
                    border-collapse:collapse;
                    border: none;
                }
                table#resultTable th, table#resultTable td {
                    border: 1px solid black;
                    padding: 5px 10px;
                }
                label {
                    font-weight: bold;
                    font-style: italic;
                    float: right;
                }
                input#FindPID {
                    margin: 5px 0;
                    width: 80%;
                    padding: 10px;
                }
                h1 {
                    font-size: 1.5em;
                    font-weight: normal;
                    margin-bottom: 0;
                    border-bottom: 1px solid #ccc;
                }
                h2 {
                    font-family: Helvetica,Arial,sans-serif;
                    font-style: italic;
                    font-size: 1em;
                    font-weight: normal;
                    margin: 0;
                }
                #jserror {
                    background: #FFDDDD;
                    border-top: 1px solid #FFAAAA;
                    border-bottom: 1px solid #FFAAAA;
                    padding: 10px;
                    margin: 10px 0;
                }
            </style>
        </head>
        <body onload="hideError();">
            <h1>IVs to PID</h1>
            <h2>—by X-Act, mingot, and Sarenji</h2>
            
            <div id="jserror">
                <strong>Warning:</strong> JavaScript is disabled! Please enable 
                JavaScript to use this.
            </div>
            
            <table id="form">
                <tr>
                    <td><label for="TextHp">HP:</label ></td>
                    <td><input id="TextHp" type="text" size="2" maxlength="2" value="31" onblur="fixField(this, 0, 31);"/></td>
    
                    <td><label for="TextAtk">Atk:</label></td>
                    <td><input id="TextAtk" type="text" size="2" maxlength="2" value="31" onblur="fixField(this, 0, 31);"/></td>
                    <td><label for="TextDef">Def:</label></td>
                    <td><input id="TextDef" type="text" size="2" maxlength="2" value="31" onblur="fixField(this, 0, 31);"/></td>
    
                </tr>
                <tr>
                    <td><label for="TextSpA">SpA:</label></td>
    
                    <td><input id="TextSpA" type="text" size="2" maxlength="2" value="31" onblur="fixField(this, 0, 31);"/></td>
                    <td><label for="TextSpD">SpD:</label></td>
                    <td><input id="TextSpD" type="text" size="2" maxlength="2" value="31" onblur="fixField(this, 0, 31);"/></td>
                    <td><label for="TextSpe">Spe:</label></td>
    
                    <td><input id="TextSpe" type="text" size="2" maxlength="2" value="31" onblur="fixField(this, 0, 31);"/></td>
                </tr>
                <tr>
                    <td><label for="nature">Nature:</label></td>
    
                    <td><select id="nature">
                        <option value="0">Hardy</option>
                        <option value="1">Lonely</option>
    
                        <option value="2">Brave</option>
                        <option value="3">Adamant</option>
                        <option value="4">Naughty</option>
    
                        <option value="5">Bold</option>
                        <option value="6">Docile</option>
                        <option value="7">Relaxed</option>
    
                        <option value="8">Impish</option>
                        <option value="9">Lax</option>
                        <option value="10">Timid</option>
    
                        <option value="11">Hasty</option>
                        <option value="12">Serious</option>
                        <option value="13">Jolly</option>
    
                        <option value="14">Naive</option>
                        <option value="15">Modest</option>
                        <option value="16">Mild</option>
                        <option value="17">Quiet</option>
                        <option value="18">Bashful</option>
                        <option value="19">Rash</option>
    
                        <option value="20">Calm</option>
                        <option value="21">Gentle</option>
                        <option value="22">Sassy</option>
    
                        <option value="23">Careful</option>
                        <option value="24">Quirky</option>
                    </select></td>
    
                    <td><label for="idnum">ID:</label></td>
                    <td><input id="idnum" type="text" size="5" maxlength="5" value="0" onblur="fixField(this, 0, 65535);"/></td>
                </tr>
                <tr>
    
                    <th colspan="16"><input id="FindPID" type="button" value="Find PID" onclick="calculateAndDisplay();"/></th>
                </tr>
            </table>
            
            <table id="resultTable">
    
                <tr>
                    <th>Method</th>
                    <th>Seed</th>
                    <th>PID</th>
    
                    <th>Ability</th>
                    <th>Gender</th>
    
                    <th>SID</th>
                </tr>
            </table>
        
        </body>
    </html>
    
  2. X-Act

    X-Act np: Biffy Clyro - Shock Shock
    is a Site Staff Alumnusis a Programmer Alumnusis a Smogon IRC SOp Alumnusis a Researcher Alumnusis a CAP Contributor Alumnusis a Tiering Contributor Alumnusis a Contributor Alumnusis an Administrator Alumnus

    Joined:
    Feb 17, 2006
    Messages:
    4,675
    I tested this and it works, but it seems to work very slowly. Looking at the code, I'm not seeing anything that is obviously downgrading performance. I don't know if anyone can spot things that can speed up performance or if Javascript is really that slow.
  3. VileTung

    VileTung

    Joined:
    Jul 25, 2008
    Messages:
    1,384
    Nice work, I just tested it too, but it's not very slow here. Maybe because I'm running localhost?

    Anyway, if you guys don't mind, I'm going to try to make it faster.
  4. RaptorEngineer

    RaptorEngineer

    Joined:
    Jun 21, 2009
    Messages:
    135
    Hey guys really new to PIDs and I have two quick questions,

    When the form asks for 'ID:' is this the Trainer ID appearing in my Poke's summary?

    And when the PID does show, where will it show?
    (I can't tell if my comp is going too slow or I just can't see it. :/ )
  5. mingot

    mingot free agent
    is a Site Staff Alumnusis a Battle Server Admin Alumnusis a Researcher Alumnusis a Smogon Media Contributor Alumnusis a Contributor Alumnusis an Administrator Alumnus

    Joined:
    Jun 15, 2008
    Messages:
    3,050
    Yes, it is. I tend to think that if you are not seeing results there is some issue with your browser and JavaScript when loading from a file directly on your system. I have had this problem reported before and Sarenji added some code to warn when JavaScript was not enabled for the page. I will see if I can get him to update with that when I next see him.
  6. ryubahamut

    ryubahamut
    is a Site Staff Alumnusis a Programmer Alumnusis a Forum Moderator Alumnusis a Contributor Alumnus

    Joined:
    Jan 18, 2007
    Messages:
    999
    i'll go through this and tell you whatever i can find, but at cursory glance i found stuff i couldn't quite find the reason for. for example, under mult32, you compute the or of variables against zero. shouldn't the code work the same without those steps?
  7. Arseus

    Arseus
    refuses to accept Contributor

    Joined:
    Oct 13, 2006
    Messages:
    869
    For all the OS X users out there, I tested this and it indeed runs on Safari 3.1.1, albeit somewhat slowly as other users have reported. If you guys can optimize it so it runs faster, that would be great, but otherwise, good work!
  8. mingot

    mingot free agent
    is a Site Staff Alumnusis a Battle Server Admin Alumnusis a Researcher Alumnusis a Smogon Media Contributor Alumnusis a Contributor Alumnusis an Administrator Alumnus

    Joined:
    Jun 15, 2008
    Messages:
    3,050
    The "| 0" basically truncates the number to 32 bits, but as we know all of the inputs to the function will already be <= 0xFFFFFFFF I can actually remove these, so that saves us having to do do that a quarter of a million times. Found one other instruction to remove from that function, too.

    Thanks and good eye.

    Updated OP with newest version of the code.

    And thank you, Arseus, for testing on Safari!

    EDIT: Well at the expense of any beauty the code may have had at some point I've managed to really speed it up. Lots of inlining, better 32 bit multiplication, and many other improvements. The IE "slow script" dialog is a thing of the past and this runs in sub 1 second for me on Firefox.

Users Viewing Thread (Users: 0, Guests: 0)