Skip to content
This repository has been archived by the owner on Jul 22, 2019. It is now read-only.

Max IV Evolution implementation with hooks for other implementations #444

Open
wants to merge 18 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions config.properties.template
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ timer_walk_to_start_pokestop=-1
# Set profile update timer (Default: 60)
profile_update_timer=60

# Whether to run an evolution strategy every time the profile is updated
auto_evolve=false
# Evolution strategy to use, blank will use max_iv by default
evolution_strategy=

# Minimum IV percentage to keep a pokemon (to ignore IV: use -1)
# between 0 and 100, suggested 80
transfer_iv_threshold=80
Expand Down
14 changes: 10 additions & 4 deletions src/main/kotlin/ink/abb/pogo/scraper/Bot.kt
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class Bot(val api: PokemonGo, val settings: Settings) {
val profile = UpdateProfile()
val catch = CatchOneNearbyPokemon()
val release = ReleasePokemon()
val evolve = EvolvePokemon()
val evolve = Evolve()
val hatchEggs = HatchEggs()
val export = Export()

Expand Down Expand Up @@ -138,8 +138,15 @@ class Bot(val api: PokemonGo, val settings: Settings) {
task(hatchEggs)
if (settings.export.length > 0)
task(export)
if (settings.evolveStackLimit > 0)
task(evolve)
if (settings.autoEvolve) {
// Pausing to not cause too much strain if a bunch or evolves happen at the same time
try {
ctx.pauseWalking.set(true)
task(evolve)
} finally {
ctx.pauseWalking.set(false)
}
}
}

runLoop(TimeUnit.SECONDS.toMillis(5), "BotLoop") {
Expand All @@ -156,7 +163,6 @@ class Bot(val api: PokemonGo, val settings: Settings) {
task(drop)
if (settings.autotransfer)
task(release)

}

runLoop(500, "PokestopLoop") {
Expand Down
9 changes: 8 additions & 1 deletion src/main/kotlin/ink/abb/pogo/scraper/Settings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import POGOProtos.Enums.PokemonIdOuterClass.PokemonId
import POGOProtos.Inventory.Item.ItemIdOuterClass.ItemId
import com.pokegoapi.google.common.geometry.S2LatLng
import ink.abb.pogo.scraper.evolve.EvolutionStrategy
import ink.abb.pogo.scraper.util.Log
import ink.abb.pogo.scraper.util.credentials.*
import java.io.BufferedReader
Expand Down Expand Up @@ -129,7 +130,10 @@ class SettingsParser(val properties: Properties) {

waitTimeMin = getPropertyIfSet("Minimal time to wait", "wait_time_min", defaults.waitTimeMin, String::toInt),

waitTimeMax = getPropertyIfSet("Maximal time to wait", "wait_time_max", defaults.waitTimeMax, String::toInt)
waitTimeMax = getPropertyIfSet("Maximal time to wait", "wait_time_max", defaults.waitTimeMax, String::toInt),

autoEvolve = getPropertyIfSet("Should auto evolve", "auto_evolve", defaults.autoEvolve, String::toBoolean),
evolutionStrategy = getPropertyIfSet("Evolution strategy to use", "evolution_strategy", defaults.evolutionStrategy, String::toString)
)
}

Expand Down Expand Up @@ -254,6 +258,9 @@ data class Settings(

val export: String = "",

val autoEvolve: Boolean = false,
val evolutionStrategy: String = "",

val guiPortSocket: Int = 8001,

var initialMapSize: Int = 9,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package ink.abb.pogo.scraper.evolve

import ink.abb.pogo.scraper.Bot
import ink.abb.pogo.scraper.Context
import ink.abb.pogo.scraper.Settings

interface EvolutionStrategy {
fun evolve(bot: Bot, ctx: Context, settings: Settings)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package ink.abb.pogo.scraper.evolve

import POGOProtos.Enums.PokemonFamilyIdOuterClass
import POGOProtos.Enums.PokemonIdOuterClass
import com.pokegoapi.api.pokemon.Pokemon
import ink.abb.pogo.scraper.Bot
import ink.abb.pogo.scraper.Context
import ink.abb.pogo.scraper.Settings
import ink.abb.pogo.scraper.util.Log
import ink.abb.pogo.scraper.util.pokemon.getIvPercentage

/*
* Evolution strategy that prioritizes maximizing IV, then prioritizes getting to highest evolution
*/
class IvMaximizingStrategy : EvolutionStrategy {

lateinit private var EEVEE_EVOLUTION_DATA: Map<PokemonIdOuterClass.PokemonId, String>

constructor() {
EEVEE_EVOLUTION_DATA = mapOf(
Pair(PokemonIdOuterClass.PokemonId.VAPOREON, "Rainer"),
Pair(PokemonIdOuterClass.PokemonId.FLAREON, "Pyro"),
Pair(PokemonIdOuterClass.PokemonId.JOLTEON, "Sparky")
)
}

override fun evolve(bot: Bot, ctx: Context, settings: Settings) {
val pokemonFamilies = ctx.api.inventories.pokebank.pokemons.groupBy { it.pokemonFamily }

pokemonFamilies.forEach {
var run = true
while (run) {
val pokemon = nextPokemonToEvolve(ctx, settings, it.key)
if (pokemon == null) {
run = false
continue
}

Log.green("Evolving ${pokemon.pokemonId.name} with IV ${pokemon.ivRatio} and ${pokemon.cp}cp")
pokemon.evolve()
}
}
}

fun nextPokemonToEvolve(ctx: Context, settings: Settings, family: PokemonFamilyIdOuterClass.PokemonFamilyId) : Pokemon? {
val candies = ctx.api.inventories.candyjar.getCandies(family)
val pokemonFamily = ctx.api.inventories.pokebank.pokemons.groupBy { it.pokemonFamily }.get(family)

var evolvePriority = pokemonFamily.orEmpty().sortedByDescending { it.ivRatio }
var pokemonToEvolve = evolvePriority[0]

// Highest in family cannot evolve and no others are high enough priority
if (pokemonToEvolve.getIvPercentage() < settings.transferIvThreshold) {
if (pokemonToEvolve.candiesToEvolve == 0) {
return null
}
} else {
val priorityEvolves = evolvePriority.filter { it.ivRatio * 100 >= settings.transferIvThreshold }
pokemonToEvolve = priorityEvolves.find { it.candiesToEvolve > 0 }

if (pokemonToEvolve == null) {
return null
}
}

if (pokemonToEvolve.candiesToEvolve > candies) {
Log.yellow("Would like to evolve ${pokemonToEvolve.pokemonId.name} with IV ${pokemonToEvolve.ivRatio * 100}%,\n" +
"\tbut only have ${candies}/${pokemonToEvolve.candiesToEvolve} candies")
return null
}

if (pokemonToEvolve.pokemonId == PokemonIdOuterClass.PokemonId.EEVEE) {
EEVEE_EVOLUTION_DATA.forEach {
if (ctx.api.inventories.pokedex.getPokedexEntry(it.component1()) == null) {
pokemonToEvolve.renamePokemon(it.component2())
return pokemonToEvolve
}

val current = ctx.api.inventories.pokebank.getPokemonByPokemonId(it.key).sortedByDescending { it.ivRatio }
if (current[0].ivRatio < pokemonToEvolve.ivRatio) {
pokemonToEvolve.renamePokemon(it.component2())
return pokemonToEvolve
}
}
}

return pokemonToEvolve
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* For more information, refer to the LICENSE file in this repositories root directory
*/

package ink.abb.pogo.scraper.tasks
package ink.abb.pogo.scraper.evolve

import POGOProtos.Networking.Responses.ReleasePokemonResponseOuterClass
import com.pokegoapi.api.pokemon.Pokemon
Expand All @@ -20,8 +20,8 @@ import ink.abb.pogo.scraper.util.cachedInventories
import ink.abb.pogo.scraper.util.pokemon.getIv
import ink.abb.pogo.scraper.util.pokemon.getIvPercentage

class EvolvePokemon : Task {
override fun run(bot: Bot, ctx: Context, settings: Settings) {
class XpBatchStrategy : EvolutionStrategy {
override fun evolve(bot: Bot, ctx: Context, settings: Settings) {
//count the current stack of possible evolves
var countEvolveStack = 0
val groupedPokemonForCount = ctx.api.inventories.pokebank.pokemons.groupBy { it.pokemonId }
Expand Down
32 changes: 32 additions & 0 deletions src/main/kotlin/ink/abb/pogo/scraper/tasks/Evolve.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package ink.abb.pogo.scraper.tasks

import ink.abb.pogo.scraper.Bot
import ink.abb.pogo.scraper.Context
import ink.abb.pogo.scraper.Settings
import ink.abb.pogo.scraper.Task
import ink.abb.pogo.scraper.evolve.EvolutionStrategy
import ink.abb.pogo.scraper.evolve.IvMaximizingStrategy
import ink.abb.pogo.scraper.evolve.XpBatchStrategy
import ink.abb.pogo.scraper.util.Log

class Evolve : Task {

private val DEFAULT_EVOLUTION_STRATEGY = "xp_batch"

private val EVOLVE_STRATEGY_MAPPER = mapOf<String, EvolutionStrategy>(
Pair("xp_batch", XpBatchStrategy()),
Pair("max_iv", IvMaximizingStrategy())
)

override fun run(bot: Bot, ctx: Context, settings: Settings) {
if (EVOLVE_STRATEGY_MAPPER.containsKey(settings.evolutionStrategy)) {
EVOLVE_STRATEGY_MAPPER.get(settings.evolutionStrategy)?.evolve(bot, ctx, settings)
} else {
if (settings.evolutionStrategy.isNotBlank()) {
Log.red("Evolution strategy ${settings.evolutionStrategy} does not exist. Not running this task")
} else {
EVOLVE_STRATEGY_MAPPER.get(DEFAULT_EVOLUTION_STRATEGY)?.evolve(bot, ctx, settings)
}
}
}
}
10 changes: 9 additions & 1 deletion src/main/kotlin/ink/abb/pogo/scraper/tasks/ReleasePokemon.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
package ink.abb.pogo.scraper.tasks

import POGOProtos.Networking.Responses.ReleasePokemonResponseOuterClass.ReleasePokemonResponse.Result
import com.pokegoapi.exceptions.AsyncPokemonGoException
import ink.abb.pogo.scraper.Bot
import ink.abb.pogo.scraper.Context
import ink.abb.pogo.scraper.Settings
Expand Down Expand Up @@ -45,7 +46,14 @@ class ReleasePokemon : Task {
if (shouldRelease) {
Log.yellow("Going to transfer ${pokemon.pokemonId.name} with " +
"CP ${pokemon.cp} and IV $ivPercentage%; reason: $reason")
val result = pokemon.transferPokemon()
val result : Result
try {
result = pokemon.transferPokemon()
} catch(e: AsyncPokemonGoException) {
Log.red("Failed to transfer ${pokemon.pokemonId.name} with " +
"CP ${pokemon.cp} and IV $ivPercentage% due to ${e.cause?.message}")
continue
}

if(ctx.pokemonInventoryFullStatus.second.get() && !settings.catchPokemon) {
// Just released a pokemon so the inventory is not full anymore
Expand Down