package main import ( "fmt" "math/rand" "os" "sort" "time" "github.com/StevanFreeborn/pokedexcli/internal/pokeapi" "github.com/StevanFreeborn/pokedexcli/internal/pokecache" ) type context struct { commands map[string]cliCommand client *pokeapi.Client prevOffset int nextOffset int args []string caughtPokemon map[string]pokeapi.Pokemon } 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, } helpCommand := cliCommand{ name: "help", description: "Displays a help message", callback: commandHelp, } mapCommand := cliCommand{ name: "map", description: "Displays the names of the next 20 location areas", callback: commandMap, } mapBackCommand := cliCommand{ name: "mapb", description: "Displays the names of the previous 20 location areas", callback: commandMapBack, } 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, } 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{}, } c.register(exitCommand) c.register(helpCommand) c.register(mapCommand) c.register(mapBackCommand) c.register(exploreCommand) c.register(catchCommand) c.register(inspectCommand) c.register(pokedexCommand) 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 { 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) } func commandExplore(c *context) error { if len(c.args) < 1 { fmt.Println("Please provide area name. i.e. explore ") 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 ") 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 }