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://[email protected]/andromedado/pokemon-go-iv-calculator.git"
  },
  "keywords": [
    "pokemon",
    "pokemongo",
    "ivcalculator",
    "calculator"
  ],
  "author": "Shad Downey <[email protected]>",
  "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.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.