Tutorials

How to Make Pokemon GO IV Calculator in JavaScript

In this tutorial, you will learn how to make a Pokemon GO IV Calculator in JavaScript. Basically, this tool can be used to get the IVs of the Pokemon. It means that now you can easily find out if your Pokemon can be the best.

You can even improve this Pokemon GO IV Calculator by adding features like PvP Team Builder for planning your PvP teams in all leagues. Also, get familiar with PvP Strategy and why lower IVs can be better.

The full source code of the Pokemon GO IV Calculator is given below. You can easily copy/paste or download it on your computer and try it yourself.

Pokemon GO IV Calculator

index.js

const _ = require('underscore');
const pokedex = require('./support/pokedex');
const levelUpData = require('./support/levelUpData');
const grader = require('./support/grader');

function testHP(hp, iv, levelData, pokemon) {
 return hp == parseInt(Math.floor((pokemon.stamina + iv) * levelData.cpScalar), 10);
}

function testCP(cp, attackIV, defenseIV, staminaIV, levelData, pokemon) {
 const attackFactor = pokemon.attack + attackIV;
 const defenseFactor = Math.pow(pokemon.defense + defenseIV, 0.5)
 const staminaFactor = Math.pow((pokemon.stamina + staminaIV), 0.5);
 const scalarFactor = Math.pow(levelData.cpScalar, 2);
 return cp == parseInt(attackFactor * defenseFactor * staminaFactor * scalarFactor / 10, 10);
}

function determinePerfection(ivs) {
 const perfection = (ivs.attackIV + ivs.defenseIV + ivs.staminaIV) / 45
 return Math.floor(perfection * 100) / 100;
}

/**
 * Evaluate a given pokemon
 * @param {string|number} Pokemon Query (e.g. "2" or "Ivysaur")
 * @param {number} CP
 * @param {number} HP
 * @param {number} dustCost Dust cost of upgrading pokemon
 * @param {bool} neverUpgraded If you've never powered it up, fewer potential levels
 */function evaluate (pokemonQuery, cp, hp, dustCost, neverUpgraded) {
 const pokemon = pokedex.pokemonByName(pokemonQuery) || pokedex.pokemonById(pokemonQuery);
 if (!pokemon) {
  return {error : `Could not find pokemon: ${pokemonQuery}`};
 }
 var potentialIVs = determinePossibleIVs(pokemon, cp, hp, dustCost, neverUpgraded);

 _.each(potentialIVs, function (possibility) {
  possibility.perfection = determinePerfection(possibility);
 });

 potentialIVs.sort(function (a, b) {
  if (a.perfection == b.perfection) {
   return 0;
  }
  return a.perfection > b.perfection ? 1 : -1;
 })

 var pokeSnapshot = {
  grade : grader.grade(_.map(potentialIVs, determinePerfection)),
  ivs : potentialIVs
 };

 return pokeSnapshot;
}

function determinePossibleIVs (pokemon, cp, hp, dust, neverUpgraded) {
 var potentialLevels = levelUpData.levelsByDust(dust);
 potentialLevels.sort(function (a, b) {
  return a.level > b.level ? 1 : -1;//no dupes
 });
 if (neverUpgraded) {
  potentialLevels = _.filter(potentialLevels, function (data) {
   return data.level % 2 === 0;
  });
 }

 var staminaIV, attackIV, defenseIV;
 var potentialHPIVs = [];

 var levelIndex;
 var levelData;
 for (levelIndex = 0; levelIndex < potentialLevels.length; levelIndex++) {
  levelData = potentialLevels[levelIndex];

  for (staminaIV = 0; staminaIV <= 15; staminaIV++) {
   if (testHP(hp, staminaIV, levelData, pokemon)) {
    potentialHPIVs.push({
     levelData,
     iv : staminaIV
    });
   }
  }

 }

 var hpIVIndex;
 var potentialIVs = [];
 for (hpIVIndex = 0; hpIVIndex < potentialHPIVs.length; hpIVIndex++) {
  staminaIV = potentialHPIVs[hpIVIndex].iv;
  levelData = potentialHPIVs[hpIVIndex].levelData;
  for (attackIV = 0; attackIV <= 15; attackIV++) {
   for (defenseIV = 0; defenseIV <= 15; defenseIV++) {
    if (testCP(cp, attackIV, defenseIV, staminaIV, levelData, pokemon)) {
     potentialIVs.push({
      attackIV, defenseIV, staminaIV,
      level : levelData.level
     })
    }
   }
  }
 }

 return potentialIVs;
}

/**
 * Determine possible IVs for a given pokemon
 * @param {string|number} Pokemon Query (e.g. "2" or "Ivysaur")
 * @param {number} CP
 * @param {number} HP
 * @param {number} dustCost Dust cost of upgrading pokemon
 * @param {bool} neverUpgraded If you've never powered it up, fewer potential levels
 */function possibleIVs (pokemonQuery, cp, hp, dust, neverUpgraded) {
 const pokemon = pokedex.pokemonByName(pokemonQuery) || pokedex.pokemonById(pokemonQuery);
 if (!pokemon) {
  return {error:`Could not find pokemon: ${pokemonQuery}`};
 }
 const ivs = determinePossibleIVs(pokemon, cp, hp, dustCost, neverUpgraded);
 if (!ivs.length) {
  return {error: `Could not find any IVs matching given information`};
 }
 return {ivs};
}

module.exports = {
 evaluate,
 possibleIVs
};

package.json

{
  "name": "pokemon-go-iv-calculator",
  "version": "0.3.2",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+ssh://git@github.com/andromedado/pokemon-go-iv-calculator.git"
  },
  "keywords": [
    "pokemon",
    "pokemongo",
    "ivcalculator",
    "calculator"
  ],
  "author": "Shad Downey <shad.downey@gmail.com>",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/andromedado/pokemon-go-iv-calculator/issues"
  },
  "homepage": "https://github.com/andromedado/pokemon-go-iv-calculator#readme",
  "dependencies": {
    "underscore": "^1.8.3"
  }
}

/support/grader.js

const _ = require('underscore');

const letterGrades = [
 { letter : 'A', min : 0.9, mid : 0.93, plus : 0.95 },
 { letter : 'B', min : 0.8, mid : 0.83, plus : 0.87 },
 { letter : 'C', min : 0.7, mid : 0.73, plus : 0.77 },
 { letter : 'D', min : 0.6, mid : 0.62, plus : 0.67 },
 { letter : 'F', min : 0 },
];

function grade(value) {
 var letter;
 var modifier;

 var idx;
 var grade;
 for (idx = 0; idx < letterGrades.length; idx++) {
  grade = letterGrades[idx];
  if (value >= grade.min) {
   letter = grade.letter;
   if (value < grade.mid) {
    modifier = '-';
   } else if (value >= grade.plus) {
    modifier = '+';
   }
   break;
  }
 }

 const finalGrade = {
  letter: letter,
  preciseLetter : letter + (modifier || '')
 };

 return finalGrade;
}

function determineGrade(values) {
 if (values && !_.isArray(values)) {
  values = [values];
 }
 if (!values || !values.length) {
  return 'Unknown';
 }
 values.sort();
 const minGrade = grade(values[0]);
 const maxGrade = grade(values[values.length - 1]);
 const averageValue = _.reduce(values, function (memo, val) {return memo + val;}, 0) / values.length;
 const averageGrade = grade(averageValue);

 if (values.length === 1 || minGrade.preciseLetter === maxGrade.preciseLetter) {
  return {
   minGrade, maxGrade, averageGrade,
   explanation : `${minGrade.preciseLetter} (${Math.floor(averageValue * 1000) / 10}%)`
  };
 }

 if (averageGrade.letter === minGrade.letter && averageGrade.letter === maxGrade.letter) {
  return {
   minGrade, maxGrade, averageGrade,
   explanation : `Solid ${averageGrade.preciseLetter} (${Math.floor(averageValue * 1000) / 10}%)`
  };
 }

 return {
  minGrade, maxGrade, averageGrade,
  explanation : `Between ${maxGrade.preciseLetter} - ${minGrade.preciseLetter}`
 }
}

module.exports = {
 grade : determineGrade
};

/support/levelUpData.js

var _ = require('underscore');

var levels = [
 {
  "level": 1,
  "dust": 200,
  "candy": 1,
  "cpScalar": 0.094
 },
 {
  "level": 2,
  "dust": 200,
  "candy": 1,
  "cpScalar": 0.1351374
 },
 {
  "level": 3,
  "dust": 200,
  "candy": 1,
  "cpScalar": 0.1663979
 },
 {
  "level": 4,
  "dust": 200,
  "candy": 1,
  "cpScalar": 0.1926509
 },
 {
  "level": 5,
  "dust": 400,
  "candy": 1,
  "cpScalar": 0.2157325
 },
 {
  "level": 6,
  "dust": 400,
  "candy": 1,
  "cpScalar": 0.2365727
 },
 {
  "level": 7,
  "dust": 400,
  "candy": 1,
  "cpScalar": 0.2557201
 },
 {
  "level": 8,
  "dust": 400,
  "candy": 1,
  "cpScalar": 0.2735304
 },
 {
  "level": 9,
  "dust": 600,
  "candy": 1,
  "cpScalar": 0.2902499
 },
 {
  "level": 10,
  "dust": 600,
  "candy": 1,
  "cpScalar": 0.3060574
 },
 {
  "level": 11,
  "dust": 600,
  "candy": 1,
  "cpScalar": 0.3210876
 },
 {
  "level": 12,
  "dust": 600,
  "candy": 1,
  "cpScalar": 0.335445
 },
 {
  "level": 13,
  "dust": 800,
  "candy": 1,
  "cpScalar": 0.3492127
 },
 {
  "level": 14,
  "dust": 800,
  "candy": 1,
  "cpScalar": 0.3624578
 },
 {
  "level": 15,
  "dust": 800,
  "candy": 1,
  "cpScalar": 0.3752356
 },
 {
  "level": 16,
  "dust": 800,
  "candy": 1,
  "cpScalar": 0.3875924
 },
 {
  "level": 17,
  "dust": 1000,
  "candy": 1,
  "cpScalar": 0.3995673
 },
 {
  "level": 18,
  "dust": 1000,
  "candy": 1,
  "cpScalar": 0.4111936
 },
 {
  "level": 19,
  "dust": 1000,
  "candy": 1,
  "cpScalar": 0.4225
 },
 {
  "level": 20,
  "dust": 1000,
  "candy": 1,
  "cpScalar": 0.4335117
 },
 {
  "level": 21,
  "dust": 1300,
  "candy": 2,
  "cpScalar": 0.4431076
 },
 {
  "level": 22,
  "dust": 1300,
  "candy": 2,
  "cpScalar": 0.45306
 },
 {
  "level": 23,
  "dust": 1300,
  "candy": 2,
  "cpScalar": 0.4627984
 },
 {
  "level": 24,
  "dust": 1300,
  "candy": 2,
  "cpScalar": 0.4723361
 },
 {
  "level": 25,
  "dust": 1600,
  "candy": 2,
  "cpScalar": 0.481685
 },
 {
  "level": 26,
  "dust": 1600,
  "candy": 2,
  "cpScalar": 0.4908558
 },
 {
  "level": 27,
  "dust": 1600,
  "candy": 2,
  "cpScalar": 0.4998584
 },
 {
  "level": 28,
  "dust": 1600,
  "candy": 2,
  "cpScalar": 0.5087018
 },
 {
  "level": 29,
  "dust": 1900,
  "candy": 2,
  "cpScalar": 0.517394
 },
 {
  "level": 30,
  "dust": 1900,
  "candy": 2,
  "cpScalar": 0.5259425
 },
 {
  "level": 31,
  "dust": 1900,
  "candy": 2,
  "cpScalar": 0.5343543
 },
 {
  "level": 32,
  "dust": 1900,
  "candy": 2,
  "cpScalar": 0.5426358
 },
 {
  "level": 33,
  "dust": 2200,
  "candy": 2,
  "cpScalar": 0.5507927
 },
 {
  "level": 34,
  "dust": 2200,
  "candy": 2,
  "cpScalar": 0.5588306
 },
 {
  "level": 35,
  "dust": 2200,
  "candy": 2,
  "cpScalar": 0.5667545
 },
 {
  "level": 36,
  "dust": 2200,
  "candy": 2,
  "cpScalar": 0.5745692
 },
 {
  "level": 37,
  "dust": 2500,
  "candy": 2,
  "cpScalar": 0.5822789
 },
 {
  "level": 38,
  "dust": 2500,
  "candy": 2,
  "cpScalar": 0.5898879
 },
 {
  "level": 39,
  "dust": 2500,
  "candy": 2,
  "cpScalar": 0.5974
 },
 {
  "level": 40,
  "dust": 2500,
  "candy": 2,
  "cpScalar": 0.6048188
 },
 {
  "level": 41,
  "dust": 3000,
  "candy": 3,
  "cpScalar": 0.6121573
 },
 {
  "level": 42,
  "dust": 3000,
  "candy": 3,
  "cpScalar": 0.6194041
 },
 {
  "level": 43,
  "dust": 3000,
  "candy": 3,
  "cpScalar": 0.6265671
 },
 {
  "level": 44,
  "dust": 3000,
  "candy": 3,
  "cpScalar": 0.6336492
 },
 {
  "level": 45,
  "dust": 3500,
  "candy": 3,
  "cpScalar": 0.640653
 },
 {
  "level": 46,
  "dust": 3500,
  "candy": 3,
  "cpScalar": 0.647581
 },
 {
  "level": 47,
  "dust": 3500,
  "candy": 3,
  "cpScalar": 0.6544356
 },
 {
  "level": 48,
  "dust": 3500,
  "candy": 3,
  "cpScalar": 0.6612193
 },
 {
  "level": 49,
  "dust": 4000,
  "candy": 3,
  "cpScalar": 0.667934
 },
 {
  "level": 50,
  "dust": 4000,
  "candy": 3,
  "cpScalar": 0.6745819
 },
 {
  "level": 51,
  "dust": 4000,
  "candy": 4,
  "cpScalar": 0.6811649
 },
 {
  "level": 52,
  "dust": 4000,
  "candy": 4,
  "cpScalar": 0.6876849
 },
 {
  "level": 53,
  "dust": 4500,
  "candy": 4,
  "cpScalar": 0.6941437
 },
 {
  "level": 54,
  "dust": 4500,
  "candy": 4,
  "cpScalar": 0.7005429
 },
 {
  "level": 55,
  "dust": 4500,
  "candy": 4,
  "cpScalar": 0.7068842
 },
 {
  "level": 56,
  "dust": 4500,
  "candy": 4,
  "cpScalar": 0.7131691
 },
 {
  "level": 57,
  "dust": 5000,
  "candy": 4,
  "cpScalar": 0.7193991
 },
 {
  "level": 58,
  "dust": 5000,
  "candy": 4,
  "cpScalar": 0.7255756
 },
 {
  "level": 59,
  "dust": 5000,
  "candy": 4,
  "cpScalar": 0.7317
 },
 {
  "level": 60,
  "dust": 5000,
  "candy": 4,
  "cpScalar": 0.734741
 },
 {
  "level": 61,
  "dust": 6000,
  "candy": 6,
  "cpScalar": 0.7377695
 },
 {
  "level": 62,
  "dust": 6000,
  "candy": 6,
  "cpScalar": 0.7407856
 },
 {
  "level": 63,
  "dust": 6000,
  "candy": 6,
  "cpScalar": 0.7437894
 },
 {
  "level": 64,
  "dust": 6000,
  "candy": 6,
  "cpScalar": 0.7467812
 },
 {
  "level": 65,
  "dust": 7000,
  "candy": 8,
  "cpScalar": 0.749761
 },
 {
  "level": 66,
  "dust": 7000,
  "candy": 8,
  "cpScalar": 0.7527291
 },
 {
  "level": 67,
  "dust": 7000,
  "candy": 8,
  "cpScalar": 0.7556855
 },
 {
  "level": 68,
  "dust": 7000,
  "candy": 8,
  "cpScalar": 0.7586304
 },
 {
  "level": 69,
  "dust": 8000,
  "candy": 10,
  "cpScalar": 0.7615638
 },
 {
  "level": 70,
  "dust": 8000,
  "candy": 10,
  "cpScalar": 0.7644861
 },
 {
  "level": 71,
  "dust": 8000,
  "candy": 10,
  "cpScalar": 0.7673972
 },
 {
  "level": 72,
  "dust": 8000,
  "candy": 10,
  "cpScalar": 0.7702973
 },
 {
  "level": 73,
  "dust": 9000,
  "candy": 12,
  "cpScalar": 0.7731865
 },
 {
  "level": 74,
  "dust": 9000,
  "candy": 12,
  "cpScalar": 0.776065
 },
 {
  "level": 75,
  "dust": 9000,
  "candy": 12,
  "cpScalar": 0.7789328
 },
 {
  "level": 76,
  "dust": 9000,
  "candy": 12,
  "cpScalar": 0.7817901
 },
 {
  "level": 77,
  "dust": 10000,
  "candy": 15,
  "cpScalar": 0.784637
 },
 {
  "level": 78,
  "dust": 10000,
  "candy": 15,
  "cpScalar": 0.7874736
 },
 {
  "level": 79,
  "dust": 10000,
  "candy": 15,
  "cpScalar": 0.7903
 },
 {
  "level": 80,
  "dust": 10000,
  "candy": 15,
  "cpScalar": 0.7931164
 }
];

var lookup = {
 byLevel : {},
 byDust : {},
 byCandy : {}
};

_.each(levels, function (data) {
 lookup.byLevel[data.level] = data;
 
 lookup.byDust[data.dust] = lookup.byDust[data.dust] || [];
 lookup.byDust[data.dust].push(data);
 
 lookup.byCandy[data.candy] = lookup.byCandy[data.candy] || [];
 lookup.byCandy[data.candy].push(data);
});


module.exports = {
 allLevels : function () {
  return levels.slice();
 },
 levelsByDust : function (dust) {
  dust = parseInt(dust, 10);
  return lookup.byDust[dust].slice();
 },
 levelsByCandy : function (candy) {
  candy = parseInt(candy, 10);
  return lookup.byCandy[candy].slice();
 }
};

/support/pokedex.js

var _ = require('underscore');

var pokemon = [
 {
  "id": 1,
  "name": "Bulbasaur",
  "stamina": 90,
  "attack": 126,
  "defense": 126
 },
 {
  "id": 2,
  "name": "Ivysaur",
  "stamina": 120,
  "attack": 156,
  "defense": 158
 },
 {
  "id": 3,
  "name": "Venusaur",
  "stamina": 160,
  "attack": 198,
  "defense": 200
 },
 {
  "id": 4,
  "name": "Charmander",
  "stamina": 78,
  "attack": 128,
  "defense": 108
 },
 {
  "id": 5,
  "name": "Charmeleon",
  "stamina": 116,
  "attack": 160,
  "defense": 140
 },
 {
  "id": 6,
  "name": "Charizard",
  "stamina": 156,
  "attack": 212,
  "defense": 182
 },
 {
  "id": 7,
  "name": "Squirtle",
  "stamina": 88,
  "attack": 112,
  "defense": 142
 },
 {
  "id": 8,
  "name": "Wartortle",
  "stamina": 118,
  "attack": 144,
  "defense": 176
 },
 {
  "id": 9,
  "name": "Blastoise",
  "stamina": 158,
  "attack": 186,
  "defense": 222
 },
 {
  "id": 10,
  "name": "Caterpie",
  "stamina": 90,
  "attack": 62,
  "defense": 66
 },
 {
  "id": 11,
  "name": "Metapod",
  "stamina": 100,
  "attack": 56,
  "defense": 86
 },
 {
  "id": 12,
  "name": "Butterfree",
  "stamina": 120,
  "attack": 144,
  "defense": 144
 },
 {
  "id": 13,
  "name": "Weedle",
  "stamina": 80,
  "attack": 68,
  "defense": 64
 },
 {
  "id": 14,
  "name": "Kakuna",
  "stamina": 90,
  "attack": 62,
  "defense": 82
 },
 {
  "id": 15,
  "name": "Beedrill",
  "stamina": 130,
  "attack": 144,
  "defense": 130
 },
 {
  "id": 16,
  "name": "Pidgey",
  "stamina": 80,
  "attack": 94,
  "defense": 90
 },
 {
  "id": 17,
  "name": "Pidgeotto",
  "stamina": 126,
  "attack": 126,
  "defense": 122
 },
 {
  "id": 18,
  "name": "Pidgeot",
  "stamina": 166,
  "attack": 170,
  "defense": 166
 },
 {
  "id": 19,
  "name": "Rattata",
  "stamina": 60,
  "attack": 92,
  "defense": 86
 },
 {
  "id": 20,
  "name": "Raticate",
  "stamina": 110,
  "attack": 146,
  "defense": 150
 },
 {
  "id": 21,
  "name": "Spearow",
  "stamina": 80,
  "attack": 102,
  "defense": 78
 },
 {
  "id": 22,
  "name": "Fearow",
  "stamina": 130,
  "attack": 168,
  "defense": 146
 },
 {
  "id": 23,
  "name": "Ekans",
  "stamina": 70,
  "attack": 112,
  "defense": 112
 },
 {
  "id": 24,
  "name": "Arbok",
  "stamina": 120,
  "attack": 166,
  "defense": 166
 },
 {
  "id": 25,
  "name": "Pikachu",
  "stamina": 70,
  "attack": 124,
  "defense": 108
 },
 {
  "id": 26,
  "name": "Raichu",
  "stamina": 120,
  "attack": 200,
  "defense": 154
 },
 {
  "id": 27,
  "name": "Sandshrew",
  "stamina": 100,
  "attack": 90,
  "defense": 114
 },
 {
  "id": 28,
  "name": "Sandslash",
  "stamina": 150,
  "attack": 150,
  "defense": 172
 },
 {
  "id": 29,
  "name": "Nidoran_female",
  "stamina": 110,
  "attack": 100,
  "defense": 104
 },
 {
  "id": 30,
  "name": "Nidorina",
  "stamina": 140,
  "attack": 132,
  "defense": 136
 },
 {
  "id": 31,
  "name": "Nidoqueen",
  "stamina": 180,
  "attack": 184,
  "defense": 190
 },
 {
  "id": 32,
  "name": "Nidoran_male",
  "stamina": 92,
  "attack": 110,
  "defense": 94
 },
 {
  "id": 33,
  "name": "Nidorino",
  "stamina": 122,
  "attack": 142,
  "defense": 128
 },
 {
  "id": 34,
  "name": "Nidoking",
  "stamina": 162,
  "attack": 204,
  "defense": 170
 },
 {
  "id": 35,
  "name": "Clefairy",
  "stamina": 140,
  "attack": 116,
  "defense": 124
 },
 {
  "id": 36,
  "name": "Clefable",
  "stamina": 190,
  "attack": 178,
  "defense": 178
 },
 {
  "id": 37,
  "name": "Vulpix",
  "stamina": 76,
  "attack": 106,
  "defense": 118
 },
 {
  "id": 38,
  "name": "Ninetales",
  "stamina": 146,
  "attack": 176,
  "defense": 194
 },
 {
  "id": 39,
  "name": "Jigglypuff",
  "stamina": 230,
  "attack": 98,
  "defense": 54
 },
 {
  "id": 40,
  "name": "Wigglytuff",
  "stamina": 280,
  "attack": 168,
  "defense": 108
 },
 {
  "id": 41,
  "name": "Zubat",
  "stamina": 80,
  "attack": 88,
  "defense": 90
 },
 {
  "id": 42,
  "name": "Golbat",
  "stamina": 150,
  "attack": 164,
  "defense": 164
 },
 {
  "id": 43,
  "name": "Oddish",
  "stamina": 90,
  "attack": 134,
  "defense": 130
 },
 {
  "id": 44,
  "name": "Gloom",
  "stamina": 120,
  "attack": 162,
  "defense": 158
 },
 {
  "id": 45,
  "name": "Vileplume",
  "stamina": 150,
  "attack": 202,
  "defense": 190
 },
 {
  "id": 46,
  "name": "Paras",
  "stamina": 70,
  "attack": 122,
  "defense": 120
 },
 {
  "id": 47,
  "name": "Parasect",
  "stamina": 120,
  "attack": 162,
  "defense": 170
 },
 {
  "id": 48,
  "name": "Venonat",
  "stamina": 120,
  "attack": 108,
  "defense": 118
 },
 {
  "id": 49,
  "name": "Venomoth",
  "stamina": 140,
  "attack": 172,
  "defense": 154
 },
 {
  "id": 50,
  "name": "Diglett",
  "stamina": 20,
  "attack": 108,
  "defense": 86
 },
 {
  "id": 51,
  "name": "Dugtrio",
  "stamina": 70,
  "attack": 148,
  "defense": 140
 },
 {
  "id": 52,
  "name": "Meowth",
  "stamina": 80,
  "attack": 104,
  "defense": 94
 },
 {
  "id": 53,
  "name": "Persian",
  "stamina": 130,
  "attack": 156,
  "defense": 146
 },
 {
  "id": 54,
  "name": "Psyduck",
  "stamina": 100,
  "attack": 132,
  "defense": 112
 },
 {
  "id": 55,
  "name": "Golduck",
  "stamina": 160,
  "attack": 194,
  "defense": 176
 },
 {
  "id": 56,
  "name": "Mankey",
  "stamina": 80,
  "attack": 122,
  "defense": 96
 },
 {
  "id": 57,
  "name": "Primeape",
  "stamina": 130,
  "attack": 178,
  "defense": 150
 },
 {
  "id": 58,
  "name": "Growlithe",
  "stamina": 110,
  "attack": 156,
  "defense": 110
 },
 {
  "id": 59,
  "name": "Arcanine",
  "stamina": 180,
  "attack": 230,
  "defense": 180
 },
 {
  "id": 60,
  "name": "Poliwag",
  "stamina": 80,
  "attack": 108,
  "defense": 98
 },
 {
  "id": 61,
  "name": "Poliwhirl",
  "stamina": 130,
  "attack": 132,
  "defense": 132
 },
 {
  "id": 62,
  "name": "Poliwrath",
  "stamina": 180,
  "attack": 180,
  "defense": 202
 },
 {
  "id": 63,
  "name": "Abra",
  "stamina": 50,
  "attack": 110,
  "defense": 76
 },
 {
  "id": 64,
  "name": "Kadabra",
  "stamina": 80,
  "attack": 150,
  "defense": 112
 },
 {
  "id": 65,
  "name": "Alakazam",
  "stamina": 110,
  "attack": 186,
  "defense": 152
 },
 {
  "id": 66,
  "name": "Machop",
  "stamina": 140,
  "attack": 118,
  "defense": 96
 },
 {
  "id": 67,
  "name": "Machoke",
  "stamina": 160,
  "attack": 154,
  "defense": 144
 },
 {
  "id": 68,
  "name": "Machamp",
  "stamina": 180,
  "attack": 198,
  "defense": 180
 },
 {
  "id": 69,
  "name": "Bellsprout",
  "stamina": 100,
  "attack": 158,
  "defense": 78
 },
 {
  "id": 70,
  "name": "Weepinbell",
  "stamina": 130,
  "attack": 190,
  "defense": 110
 },
 {
  "id": 71,
  "name": "Victreebel",
  "stamina": 160,
  "attack": 222,
  "defense": 152
 },
 {
  "id": 72,
  "name": "Tentacool",
  "stamina": 80,
  "attack": 106,
  "defense": 136
 },
 {
  "id": 73,
  "name": "Tentacruel",
  "stamina": 160,
  "attack": 170,
  "defense": 196
 },
 {
  "id": 74,
  "name": "Geodude",
  "stamina": 80,
  "attack": 106,
  "defense": 118
 },
 {
  "id": 75,
  "name": "Graveler",
  "stamina": 110,
  "attack": 142,
  "defense": 156
 },
 {
  "id": 76,
  "name": "Golem",
  "stamina": 160,
  "attack": 176,
  "defense": 198
 },
 {
  "id": 77,
  "name": "Ponyta",
  "stamina": 100,
  "attack": 168,
  "defense": 138
 },
 {
  "id": 78,
  "name": "Rapidash",
  "stamina": 130,
  "attack": 200,
  "defense": 170
 },
 {
  "id": 79,
  "name": "Slowpoke",
  "stamina": 180,
  "attack": 110,
  "defense": 110
 },
 {
  "id": 80,
  "name": "Slowbro",
  "stamina": 190,
  "attack": 184,
  "defense": 198
 },
 {
  "id": 81,
  "name": "Magnemite",
  "stamina": 50,
  "attack": 128,
  "defense": 138
 },
 {
  "id": 82,
  "name": "Magneton",
  "stamina": 100,
  "attack": 186,
  "defense": 180
 },
 {
  "id": 83,
  "name": "Farfetchd",
  "stamina": 104,
  "attack": 138,
  "defense": 132
 },
 {
  "id": 84,
  "name": "Doduo",
  "stamina": 70,
  "attack": 126,
  "defense": 96
 },
 {
  "id": 85,
  "name": "Dodrio",
  "stamina": 120,
  "attack": 182,
  "defense": 150
 },
 {
  "id": 86,
  "name": "Seel",
  "stamina": 130,
  "attack": 104,
  "defense": 138
 },
 {
  "id": 87,
  "name": "Dewgong",
  "stamina": 180,
  "attack": 156,
  "defense": 192
 },
 {
  "id": 88,
  "name": "Grimer",
  "stamina": 160,
  "attack": 124,
  "defense": 110
 },
 {
  "id": 89,
  "name": "Muk",
  "stamina": 210,
  "attack": 180,
  "defense": 188
 },
 {
  "id": 90,
  "name": "Shellder",
  "stamina": 60,
  "attack": 120,
  "defense": 112
 },
 {
  "id": 91,
  "name": "Cloyster",
  "stamina": 100,
  "attack": 196,
  "defense": 196
 },
 {
  "id": 92,
  "name": "Gastly",
  "stamina": 60,
  "attack": 136,
  "defense": 82
 },
 {
  "id": 93,
  "name": "Haunter",
  "stamina": 90,
  "attack": 172,
  "defense": 118
 },
 {
  "id": 94,
  "name": "Gengar",
  "stamina": 120,
  "attack": 204,
  "defense": 156
 },
 {
  "id": 95,
  "name": "Onix",
  "stamina": 70,
  "attack": 90,
  "defense": 186
 },
 {
  "id": 96,
  "name": "Drowzee",
  "stamina": 120,
  "attack": 104,
  "defense": 140
 },
 {
  "id": 97,
  "name": "Hypno",
  "stamina": 170,
  "attack": 162,
  "defense": 196
 },
 {
  "id": 98,
  "name": "Krabby",
  "stamina": 60,
  "attack": 116,
  "defense": 110
 },
 {
  "id": 99,
  "name": "Kingler",
  "stamina": 110,
  "attack": 178,
  "defense": 168
 },
 {
  "id": 100,
  "name": "Voltorb",
  "stamina": 80,
  "attack": 102,
  "defense": 124
 },
 {
  "id": 101,
  "name": "Electrode",
  "stamina": 120,
  "attack": 150,
  "defense": 174
 },
 {
  "id": 102,
  "name": "Exeggcute",
  "stamina": 120,
  "attack": 110,
  "defense": 132
 },
 {
  "id": 103,
  "name": "Exeggutor",
  "stamina": 190,
  "attack": 232,
  "defense": 164
 },
 {
  "id": 104,
  "name": "Cubone",
  "stamina": 100,
  "attack": 102,
  "defense": 150
 },
 {
  "id": 105,
  "name": "Marowak",
  "stamina": 120,
  "attack": 140,
  "defense": 202
 },
 {
  "id": 106,
  "name": "Hitmonlee",
  "stamina": 100,
  "attack": 148,
  "defense": 172
 },
 {
  "id": 107,
  "name": "Hitmonchan",
  "stamina": 100,
  "attack": 138,
  "defense": 204
 },
 {
  "id": 108,
  "name": "Lickitung",
  "stamina": 180,
  "attack": 126,
  "defense": 160
 },
 {
  "id": 109,
  "name": "Koffing",
  "stamina": 80,
  "attack": 136,
  "defense": 142
 },
 {
  "id": 110,
  "name": "Weezing",
  "stamina": 130,
  "attack": 190,
  "defense": 198
 },
 {
  "id": 111,
  "name": "Rhyhorn",
  "stamina": 160,
  "attack": 110,
  "defense": 116
 },
 {
  "id": 112,
  "name": "Rhydon",
  "stamina": 210,
  "attack": 166,
  "defense": 160
 },
 {
  "id": 113,
  "name": "Chansey",
  "stamina": 500,
  "attack": 40,
  "defense": 60
 },
 {
  "id": 114,
  "name": "Tangela",
  "stamina": 130,
  "attack": 164,
  "defense": 152
 },
 {
  "id": 115,
  "name": "Kangaskhan",
  "stamina": 210,
  "attack": 142,
  "defense": 178
 },
 {
  "id": 116,
  "name": "Horsea",
  "stamina": 60,
  "attack": 122,
  "defense": 100
 },
 {
  "id": 117,
  "name": "Seadra",
  "stamina": 110,
  "attack": 176,
  "defense": 150
 },
 {
  "id": 118,
  "name": "Goldeen",
  "stamina": 90,
  "attack": 112,
  "defense": 126
 },
 {
  "id": 119,
  "name": "Seaking",
  "stamina": 160,
  "attack": 172,
  "defense": 160
 },
 {
  "id": 120,
  "name": "Staryu",
  "stamina": 60,
  "attack": 130,
  "defense": 128
 },
 {
  "id": 121,
  "name": "Starmie",
  "stamina": 120,
  "attack": 194,
  "defense": 192
 },
 {
  "id": 122,
  "name": "Mr_mime",
  "stamina": 80,
  "attack": 154,
  "defense": 196
 },
 {
  "id": 123,
  "name": "Scyther",
  "stamina": 140,
  "attack": 176,
  "defense": 180
 },
 {
  "id": 124,
  "name": "Jynx",
  "stamina": 130,
  "attack": 172,
  "defense": 134
 },
 {
  "id": 125,
  "name": "Electabuzz",
  "stamina": 130,
  "attack": 198,
  "defense": 160
 },
 {
  "id": 126,
  "name": "Magmar",
  "stamina": 130,
  "attack": 214,
  "defense": 158
 },
 {
  "id": 127,
  "name": "Pinsir",
  "stamina": 130,
  "attack": 184,
  "defense": 186
 },
 {
  "id": 128,
  "name": "Tauros",
  "stamina": 150,
  "attack": 148,
  "defense": 184
 },
 {
  "id": 129,
  "name": "Magikarp",
  "stamina": 40,
  "attack": 42,
  "defense": 84
 },
 {
  "id": 130,
  "name": "Gyarados",
  "stamina": 190,
  "attack": 192,
  "defense": 196
 },
 {
  "id": 131,
  "name": "Lapras",
  "stamina": 260,
  "attack": 186,
  "defense": 190
 },
 {
  "id": 132,
  "name": "Ditto",
  "stamina": 96,
  "attack": 110,
  "defense": 110
 },
 {
  "id": 133,
  "name": "Eevee",
  "stamina": 110,
  "attack": 114,
  "defense": 128
 },
 {
  "id": 134,
  "name": "Vaporeon",
  "stamina": 260,
  "attack": 186,
  "defense": 168
 },
 {
  "id": 135,
  "name": "Jolteon",
  "stamina": 130,
  "attack": 192,
  "defense": 174
 },
 {
  "id": 136,
  "name": "Flareon",
  "stamina": 130,
  "attack": 238,
  "defense": 178
 },
 {
  "id": 137,
  "name": "Porygon",
  "stamina": 130,
  "attack": 156,
  "defense": 158
 },
 {
  "id": 138,
  "name": "Omanyte",
  "stamina": 70,
  "attack": 132,
  "defense": 160
 },
 {
  "id": 139,
  "name": "Omastar",
  "stamina": 140,
  "attack": 180,
  "defense": 202
 },
 {
  "id": 140,
  "name": "Kabuto",
  "stamina": 60,
  "attack": 148,
  "defense": 142
 },
 {
  "id": 141,
  "name": "Kabutops",
  "stamina": 120,
  "attack": 190,
  "defense": 190
 },
 {
  "id": 142,
  "name": "Aerodactyl",
  "stamina": 160,
  "attack": 182,
  "defense": 162
 },
 {
  "id": 143,
  "name": "Snorlax",
  "stamina": 320,
  "attack": 180,
  "defense": 180
 },
 {
  "id": 144,
  "name": "Articuno",
  "stamina": 180,
  "attack": 198,
  "defense": 242
 },
 {
  "id": 145,
  "name": "Zapdos",
  "stamina": 180,
  "attack": 232,
  "defense": 194
 },
 {
  "id": 146,
  "name": "Moltres",
  "stamina": 180,
  "attack": 242,
  "defense": 194
 },
 {
  "id": 147,
  "name": "Dratini",
  "stamina": 82,
  "attack": 128,
  "defense": 110
 },
 {
  "id": 148,
  "name": "Dragonair",
  "stamina": 122,
  "attack": 170,
  "defense": 152
 },
 {
  "id": 149,
  "name": "Dragonite",
  "stamina": 182,
  "attack": 250,
  "defense": 212
 },
 {
  "id": 150,
  "name": "Mewtwo",
  "stamina": 212,
  "attack": 284,
  "defense": 202
 },
 {
  "id": 151,
  "name": "Mew",
  "stamina": 200,
  "attack": 220,
  "defense": 220
 }
];

const boundsOfInterest = [0, 100, 200];
function boundKeyForValue(value) {
 var key;
 var idx;
 var boundValue;
 var upperValue;
 for (idx = 0; idx < boundsOfInterest.length; idx++) {
  boundValue = boundsOfInterest[idx];
  upperValue = boundsOfInterest[idx + 1];
  if (!upperValue) {
   //We've reached the end
   return boundValue + '+';
  }
  if (value >= boundValue && value < upperValue) {
   return boundValue + '-' + upperValue;
  }
 }
 return key;
}
const boundKeys = _.map(boundsOfInterest, boundKeyForValue);

var lookup = {
 byId : {},
 byName : {},
 byStamina : {},
 byAttack : {},
 byDefense : {},
};

[
 'byStamina',
 'byAttack',
 'byDefense'
].forEach(function (name) {
 var dict = {
  all : {}
 };
 boundKeys.forEach(function (key) {
  dict[key] = [];
 });
 lookup[name] = dict;
});

_.each(pokemon, function (pokeData) {
 lookup.byId[pokeData.id] = pokeData;
 lookup.byName[pokeData.name.toLowerCase()] = pokeData;
 
 lookup.byStamina.all[pokeData.stamina] = lookup.byStamina.all[pokeData.stamina] || [];
 lookup.byStamina.all[pokeData.stamina].push(pokeData);
 lookup.byStamina[boundKeyForValue(pokeData.stamina)].push(pokeData);
 
 lookup.byAttack.all[pokeData.attack] = lookup.byAttack.all[pokeData.attack] || [];
 lookup.byAttack.all[pokeData.attack].push(pokeData);
 lookup.byAttack[boundKeyForValue(pokeData.attack)].push(pokeData);
 
 lookup.byDefense.all[pokeData.defense] = lookup.byDefense.all[pokeData.defense] || [];
 lookup.byDefense.all[pokeData.defense].push(pokeData);
 lookup.byDefense[boundKeyForValue(pokeData.defense)].push(pokeData);
});

module.exports = {
 pokemonByName : function (name) {
  return lookup.byName[(name + '').toLowerCase()];
 },
 pokemonById : function (id) {
  var pokeId = parseInt(id, 10);
  return lookup.byId[pokeId];
 }
};

How to Use Pokemon GO IV Calculator?

const ivCalculator = require('pokemon-go-iv-calculator');

//Ivysaur with CP 608, HP of 69, and dust-upgrade-cost of 1600
const result = ivCalculator.evaluate('Ivysaur', 608, 59, 1600);

/**
 Gives:
{ grade: 
   { minGrade: { letter: 'F', preciseLetter: 'F' },
     maxGrade: { letter: 'D', preciseLetter: 'D' },
     averageGrade: { letter: 'F', preciseLetter: 'F' },
     explanation: 'Between D - F' },
  ivs: 
   [ { attackIV: 15,
       defenseIV: 11,
       staminaIV: 0,
       level: 27,
       perfection: 0.57 },
     { attackIV: 14,
       defenseIV: 13,
       staminaIV: 0,
       level: 27,
       perfection: 0.6 },
     { attackIV: 13,
       defenseIV: 15,
       staminaIV: 0,
       level: 27,
       perfection: 0.62 } ] }

*/
const niceTry = ivCalculator.evaluate('ivysaurus', 608, 59, 1600)

/**
 Gives
{ error: 'Could not find pokemon: ivysaurus' }
*/

Important Note

Pokemon can be any case (upper/lower/mixed), OR you can use pokedex id (e.g. Ivysaur == 2)

There’s an optional fifth argument: Boolean : neverUpgraded. If you’ve never upgraded the pokemon, pass true. This reduces the possible levels the pokemon could be at.

Furqan

Well. I've been working for the past three years as a web designer and developer. I have successfully created websites for small to medium sized companies as part of my freelance career. During that time I've also completed my bachelor's in Information Technology.

Recent Posts

MiniMax-M1 vs GPT-4o vs Claude 3 Opus vs LLaMA 3 Benchmarks

MiniMax-M1 is a new open-weight large language model (456 B parameters, ~46 B active) built with hybrid…

June 22, 2025

How to Use Husky with npm to Manage Git Hooks

Managing Git hooks manually can quickly become tedious and error-prone—especially in fast-moving JavaScript or Node.js…

June 22, 2025

How to Use Lefthook with npm to Manage Git Hooks

Git hooks help teams enforce code quality by automating checks at key stages like commits…

June 22, 2025

Lefthook vs Husky: Which Git Hooks Tool is Better? [2025]

Choosing the right Git hooks manager directly impacts code quality, developer experience, and CI/CD performance.…

June 22, 2025

Llama 3.1 vs GPT-4 Benchmarks

We evaluated the performance of Llama 3.1 vs GPT-4 models on over 150 benchmark datasets…

July 24, 2024

Transforming Manufacturing with Industrial IoT Solutions and Machine Learning

The manufacturing industry is undergoing a significant transformation with the advent of Industrial IoT Solutions.…

July 6, 2024