From 7fb09a12fd4e12d5d518676a2a92ae1113857f38 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn Date: Wed, 29 Jul 2026 06:52:44 -0500 Subject: [PATCH] feat: added catch, inspect, and pokedex commands --- commands.go | 124 ++++++++++++++++++++++++++++++++++--- internal/pokeapi/client.go | 58 ++++++++++++++++- 2 files changed, 171 insertions(+), 11 deletions(-) diff --git a/commands.go b/commands.go index afe5dbb..53bec17 100644 --- a/commands.go +++ b/commands.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "math/rand" "os" "sort" "time" @@ -11,11 +12,12 @@ import ( ) type context struct { - commands map[string]cliCommand - client *pokeapi.Client - prevOffset int - nextOffset int - args []string + commands map[string]cliCommand + client *pokeapi.Client + prevOffset int + nextOffset int + args []string + caughtPokemon map[string]pokeapi.Pokemon } func (r *context) register(c cliCommand) { @@ -55,11 +57,31 @@ func NewContext() *context { callback: commandExplore, } + catchCommand := cliCommand{ + name: "catch", + description: "Attempt to catch pokemon with given name", + callback: commandCatch, + } + + inspectCommand := cliCommand{ + name: "inspect", + description: "Inspect information about pokemon with given name if caught", + callback: commandInspect, + } + + pokedexCommand := cliCommand{ + name: "pokedex", + description: "Display the names of all pokemon you've caught", + callback: commandPokedex, + } + c := &context{ - commands: map[string]cliCommand{}, - client: pokeapi.NewClient(pokecache.NewCache(5 * time.Second)), - prevOffset: 0, - nextOffset: 0, + commands: map[string]cliCommand{}, + client: pokeapi.NewClient(pokecache.NewCache(5 * time.Second)), + prevOffset: 0, + nextOffset: 0, + args: []string{}, + caughtPokemon: map[string]pokeapi.Pokemon{}, } c.register(exitCommand) @@ -67,6 +89,9 @@ func NewContext() *context { c.register(mapCommand) c.register(mapBackCommand) c.register(exploreCommand) + c.register(catchCommand) + c.register(inspectCommand) + c.register(pokedexCommand) return c } @@ -165,3 +190,84 @@ func commandExplore(c *context) error { return nil } + +func commandCatch(c *context) error { + // TODO: Probably want to allow user to decide + // if they want to catch a pokemon they've + // already caught. Maybe present xp of current + // vs encountered then let them choose. + + if len(c.args) < 1 { + fmt.Println("Please provide pokemon name. i.e. catch ") + return nil + } + + pokemon, err := c.client.Pokemon.Get(c.args[0]) + + if err != nil { + return err + } + + fmt.Printf("Throwing a Pokeball at %s...\n", pokemon.Name) + + roll := rand.Intn(100) + baseChance := 75.0 + pokemonXpMinValue := 0 + pokemonXpMaxValue := 1000 + pokemonXp := min(max(pokemon.BaseExperience, pokemonXpMinValue), pokemonXpMaxValue) + + modifier := int(float64(pokemonXp) / float64(pokemonXpMaxValue) * float64(baseChance)) + chance := int(baseChance) - modifier + + if roll > chance { + c.caughtPokemon[pokemon.Name] = pokemon + fmt.Printf("You caught %s!\n", pokemon.Name) + } else { + fmt.Printf("%s was able to break free!\n", pokemon.Name) + } + + return nil +} + +func commandInspect(c *context) error { + if len(c.args) < 1 { + fmt.Println("Please provide pokemon name. i.e. inspect ") + return nil + } + + pokemonToInspect := c.args[0] + + pokemon, caught := c.caughtPokemon[pokemonToInspect] + + if !caught { + fmt.Printf("You have not previously caught a %s", pokemonToInspect) + return nil + } + + fmt.Printf("Name: %s\n", pokemon.Name) + fmt.Printf("Height: %d\n", pokemon.Height) + fmt.Printf("Weight: %d\n", pokemon.Weight) + fmt.Println("Stats:") + + for _, stat := range pokemon.Stats { + fmt.Printf(" - %s: %d\n", stat.Stat.Name, stat.BaseStat) + } + + fmt.Println("Types:") + + for _, t := range pokemon.Types { + fmt.Printf(" - %s\n", t.Type.Name) + } + + return nil +} + +func commandPokedex(c *context) error { + fmt.Println("Your Pokedex:") + + for _, pokemon := range c.caughtPokemon { + fmt.Printf(" - %s\n", pokemon.Name) + } + + return nil +} diff --git a/internal/pokeapi/client.go b/internal/pokeapi/client.go index eb9a9eb..c800d14 100644 --- a/internal/pokeapi/client.go +++ b/internal/pokeapi/client.go @@ -19,6 +19,7 @@ type Client struct { cache *pokecache.Cache Locations *locationsEndpoint + Pokemon *pokemonEndpoint } func NewClient(cache *pokecache.Cache) *Client { @@ -29,6 +30,7 @@ func NewClient(cache *pokecache.Cache) *Client { } c.Locations = &locationsEndpoint{client: c, path: "/location-area"} + c.Pokemon = &pokemonEndpoint{client: c, path: "/pokemon"} return c } @@ -160,12 +162,12 @@ type Location struct { Url string `json:"url"` } -type Pokemon struct { +type EncounteredPokemon struct { Name string `json:"name"` } type PokemonEncounter struct { - Pokemon Pokemon `json:"pokemon"` + Pokemon EncounteredPokemon `json:"pokemon"` } type LocationArea struct { @@ -220,3 +222,55 @@ func (le *locationsEndpoint) List(offset int) (Page[Location], error) { return page, nil } + +type Stat struct { + Name string `json:"name"` +} + +type PokemonStat struct { + BaseStat int `json:"base_stat"` + Effort int `json:"effort"` + Stat Stat `json:"stat"` +} + +type Type struct { + Name string `json:"name"` +} + +type PokemonType struct { + Type Type `json:"type"` +} + +type Pokemon struct { + Id int `json:"id"` + Name string `json:"name"` + Height int `json:"height"` + Weight int `json:"weight"` + Stats []PokemonStat `json:"stats"` + Types []PokemonType `json:"types"` + BaseExperience int `json:"base_experience"` +} + +type pokemonEndpoint struct { + path string + client *Client +} + +func (pe *pokemonEndpoint) Get(name string) (Pokemon, error) { + var pokemon Pokemon + + requestUrl := fmt.Sprintf("%s/%s", pe.path, name) + req, err := pe.client.NewRequest(http.MethodGet, requestUrl, map[string]string{}, nil) + + if err != nil { + return pokemon, err + } + + err = pe.client.doWithJsonResponse(req, &pokemon) + + if err != nil { + return pokemon, err + } + + return pokemon, nil +}