Programming GSC DV Calculator

NixHex

Doing just fine, here at the top of the world
is a Site Staff Alumnusis a Forum Moderator Alumnusis a Researcher Alumnusis a Contributor Alumnusis a Battle Server Moderator Alumnus
#1
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.
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
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.
 

Jorgen

World's Strongest Fairy
is a Forum Moderator Alumnusis a Community Contributor Alumnusis a Contributor Alumnusis a Past SPL Champion
#3
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).
 

NixHex

Doing just fine, here at the top of the world
is a Site Staff Alumnusis a Forum Moderator Alumnusis a Researcher Alumnusis a Contributor Alumnusis a Battle Server Moderator Alumnus
#4
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!
 

Joim

Pixels matter
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
#5
NixHex, it's pretty easy to transform the final version of this into a nice javascript that works in all navigators :>