Files
pokedexcli/commands.go
T

274 lines
5.7 KiB
Go
Raw Normal View History

2026-07-26 10:54:19 -05:00
package main
import (
"fmt"
"math/rand"
2026-07-26 10:54:19 -05:00
"os"
"sort"
"time"
"github.com/StevanFreeborn/pokedexcli/internal/pokeapi"
"github.com/StevanFreeborn/pokedexcli/internal/pokecache"
2026-07-26 10:54:19 -05:00
)
type context struct {
commands map[string]cliCommand
client *pokeapi.Client
prevOffset int
nextOffset int
args []string
caughtPokemon map[string]pokeapi.Pokemon
2026-07-26 10:54:19 -05:00
}
func (r *context) register(c cliCommand) {
if c.name != "" {
r.commands[c.name] = c
}
}
func NewContext() *context {
var exitCommand = cliCommand{
name: "exit",
description: "Exit the Pokedex",
callback: commandExit,
}
2026-07-28 08:18:48 -05:00
helpCommand := cliCommand{
2026-07-26 10:54:19 -05:00
name: "help",
description: "Displays a help message",
callback: commandHelp,
}
2026-07-28 08:18:48 -05:00
mapCommand := cliCommand{
name: "map",
description: "Displays the names of the next 20 location areas",
callback: commandMap,
}
2026-07-28 08:18:48 -05:00
mapBackCommand := cliCommand{
name: "mapb",
description: "Displays the names of the previous 20 location areas",
callback: commandMapBack,
}
2026-07-28 08:18:48 -05:00
exploreCommand := cliCommand{
name: "explore",
description: "Displays a list of pokemon in the area",
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,
}
2026-07-26 10:54:19 -05:00
c := &context{
commands: map[string]cliCommand{},
client: pokeapi.NewClient(pokecache.NewCache(5 * time.Second)),
prevOffset: 0,
nextOffset: 0,
args: []string{},
caughtPokemon: map[string]pokeapi.Pokemon{},
2026-07-26 10:54:19 -05:00
}
c.register(exitCommand)
c.register(helpCommand)
c.register(mapCommand)
c.register(mapBackCommand)
2026-07-28 08:18:48 -05:00
c.register(exploreCommand)
c.register(catchCommand)
c.register(inspectCommand)
c.register(pokedexCommand)
2026-07-26 10:54:19 -05:00
return c
}
type commandFunc func(c *context) error
type cliCommand struct {
name string
description string
callback commandFunc
}
func commandExit(c *context) error {
fmt.Println("Closing the Pokedex... Goodbye!")
os.Exit(0)
return nil
}
func commandHelp(c *context) error {
fmt.Println("Welcome to the Pokedex!")
fmt.Println("Usage:")
fmt.Println("")
sortedKeys := []string{}
for k := range c.commands {
sortedKeys = append(sortedKeys, k)
}
sort.Strings(sortedKeys)
for _, key := range sortedKeys {
command := c.commands[key]
fmt.Printf("%s: %s\n", command.name, command.description)
}
return nil
}
func getMaps(c *context, offset int) error {
2026-07-28 08:18:48 -05:00
page, err := c.client.Locations.List(offset)
if err != nil {
fmt.Println("Unable to get locations")
return err
}
c.prevOffset = page.GetPreviousOffset()
c.nextOffset = page.GetNextOffset()
if len(page.Results) == 0 {
fmt.Println("No locations found")
} else {
locationsPerPage := 20
currentPage := (offset / locationsPerPage) + 1
totalPages := page.Count / locationsPerPage
fmt.Printf("Displaying page %d of %d page(s)\n", currentPage, totalPages)
}
for _, location := range page.Results {
fmt.Printf("%s\n", location.Name)
}
return nil
}
func commandMap(c *context) error {
return getMaps(c, c.nextOffset)
}
func commandMapBack(c *context) error {
if c.prevOffset == 0 && (c.nextOffset == 0 || c.nextOffset == 20) {
fmt.Println("You're on the first page")
return nil
}
return getMaps(c, c.prevOffset)
}
2026-07-28 08:18:48 -05:00
func commandExplore(c *context) error {
if len(c.args) < 1 {
fmt.Println("Please provide area name. i.e. explore <area_name>")
return nil
}
area, err := c.client.Locations.Get(c.args[0])
if err != nil {
return err
}
for _, encounter := range area.PokemonEncounters {
fmt.Println(encounter.Pokemon.Name)
}
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 <pokemon_name>")
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 <pokemon_name>")
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
}