Skip to content

Commit

Permalink
Pokemon Hunter (#5426)
Browse files Browse the repository at this point in the history
* Add PokemonHunter task

* Config example
  • Loading branch information
anakin5 authored and solderzzc committed Sep 13, 2016
1 parent a8aed9c commit fbe0507
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 3 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,10 @@ configs/*
!configs/config.json.path.example
!configs/config.json.map.example
!configs/path.example.json
!config.json.campfort.example
!config.json.cluster.example
!config.json.hunter.example
!config.json.optimizer.example
!config.json.campfort.example
!auth.json.example

# Virtualenv folders
Expand Down
25 changes: 25 additions & 0 deletions configs/config.json.hunter.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"tasks": [
{
"type": "PokemonHunter",
"config": {
"enabled": true,
"max_distance": 1500,
"hunt_all": false,
"hunt_vip": true,
"hunt_pokedex": true
}
},
{
"type": "MoveToFort",
"config": {
"enabled": true,
"lure_attraction": true,
"lure_max_distance": 300,
"ignore_item_count": true,
"walker": "PolylineWalker",
"log_interval": 5
}
}
]
}
17 changes: 15 additions & 2 deletions pokemongo_bot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from geopy.geocoders import GoogleV3
from pgoapi import PGoApi
from pgoapi.utilities import f2i, get_cell_ids
from s2sphere import Cell, CellId, LatLng

import cell_workers
from base_task import BaseTask
Expand Down Expand Up @@ -715,27 +716,39 @@ def get_meta_cell(self):
forts = []
wild_pokemons = []
catchable_pokemons = []
nearby_pokemons = []
for cell in cells:
if "forts" in cell and len(cell["forts"]):
forts += cell["forts"]
if "wild_pokemons" in cell and len(cell["wild_pokemons"]):
wild_pokemons += cell["wild_pokemons"]
if "catchable_pokemons" in cell and len(cell["catchable_pokemons"]):
catchable_pokemons += cell["catchable_pokemons"]
if "nearby_pokemons" in cell and len(cell["nearby_pokemons"]):
latlng = LatLng.from_point(Cell(CellId(cell["s2_cell_id"])).get_center())

for p in cell["nearby_pokemons"]:
p["latitude"] = latlng.lat().degrees
p["longitude"] = latlng.lng().degrees
p["s2_cell_id"] = cell["s2_cell_id"]

nearby_pokemons += cell["nearby_pokemons"]

# If there are forts present in the cells sent from the server or we don't yet have any cell data, return all data retrieved
if len(forts) > 1 or not self.cell:
return {
"forts": forts,
"wild_pokemons": wild_pokemons,
"catchable_pokemons": catchable_pokemons
"catchable_pokemons": catchable_pokemons,
"nearby_pokemons": nearby_pokemons
}
# If there are no forts present in the data from the server, keep our existing fort data and only update the pokemon cells.
else:
return {
"forts": self.cell["forts"],
"wild_pokemons": wild_pokemons,
"catchable_pokemons": catchable_pokemons
"catchable_pokemons": catchable_pokemons,
"nearby_pokemons": nearby_pokemons
}

def update_web_location(self, cells=[], lat=None, lng=None, alt=None):
Expand Down
1 change: 1 addition & 0 deletions pokemongo_bot/cell_workers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from move_to_map_pokemon import MoveToMapPokemon
from nickname_pokemon import NicknamePokemon
from pokemon_catch_worker import PokemonCatchWorker
from pokemon_hunter import PokemonHunter
from pokemon_optimizer import PokemonOptimizer
from transfer_pokemon import TransferPokemon
from recycle_items import RecycleItems
Expand Down
156 changes: 156 additions & 0 deletions pokemongo_bot/cell_workers/pokemon_hunter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import time

from geopy.distance import great_circle
from s2sphere import Cell, CellId, LatLng

from pokemongo_bot import inventory
from pokemongo_bot.base_task import BaseTask
from pokemongo_bot.item_list import Item
from pokemongo_bot.walkers.polyline_walker import PolylineWalker
from pokemongo_bot.walkers.step_walker import StepWalker
from pokemongo_bot.worker_result import WorkerResult


class PokemonHunter(BaseTask):
SUPPORTED_TASK_API_VERSION = 1

def __init__(self, bot, config):
super(PokemonHunter, self).__init__(bot, config)

def initialize(self):
self.destination = None
self.walker = None
self.search_cell_id = None
self.search_points = []
self.lost_counter = 0
self.no_log_until = 0

self.config_max_distance = self.config.get("max_distance", 2000)
self.config_hunt_all = self.config.get("hunt_all", False)
self.config_hunt_vip = self.config.get("hunt_vip", True)
self.config_hunt_pokedex = self.config.get("hunt_pokedex", True)

def work(self):
if not self.enabled:
return WorkerResult.SUCCESS

if self.get_pokeball_count() <= 0:
self.destination = None
self.last_cell_id = None
return WorkerResult.SUCCESS

now = time.time()
pokemons = self.get_nearby_pokemons()

if self.destination is None:
worth_pokemons = self.get_worth_pokemons(pokemons)

if len(worth_pokemons) > 0:
self.destination = worth_pokemons[0]
self.lost_counter = 0

self.logger.info("New destination at %(distance).2f meters: %(name)s", self.destination)
self.no_log_until = now + 60

if self.destination["s2_cell_id"] != self.search_cell_id:
self.search_points = self.get_search_points(self.destination["s2_cell_id"])
self.walker = PolylineWalker(self.bot, self.search_points[0][0], self.search_points[0][1])
self.search_cell_id = self.destination["s2_cell_id"]
self.search_points = self.search_points[1:] + self.search_points[:1]
else:
if self.no_log_until < now:
self.logger.info("There is no nearby pokemon worth hunting down [%s]", ", ".join(p["name"] for p in pokemons))
self.no_log_until = now + 120

self.last_cell_id = None

return WorkerResult.SUCCESS

if any(self.destination["encounter_id"] == p["encounter_id"] for p in self.bot.cell["catchable_pokemons"] + self.bot.cell["wild_pokemons"]):
self.destination = None
elif self.walker.step():
if not any(self.destination["encounter_id"] == p["encounter_id"] for p in pokemons):
self.lost_counter += 1
else:
self.lost_counter = 0

if self.lost_counter >= 3:
self.destination = None
else:
self.logger.info("Now searching for %(name)s", self.destination)

self.walker = StepWalker(self.bot, self.search_points[0][0], self.search_points[0][1])
self.search_points = self.search_points[1:] + self.search_points[:1]
elif self.no_log_until < now:
distance = great_circle(self.bot.position, (self.walker.dest_lat, self.walker.dest_lng)).meters
self.logger.info("Moving to destination at %s meters: %s", round(distance, 2), self.destination["name"])
self.no_log_until = now + 30

return WorkerResult.RUNNING

def get_pokeball_count(self):
return sum([inventory.items().get(ball.value).count for ball in [Item.ITEM_POKE_BALL, Item.ITEM_GREAT_BALL, Item.ITEM_ULTRA_BALL]])

def get_nearby_pokemons(self):
radius = self.config_max_distance

pokemons = [p for p in self.bot.cell["nearby_pokemons"] if self.get_distance(self.bot.start_position, p) <= radius]

for pokemon in pokemons:
pokemon["distance"] = self.get_distance(self.bot.position, p)
pokemon["name"] = inventory.pokemons().name_for(pokemon["pokemon_id"])

pokemons.sort(key=lambda p: p["distance"])

return pokemons

def get_worth_pokemons(self, pokemons):
if self.config_hunt_all:
worth_pokemons = pokemons
else:
worth_pokemons = []

if self.config_hunt_vip:
worth_pokemons += [p for p in pokemons if p["name"] in self.bot.config.vips]

if self.config_hunt_pokedex:
worth_pokemons += [p for p in pokemons if (p not in worth_pokemons) and any(not inventory.pokedex().seen(fid) for fid in self.get_family_ids(p))]

worth_pokemons.sort(key=lambda p: inventory.candies().get(p["pokemon_id"]).quantity)

return worth_pokemons

def get_family_ids(self, pokemon):
family_id = inventory.pokemons().data_for(pokemon["pokemon_id"]).first_evolution_id
ids = [family_id]
ids += inventory.pokemons().data_for(family_id).next_evolutions_all[:]

return ids

def get_distance(self, location, pokemon):
return great_circle(location, (pokemon["latitude"], pokemon["longitude"])).meters

def get_search_points(self, cell_id):
points = []

# For cell level 15
for c in Cell(CellId(cell_id)).subdivide():
for cc in c.subdivide():
latlng = LatLng.from_point(cc.get_center())
point = (latlng.lat().degrees, latlng.lng().degrees)
points.append(point)

points[0], points[1] = points[1], points[0]
points[14], points[15] = points[15], points[14]
point = points.pop(2)
points.insert(7, point)
point = points.pop(13)
points.insert(8, point)

closest = min(points, key=lambda p: great_circle(self.bot.position, p).meters)
index = points.index(closest)

return points[index:] + points[:index]

0 comments on commit fbe0507

Please sign in to comment.