Compare commits

..

2 commits

155
main.go
View file

@ -5,11 +5,13 @@ import (
"errors" "errors"
"fmt" "fmt"
"maps" "maps"
"math/rand/v2"
"os" "os"
"slices" "slices"
"strings" "strings"
"time" "time"
"codeflow.dananglin.me.uk/apollo/pokedex/internal/api/pokeapi"
"codeflow.dananglin.me.uk/apollo/pokedex/internal/pokeclient" "codeflow.dananglin.me.uk/apollo/pokedex/internal/pokeclient"
) )
@ -18,8 +20,6 @@ type State struct {
Next *string Next *string
} }
var state State
type command struct { type command struct {
name string name string
description string description string
@ -28,6 +28,10 @@ type command struct {
type callbackFunc func(args []string) error type callbackFunc func(args []string) error
type pokedex map[string]pokeapi.Pokemon
var dexter = make(pokedex)
func main() { func main() {
run() run()
} }
@ -38,6 +42,8 @@ func run() {
10*time.Second, 10*time.Second,
) )
var state State
commandMap := map[string]command{ commandMap := map[string]command{
"exit": { "exit": {
name: "exit", name: "exit",
@ -52,18 +58,28 @@ func run() {
"map": { "map": {
name: "map", name: "map",
description: "Displays the next 20 locations in the Pokemon world", description: "Displays the next 20 locations in the Pokemon world",
callback: mapFunc(client), callback: mapFunc(client, &state),
}, },
"mapb": { "mapb": {
name: "map back", name: "map back",
description: "Displays the previous 20 locations in the Pokemon world", description: "Displays the previous 20 locations in the Pokemon world",
callback: mapBFunc(client), callback: mapBFunc(client, &state),
}, },
"explore": { "explore": {
name: "explore", name: "explore",
description: "Lists all the pokemon in a given area", description: "Lists all the Pokemon in a given area",
callback: exploreFunc(client), callback: exploreFunc(client),
}, },
"catch": {
name: "catch",
description: "Catches a Pokemon and adds them to your Pokedex",
callback: catchFunc(client),
},
"inspect": {
name: "inspect",
description: "Inspects a Pokemon from your Pokedex",
callback: inspectFunc(),
},
} }
summaries := summaryMap(commandMap) summaries := summaryMap(commandMap)
@ -137,26 +153,26 @@ func exitFunc(_ []string) error {
return nil return nil
} }
func mapFunc(client *pokeclient.Client) callbackFunc { func mapFunc(client *pokeclient.Client, state *State) callbackFunc {
return func(_ []string) error { return func(_ []string) error {
url := state.Next url := state.Next
if url == nil { if url == nil {
url = new(string) url = new(string)
*url = pokeclient.LocationAreaEndpoint *url = pokeclient.LocationAreaPath
} }
return printResourceList(client, *url) return printResourceList(client, *url, state)
} }
} }
func mapBFunc(client *pokeclient.Client) callbackFunc { func mapBFunc(client *pokeclient.Client, state *State) callbackFunc {
return func(_ []string) error { return func(_ []string) error {
url := state.Previous url := state.Previous
if url == nil { if url == nil {
return fmt.Errorf("no previous locations available") return fmt.Errorf("no previous locations available")
} }
return printResourceList(client, *url) return printResourceList(client, *url, state)
} }
} }
@ -195,7 +211,93 @@ func exploreFunc(client *pokeclient.Client) callbackFunc {
} }
} }
func printResourceList(client *pokeclient.Client, url string) error { func catchFunc(client *pokeclient.Client) callbackFunc {
return func(args []string) error {
if args == nil {
return errors.New("the name of the Pokemon has not been specified")
}
if len(args) != 1 {
return fmt.Errorf(
"unexpected number of Pokemon names: want 1; got %d",
len(args),
)
}
pokemonName := args[0]
fmt.Printf("Throwing a Pokeball at %s...\n", pokemonName)
pokemon, err := client.GetPokemon(pokemonName)
if err != nil {
return fmt.Errorf(
"unable to get the information on %s: %w",
pokemonName,
err,
)
}
chance := 50
if caught := catchPokemon(chance); caught {
dexter[pokemonName] = pokemon
fmt.Printf("%s was caught!\n", pokemonName)
} else {
fmt.Printf("%s escaped!\n", pokemonName)
}
return nil
}
}
func inspectFunc() callbackFunc {
return func(args []string) error {
if args == nil {
return errors.New("the name of the Pokemon has not been specified")
}
if len(args) != 1 {
return fmt.Errorf(
"unexpected number of Pokemon names: want 1; got %d",
len(args),
)
}
pokemonName := args[0]
pokemon, ok := dexter[pokemonName]
if !ok {
return fmt.Errorf("you have not caught %s", pokemonName)
}
info := fmt.Sprintf(
"Name: %s\nHeight: %d\nWeight: %d\nStats:",
pokemon.Name,
pokemon.Height,
pokemon.Weight,
)
for _, stat := range slices.All(pokemon.Stats) {
info += fmt.Sprintf(
"\n - %s: %d",
stat.Stat.Name,
stat.BaseStat,
)
}
info += "\nTypes:"
for _, pType := range slices.All(pokemon.Types) {
info += "\n - " + pType.Type.Name
}
fmt.Println(info)
return nil
}
}
func printResourceList(client *pokeclient.Client, url string, state *State) error {
list, err := client.GetNamedAPIResourceList(url) list, err := client.GetNamedAPIResourceList(url)
if err != nil { if err != nil {
return fmt.Errorf("unable to get the list of resources: %w", err) return fmt.Errorf("unable to get the list of resources: %w", err)
@ -234,3 +336,34 @@ func parseArgs(input string) (string, []string) {
return split[0], split[1:] return split[0], split[1:]
} }
func catchPokemon(chance int) bool {
if chance >= 100 {
return true
}
if chance <= 0 {
return false
}
maxInt := 100
numGenerator := rand.New(rand.NewPCG(rand.Uint64(), rand.Uint64()))
luckyNumberSet := make(map[int]struct{})
for len(luckyNumberSet) < chance {
num := numGenerator.IntN(maxInt)
if _, ok := luckyNumberSet[num]; !ok {
luckyNumberSet[num] = struct{}{}
}
}
roller := rand.New(rand.NewPCG(rand.Uint64(), rand.Uint64()))
got := roller.IntN(maxInt)
_, ok := luckyNumberSet[got]
return ok
}