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.

Programming GSC DV Calculator

Discussion in 'Technical Projects' started by NixHex, Jun 7, 2013.

  1. NixHex

    NixHex what is béisbol
    is a member of the Site Staffis a Forum Moderatoris a Pokemon Researcheris a Contributor to Smogonis a Battle Server Moderator
    Moderator

    Joined:
    Oct 6, 2009
    Messages:
    2,641
    About a year ago, I wrote an article on Stat Calculations and Breeding Mechanics in RBY and GSC. Not satisfied, I decided to make a DV calculator because I was sick of using the inflexible one on Psypoke. I've always wanted to contribute to this forum, so it's a win-win.

    The article and the following calculator are made for people who would like to raise Pokemon for use in Pokemon Stadium 1 & 2, or for the Battle Tower in Pokemon Crystal. It has very little competitive relevance outside of that, unless of course you play competitive GSC/RBY on carts with your friends or something. In that case, you can raise the perfect Snorlax and smash your friends to pieces. If only we had something useful like this back then.

    For the moment it only runs in MATLAB, but I plan on adapting it to Python when I must up the will power. Obviously, this is completely open-source since it's just two m-files (and eventually one .py). You are free to port it to Python or any other language yourself if you see fit. I chose MATLAB because it was designed to work with arrays and hence the set logic involved in breeding mechanics made this incredibly easy to write.

    The first m-file, andM.m, just defines a function that uses the AND operation on two vectors of different lengths. I'm sure MATLAB has a built in command to do this but I couldn't remember it and google was failing me it so I wrote my own.

    The second m-file, gscivs.m, is the calculator itself. In it you are free to modify the Pokemon's base stats, Stat Exp. (the Gen 1/2 analog to EVs), and gender ratio.
    andM.m (open)

    Code:
    function y = andM(a,b)
    %%% Performs the AND operation on vectors of two different sizes %%%
    y=[];
    J=length(a);
    K=length(b);
    for j = 1:J
        for k = 1:K
            if a(j) == b(k)
               y = [y a(j)]; 
            end
        end
    end
    y=unique(y);
    end
    gscivs.m (open)
    Code:
    clear all;
    clc;
    %%%%%%%%%%%%%%% Better RBY IV Calculator %%%%%%%%%%%%%%%%%%%%%%
    BaseStats=[65,60,70,85,75,40]; %% Enter the Base Stats AS LISTED IN Game:
                            %% HP, Attack, Defense, Sp. Attack, Sp. Def, Speed
    EVs=[0,0,0,0,0,0]; %% This number must be known. If you don't know it, use
                                               %% HP Up, Protein, Iron,
                                               %% Calcium, Carbos says "It will have no
                                               %% effect", then use the default
                                               %% value 25600 for each stat. 
    Stats=[23,11,13,15,14,9]; %% Enter the Actual (Visible) Stats AS LISTED IN Game:
              %% HP, Attack, Defense, Special (Attack/Defense), Speed
    Breed = true;
    Female = true;
    FMRatio = [0 0]; %% ratio of female to male
    %% [1 7]
    %% [1 3]
    %% [1 1]
    %% [3 1]
    %% [0 0] for All Female / Genderless
    MotherIVs = [15 15]; % Defense / Special, since those stats are inherited
    Level=5; %% Enter the level of the Pokemon here.
    HPIVs=[];
    AtkIVs=[];
    DefIVs=[];
    SpAIVs=[];
    SpDIVs=[];
    SpeIVs=[];
    %%% First, Calculate HP %%%
    for HPIV=0:15 %%% HP
       X=floor((HPIV+BaseStats(1)+sqrt(EVs(1))/8+50)*Level/50)+10;
       if X==Stats(1)
           HPIVs=[HPIVs HPIV];
       end  
    end
    
    %%% Now, for the rest of the stats %%%
    for AtkIV=0:15 %%% Attack
       X=floor((AtkIV+BaseStats(2)+sqrt(EVs(2))/8)*Level/50)+5;
       if X==Stats(2)
           AtkIVs=[AtkIVs AtkIV];
       end
    end
    
    for DefIV=0:15 %%% Defense
       X=floor((DefIV+BaseStats(3)+sqrt(EVs(3))/8)*Level/50)+5;
       if X==Stats(3)
           DefIVs=[DefIVs DefIV];
       end
    end
    
    for SpAIV=0:15 %%% Special Attack (Same as Special)
       X=floor((SpAIV+BaseStats(4)+sqrt(EVs(4))/8)*Level/50)+5;
       if X==Stats(4)
           SpAIVs=[SpAIVs SpAIV];
       end
    end
    
    for SpDIV=0:15 %%% Special Defense (Same as Special)
       X=floor((SpDIV+BaseStats(5)+sqrt(EVs(5))/8)*Level/50)+5;
       if X==Stats(5)
           SpDIVs=[SpDIVs SpDIV];
       end
    end
    
    for SpeIV=0:15 %%% Speed
       X=floor((SpeIV+BaseStats(6)+sqrt(EVs(6))/8)*Level/50)+5;
       if X==Stats(6)
           SpeIVs=[SpeIVs SpeIV];
       end
    end
    
    %%% Do a female/male comparison
    
    if Female == true
        if     FMRatio == [1 7]
            GenderAtkRange = 0:1;
        elseif FMRatio == [1 3]
            GenderAtkRange = 0:4;
        elseif FMRatio == [1 1]
            GenderAtkRange = 0:6;
        elseif FMRatio == [3 1]
            GenderAtkRange = 0:11;
        elseif FMRatio == [0 0]
            GenderAtkRange = 0:15;
        end
    else
        GenderAtkRange = 0:15;
    end
    
    AtkIVs = unique(andM(AtkIVs,GenderAtkRange));
    SpcIVs = unique(andM(SpAIVs,SpDIVs)); %%% Do a set comparison since SpA = SpD = Spc
    %%% Do a set comparison with the HP IVs based on the HP Formula %%%
    
    if Breed == true
       DefIVs = MotherIVs(1);
       SpcM = MotherIVs(2);
       if (SpcM < 8)
           SpcM = [SpcM SpcM+8];
       else
           SpcM = [SpcM SpcM-8];
       end
       SpcIVs = unique(andM(SpcIVs,SpcM));    
    end
    
    % HPIVs
    if isempty(HPIVs)
        disp('HP = Invalid IVs (Possible Invalid IVs). Please verify your stats.');
    else
        disp(strcat('HP  = [',num2str(HPIVs),']'));
    end
    % AtkIVs
    if isempty(AtkIVs)
        disp('Atk = Invalid IVs (Possible Gender Attack IV Mismatch). Please verify your stats.');
    else
        disp(strcat('Atk = [',num2str(AtkIVs),']'));
    end
    % DefIVs
    
    if isempty(DefIVs)
        disp('Def = Invalid IVs(Possible Breeding IV Mismatch). Please verify your stats.');
    else
        disp(strcat('Def = [',num2str(DefIVs),']'));
    end
    
    % SpAIVs
    if isempty(SpcIVs)
        disp('SpA = Invalid IVs (Possible Special Attack/Defense IV or Breeding Mismatch). Please verify your stats.');
    else
        disp(strcat('SpA = [',num2str(SpcIVs),']'));
    end
    % SpDIVs
    if isempty(SpcIVs)
        disp('SpD = Invalid IVs (Possible Special Attack/Defense IV Mismatch). Please verify your stats.');
    else
        disp(strcat('SpD = [',num2str(SpcIVs),']')); 
    end
    % SpeIVs
    if isempty(SpeIVs)
        disp('Spe = Invalid  IVs. Please verify your stats.');
    else
        disp(strcat('Spe = [',num2str(SpeIVs),']'));
    end

    Instructions:
    Say you want to calculate a freshly hatched Porygon Egg, bred with a Ditto with flawless Defense and Special IVs. Modify the BaseStats vector to Porygon's base stats, and set EV vector to 0, and type in Porygon's raw stats into the Stats vector:
    Code:
    BaseStats=[65,60,70,85,75,40]
    Code:
    EVs=[0,0,0,0,0,0];
    Code:
    Stats=[23,11,13,15,14,9];
    Since we are breeding, and the baby that hatched was genderless, edit the following lines accordingly:
    Code:
    Breed = true;
    Female = false;
    The following line doesn't matter since it's a Porygon, but for any female Pokemon you would edit it according to the comments below it:
    Code:
    FMRatio = [0 0]; %% ratio of female to male
    %% [1 7]
    %% [1 3]
    %% [1 1]
    %% [3 1]
    %% [0 0] for All Female
    As stated before, the Ditto's Defense and Special DVs are both 15. These are the only ones that require modification because no other DVs undergo any other inheritance scheme.
    Code:
    MotherIVs = [15 15];
    Finally, it's a baby, so Level 5:
    Code:
    Level=5;
    Now, click the "Save and Run" button with the Green arrow in the toolbar, or type F5 on Windows to run.

    The results are displayed in the MATLAB command window:
    HP = [15]
    Atk = [0 1 2 3 4 5 6 7 8 9]
    Def = [15]
    SpA = [15]
    SpD = [15]
    Spe = [0 1 2 3 4 5 6 7 8 9]

    Let's try modifying one of the Special stats:
    Code:
    Stats=[23,11,13,15,[COLOR=Red][B]13[/B][/COLOR],9];
    The results are:
    HP = [15]
    Atk = [0 1 2 3 4 5 6 7 8 9]
    Def = [15]
    SpA = Invalid IVs (Possible Special Attack/Defense IV or Breeding Mismatch). Please verify your stats.
    SpD = Invalid IVs (Possible Special Attack/Defense IV Mismatch). Please verify your stats.
    Spe = [0 1 2 3 4 5 6 7 8 9]

    Since both Special Attack and Special Defense run off of the same DV, both stats are invalid despite the fact that we only modified one of them.

    Let's screw around with the breeding. First, lower Ditto's Special IV to 14. Next, change Ditto's Defense IV to 13.

    HP = [15]
    Atk = [0 1 2 3 4 5 6 7 8 9]
    Def = [13]
    SpA = Invalid IVs (Possible Special Attack/Defense IV or Breeding Mismatch). Please verify your stats.
    SpD = Invalid IVs (Possible Special Attack/Defense IV Mismatch). Please verify your stats.
    Spe = [0 1 2 3 4 5 6 7 8 9]

    We get a reasonable result for Defense; as it turns out, the current Defense stat is valid for 11, 13, and 15 (given as how the HP IV is calculated to be odd). Hence, 13 Defense is still valid. Now, let's change Ditto's Special EV to 7:

    HP = [15]
    Atk = [0 1 2 3 4 5 6 7 8 9]
    Def = [13]
    SpA = [15]
    SpD = [15]
    Spe = [0 1 2 3 4 5 6 7 8 9]

    Porygon's Special IV is valid again, because Ditto's Special DV of 7 can possibly be inherited as 15 according to the article I linked to earlier.
  2. DracoSP360

    DracoSP360

    Joined:
    May 26, 2013
    Messages:
    23
  3. Jorgen

    Jorgen World's Strongest Fairy
    is a Forum Moderator Alumnusis a Community Contributor Alumnusis a Contributor Alumnusis a Past SPL Winner

    Joined:
    Jun 5, 2010
    Messages:
    1,253
    A decent, if rough, start.

    The function you're looking for is intersect. I'm pretty sure it also reduces the list to only the unique values, too, so you don't have to wrap everything in unique() like you do here.

    When you convert to Python it would probably be best to make it a function or create a series of user prompts so the user doesn't have to manually change the script for every calculation, or even incorporate this script into a GUI if you're savvy. A function would be preferable if you want to be able to perform bulk calculations, though.

    Also I question the utility of manual-input EVs (technically Stat Exp) unless they are 0, full, or max-vitaminned. Perhaps just adding a "full-vitamin" discrete input to the options from Psypokes as opposed to having to input an array of 25600s manually would be best.

    Psypokes' base stat input field is actually a Pokemon input field, which I feel would be a more convenient way to input that information than having to manually look up and input base stats.

    Other than that, it seems like the main feature this has that Psypokes doesn't is the option to select the Mother's DVs to narrow down possibilities based on that. However, you seemed inspired to undergo this project primarily because the PsyPokes one was "inflexible", not because it didn't incorporate stat inheritance mechanics. What specifically does "inflexible" mean, and how does this script change that? I'm just trying to find out how you're addressing your key complaint about the PsyPokes calculator, not trying to dissuade you from continuing work on this or anything. (FWIW incorporating breeding mechanics into a calculator like this for GSC is a pretty unique feature on its own and more than reason enough to continue work on this imo).
  4. NixHex

    NixHex what is béisbol
    is a member of the Site Staffis a Forum Moderatoris a Pokemon Researcheris a Contributor to Smogonis a Battle Server Moderator
    Moderator

    Joined:
    Oct 6, 2009
    Messages:
    2,641
    It was mainly for the breeding mechanics. In all honesty, keeping track of Stat Exp. is a pain outside of vitamins / full so I'll make it more automated. Eventually I'll get it so you can add levels like with metalkid's calculator. Also, what do you think would be the best way to do a list of of Pokemon with their base stats? Just from a csv file?

    Also do you think this would be an easy task in javascript? I'd like to make it browser based. Just need an intersect function in that and I think I could pull it off. Thanks for the tips Jorgen!
  5. Joim

    Joim Navigate the pitfalls, cross the great divide!
    is a Site Staff Alumnusis a Battle Server Admin Alumnusis a Programmer Alumnusis a Tiering Contributor Alumnusis a Contributor Alumnusis a Smogon Media Contributor Alumnusis an Administrator Alumnus

    Joined:
    Oct 9, 2012
    Messages:
    1,510
    NixHex, it's pretty easy to transform the final version of this into a nice javascript that works in all navigators :>

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