Added more functionality to the Pokedex; WIP - add more testing and refactor
This commit is contained in:
parent
f0b303c0c0
commit
f6e8038cdc
63
command_catch.go
Normal file
63
command_catch.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func commandCatch(p *PokedexConfig, a *string) error {
|
||||||
|
if *a == "" {
|
||||||
|
return fmt.Errorf("you need to specify a Pokemon to catch")
|
||||||
|
}
|
||||||
|
var pokemonName string
|
||||||
|
var baseUrl string
|
||||||
|
for _, encounter := range p.LocalPokemons.PokemonEncounters {
|
||||||
|
if encounter.PokemonSummary.Name == *a {
|
||||||
|
pokemonName = *a
|
||||||
|
baseUrl = encounter.PokemonSummary.DataUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if pokemonName == "" {
|
||||||
|
baseUrl = "https://pokeapi.co/api/v2/pokemon/" + *a
|
||||||
|
}
|
||||||
|
// if pokemonName != *a {
|
||||||
|
// fmt.Println("this pokemon is not present in the current area")
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
body, exists := p.Cache.Get(baseUrl)
|
||||||
|
if !exists {
|
||||||
|
client := http.Client{}
|
||||||
|
|
||||||
|
resp, err := client.Get(baseUrl)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not make request to Pokedex API! Err: %w", err)
|
||||||
|
}
|
||||||
|
body, err = io.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode > 299 {
|
||||||
|
return fmt.Errorf("request returned non-200 code! Code: %v Body: %v", resp.StatusCode, body)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not read request body! Err: %w", err)
|
||||||
|
}
|
||||||
|
p.Cache.Add(baseUrl, body)
|
||||||
|
}
|
||||||
|
var pokemon PokemonDetails
|
||||||
|
if err := json.Unmarshal(body, &pokemon); err != nil {
|
||||||
|
return fmt.Errorf("could not unmarshal Pokemon data! err: %w", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Throwing a Pokeball at %s...\n", *a)
|
||||||
|
catchSuccess := rand.Intn(pokemon.BaseExperience)
|
||||||
|
if 2*catchSuccess >= pokemon.BaseExperience {
|
||||||
|
fmt.Printf("%s was caught!\n", pokemon.Name)
|
||||||
|
p.CaughtPokemon = append(p.CaughtPokemon, pokemon)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
fmt.Printf("%s escaped!\n", *a)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -3,10 +3,9 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"k3gtpi.jumpingcrab.com/go-learning/pokedexcli/internal/pokecache"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func commandExit(p *PokedexConfig, c *pokecache.Cache) error {
|
func commandExit(p *PokedexConfig, a *string) error {
|
||||||
fmt.Println("Closing the Pokedex... Goodbye!")
|
fmt.Println("Closing the Pokedex... Goodbye!")
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
43
command_explore.go
Normal file
43
command_explore.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func commandExplore(p *PokedexConfig, a *string) error {
|
||||||
|
if *a == "" {
|
||||||
|
return fmt.Errorf("you need to specify an area to explore")
|
||||||
|
}
|
||||||
|
baseUrl := "https://pokeapi.co/api/v2/location-area/" + *a + "/"
|
||||||
|
body, exists := p.Cache.Get(baseUrl)
|
||||||
|
if !exists {
|
||||||
|
client := http.Client{}
|
||||||
|
|
||||||
|
resp, err := client.Get(baseUrl)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not make request to Pokedex API! Err: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err = io.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode > 299 {
|
||||||
|
return fmt.Errorf("request returned non-200 code! Code: %v Body: %v", resp.StatusCode, body)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not read request body! Err: %w", err)
|
||||||
|
}
|
||||||
|
p.Cache.Add(baseUrl, body)
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(body, &p.LocalPokemons); err != nil {
|
||||||
|
return fmt.Errorf("could not unmarshal response! Err: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pokemon := range p.LocalPokemons.PokemonEncounters {
|
||||||
|
fmt.Println(pokemon.PokemonSummary.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -2,14 +2,12 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"k3gtpi.jumpingcrab.com/go-learning/pokedexcli/internal/pokecache"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func commandHelp(p *PokedexConfig, a *string) error {
|
||||||
func commandHelp(p *PokedexConfig, c *pokecache.Cache) error {
|
|
||||||
fmt.Print("Pokedex CLI - available commands:\n\n")
|
fmt.Print("Pokedex CLI - available commands:\n\n")
|
||||||
for _, v := range getCommands() {
|
for _, v := range getCommands() {
|
||||||
fmt.Printf("%s %s\n", v.name, v.description)
|
fmt.Printf("%s %s\n", v.name, v.description)
|
||||||
}
|
}
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
45
command_inspect.go
Normal file
45
command_inspect.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PokemonInspectOutput struct {
|
||||||
|
Name string
|
||||||
|
Height int
|
||||||
|
Weight int
|
||||||
|
Stats map[string]int
|
||||||
|
Types []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func commandInspect(p *PokedexConfig, a *string) error {
|
||||||
|
found := false
|
||||||
|
for _, pokemon := range p.CaughtPokemon {
|
||||||
|
if pokemon.Name == *a {
|
||||||
|
found = true
|
||||||
|
stats := map[string]int{}
|
||||||
|
types := []string{}
|
||||||
|
for _, pokeStat := range pokemon.PokeStats {
|
||||||
|
stats[pokeStat.PokeStat.Name] = pokeStat.BaseStat
|
||||||
|
}
|
||||||
|
for _, pokeType := range pokemon.PokeTypes {
|
||||||
|
types = append(types, pokeType.PokeType.Name)
|
||||||
|
}
|
||||||
|
pokemonInspectOutput := PokemonInspectOutput{
|
||||||
|
Name: pokemon.Name,
|
||||||
|
Height: pokemon.Height,
|
||||||
|
Weight: pokemon.Weight,
|
||||||
|
Stats: stats,
|
||||||
|
Types: types,
|
||||||
|
}
|
||||||
|
data, _ := yaml.Marshal(pokemonInspectOutput)
|
||||||
|
fmt.Println(string(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
fmt.Println("you have not caught that pokemon")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -1,25 +1,23 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"k3gtpi.jumpingcrab.com/go-learning/pokedexcli/internal/pokecache"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func commandMap(p *PokedexConfig, a *string) error {
|
||||||
func commandMap(p *PokedexConfig, c *pokecache.Cache) error {
|
|
||||||
var baseUrl string
|
var baseUrl string
|
||||||
if p.Next == nil {
|
if p.LocationData.Next == nil {
|
||||||
baseUrl = "https://pokeapi.co/api/v2/location-area/"
|
baseUrl = "https://pokeapi.co/api/v2/location-area/"
|
||||||
} else {
|
} else {
|
||||||
baseUrl = *p.Next
|
baseUrl = *p.LocationData.Next
|
||||||
}
|
}
|
||||||
|
|
||||||
var body []byte
|
var body []byte
|
||||||
// Check if respones is available in cache
|
// Check if respones is available in cache
|
||||||
if resp, exists := c.Get(baseUrl); exists {
|
if resp, exists := p.Cache.Get(baseUrl); exists {
|
||||||
body = resp
|
body = resp
|
||||||
} else {
|
} else {
|
||||||
client := &http.Client{}
|
client := &http.Client{}
|
||||||
@ -29,7 +27,7 @@ func commandMap(p *PokedexConfig, c *pokecache.Cache) error {
|
|||||||
return fmt.Errorf("could not make request to Pokedex API! Err: %w", err)
|
return fmt.Errorf("could not make request to Pokedex API! Err: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
body, err = io.ReadAll(resp.Body)
|
body, err = io.ReadAll(resp.Body)
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
if resp.StatusCode > 299 {
|
if resp.StatusCode > 299 {
|
||||||
return fmt.Errorf("request returned non-200 code! Code: %v Body: %v", resp.StatusCode, body)
|
return fmt.Errorf("request returned non-200 code! Code: %v Body: %v", resp.StatusCode, body)
|
||||||
@ -37,13 +35,13 @@ func commandMap(p *PokedexConfig, c *pokecache.Cache) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not read request body! Err: %w", err)
|
return fmt.Errorf("could not read request body! Err: %w", err)
|
||||||
}
|
}
|
||||||
c.Add(baseUrl, body)
|
p.Cache.Add(baseUrl, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.Unmarshal(body, &p); err != nil {
|
if err := json.Unmarshal(body, &p.LocationData); err != nil {
|
||||||
return fmt.Errorf("could not unmarshal response! Err: %w", err)
|
return fmt.Errorf("could not unmarshal response! Err: %w", err)
|
||||||
}
|
}
|
||||||
for _, location := range p.Results {
|
for _, location := range p.LocationData.Locations {
|
||||||
fmt.Println(location["name"])
|
fmt.Println(location["name"])
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -1,33 +1,32 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"k3gtpi.jumpingcrab.com/go-learning/pokedexcli/internal/pokecache"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func commandMapb(p *PokedexConfig, c *pokecache.Cache) error {
|
func commandMapb(p *PokedexConfig, a *string) error {
|
||||||
var baseUrl string
|
var baseUrl string
|
||||||
if p.Previous == nil {
|
if p.LocationData.Previous == nil {
|
||||||
fmt.Println("you're on the first page")
|
fmt.Println("you're on the first page")
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
baseUrl = *p.Previous
|
baseUrl = *p.LocationData.Previous
|
||||||
}
|
}
|
||||||
var body []byte
|
var body []byte
|
||||||
if resp, exists := c.Get(baseUrl); exists {
|
if resp, exists := p.Cache.Get(baseUrl); exists {
|
||||||
body = resp
|
body = resp
|
||||||
} else {
|
} else {
|
||||||
client := &http.Client{}
|
client := &http.Client{}
|
||||||
|
|
||||||
resp, err := client.Get(baseUrl)
|
resp, err := client.Get(baseUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not make request to Pokedex API! Err: %w", err)
|
return fmt.Errorf("could not make request to Pokedex API! Err: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
body, err = io.ReadAll(resp.Body)
|
body, err = io.ReadAll(resp.Body)
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
if resp.StatusCode > 299 {
|
if resp.StatusCode > 299 {
|
||||||
return fmt.Errorf("request returned non-200 code! Code: %v Body: %v", resp.StatusCode, body)
|
return fmt.Errorf("request returned non-200 code! Code: %v Body: %v", resp.StatusCode, body)
|
||||||
@ -36,12 +35,12 @@ func commandMapb(p *PokedexConfig, c *pokecache.Cache) error {
|
|||||||
return fmt.Errorf("could not read request body! Err: %w", err)
|
return fmt.Errorf("could not read request body! Err: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Add(baseUrl, body)
|
p.Cache.Add(baseUrl, body)
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(body, &p); err != nil {
|
if err := json.Unmarshal(body, &p.LocationData); err != nil {
|
||||||
return fmt.Errorf("could not unmarshal response! Err: %w", err)
|
return fmt.Errorf("could not unmarshal response! Err: %w", err)
|
||||||
}
|
}
|
||||||
for _, location := range p.Results {
|
for _, location := range p.LocationData.Locations {
|
||||||
fmt.Println(location["name"])
|
fmt.Println(location["name"])
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
16
command_pokedex.go
Normal file
16
command_pokedex.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func commandPokedex(p *PokedexConfig, a *string) error {
|
||||||
|
if len(p.CaughtPokemon) == 0 {
|
||||||
|
fmt.Println("Your Pokedex is empty.")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
fmt.Println("Your Pokedex:")
|
||||||
|
for _, pokemon := range p.CaughtPokemon {
|
||||||
|
fmt.Println(" - ", pokemon.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
2
go.mod
2
go.mod
@ -1,3 +1,5 @@
|
|||||||
module k3gtpi.jumpingcrab.com/go-learning/pokedexcli
|
module k3gtpi.jumpingcrab.com/go-learning/pokedexcli
|
||||||
|
|
||||||
go 1.24.5
|
go 1.24.5
|
||||||
|
|
||||||
|
require gopkg.in/yaml.v2 v2.4.0
|
||||||
|
|||||||
4
go.sum
Normal file
4
go.sum
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
@ -1,25 +1,25 @@
|
|||||||
package pokecache
|
package pokecache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type cacheEntry struct {
|
type cacheEntry struct {
|
||||||
createdAt time.Time
|
createdAt time.Time
|
||||||
val []byte
|
val []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type Cache struct {
|
type Cache struct {
|
||||||
PokeCache map[string]cacheEntry
|
PokeCache map[string]cacheEntry
|
||||||
Interval time.Duration
|
Interval time.Duration
|
||||||
Mu sync.Mutex
|
Mu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cache) Add(key string, val []byte) {
|
func (c *Cache) Add(key string, val []byte) {
|
||||||
newEntry := cacheEntry{
|
newEntry := cacheEntry{
|
||||||
createdAt: time.Now(),
|
createdAt: time.Now(),
|
||||||
val: val,
|
val: val,
|
||||||
}
|
}
|
||||||
c.Mu.Lock()
|
c.Mu.Lock()
|
||||||
defer c.Mu.Unlock()
|
defer c.Mu.Unlock()
|
||||||
@ -45,7 +45,7 @@ func (c *Cache) reapLoop() {
|
|||||||
c.Mu.Lock()
|
c.Mu.Lock()
|
||||||
for k, v := range c.PokeCache {
|
for k, v := range c.PokeCache {
|
||||||
if time.Since(v.createdAt) > c.Interval {
|
if time.Since(v.createdAt) > c.Interval {
|
||||||
delete(c.PokeCache, k)
|
delete(c.PokeCache, k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.Mu.Unlock()
|
c.Mu.Unlock()
|
||||||
@ -55,11 +55,9 @@ func (c *Cache) reapLoop() {
|
|||||||
func NewCache(interval time.Duration) *Cache {
|
func NewCache(interval time.Duration) *Cache {
|
||||||
newCache := Cache{
|
newCache := Cache{
|
||||||
PokeCache: map[string]cacheEntry{},
|
PokeCache: map[string]cacheEntry{},
|
||||||
Interval: interval,
|
Interval: interval,
|
||||||
Mu: sync.Mutex{},
|
Mu: sync.Mutex{},
|
||||||
}
|
}
|
||||||
go newCache.reapLoop()
|
go newCache.reapLoop()
|
||||||
return &newCache
|
return &newCache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
package pokecache
|
package pokecache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
"fmt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
func TestAddGet(t *testing.T) {
|
func TestAddGet(t *testing.T) {
|
||||||
const interval = 5 * time.Second
|
const interval = 5 * time.Second
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
@ -54,7 +53,7 @@ func TestReapLoop(t *testing.T) {
|
|||||||
const waitTime = baseTime + 5*time.Millisecond
|
const waitTime = baseTime + 5*time.Millisecond
|
||||||
cache := NewCache(baseTime)
|
cache := NewCache(baseTime)
|
||||||
cache.Add("https://example.com", []byte("testdata"))
|
cache.Add("https://example.com", []byte("testdata"))
|
||||||
|
|
||||||
_, ok := cache.Get("https://example.com")
|
_, ok := cache.Get("https://example.com")
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("expected to find key")
|
t.Errorf("expected to find key")
|
||||||
|
|||||||
132
repl.go
132
repl.go
@ -1,52 +1,106 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"k3gtpi.jumpingcrab.com/go-learning/pokedexcli/internal/pokecache"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"k3gtpi.jumpingcrab.com/go-learning/pokedexcli/internal/pokecache"
|
||||||
)
|
)
|
||||||
|
|
||||||
type cliCommand struct {
|
type cliCommand struct {
|
||||||
name string
|
name string
|
||||||
description string
|
description string
|
||||||
callback func(*PokedexConfig, *pokecache.Cache) error
|
callback func(*PokedexConfig, *string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type PokedexLocationData struct {
|
||||||
|
Next *string `json:"next"`
|
||||||
|
Previous *string `json:"previous"`
|
||||||
|
Locations []map[string]string `json:"results"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PokemonSummary struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
DataUrl string `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PokemonStat struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PokemonStats struct {
|
||||||
|
BaseStat int `json:"base_stat"`
|
||||||
|
PokeStat PokemonStat `json:"stat"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PokemonTypeEntry struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PokemonTypes struct {
|
||||||
|
PokeType PokemonTypeEntry `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PokemonDetails struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
BaseExperience int `json:"base_experience"`
|
||||||
|
Weight int `json:"weight"`
|
||||||
|
Height int `json:"height"`
|
||||||
|
PokeStats []PokemonStats `json:"stats"`
|
||||||
|
PokeTypes []PokemonTypes `json:"types"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PokemonEncounterData struct {
|
||||||
|
PokemonSummary PokemonSummary `json:"pokemon"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PokedexLocalPokemons struct {
|
||||||
|
LocationName string `json:"name"`
|
||||||
|
PokemonEncounters []PokemonEncounterData `json:"pokemon_encounters"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PokedexConfig struct {
|
type PokedexConfig struct {
|
||||||
Next *string
|
Cache *pokecache.Cache
|
||||||
Previous *string
|
LocationData PokedexLocationData
|
||||||
Results []map[string]string
|
LocalPokemons PokedexLocalPokemons
|
||||||
|
CaughtPokemon []PokemonDetails
|
||||||
}
|
}
|
||||||
|
|
||||||
var supportedCommands map[string]cliCommand
|
|
||||||
|
|
||||||
func startRepl() {
|
func startRepl() {
|
||||||
reader := bufio.NewScanner(os.Stdin)
|
reader := bufio.NewScanner(os.Stdin)
|
||||||
fmt.Println("Welcome to the Pokedex!")
|
fmt.Println("Welcome to the Pokedex!")
|
||||||
pokedexConfig := PokedexConfig{}
|
pokedexConfig := PokedexConfig{}
|
||||||
cache := pokecache.NewCache(5 * time.Second)
|
pokedexConfig.Cache = pokecache.NewCache(5 * time.Second)
|
||||||
for {
|
for {
|
||||||
// Print prompt
|
|
||||||
fmt.Printf("Pokedex > ")
|
fmt.Printf("Pokedex > ")
|
||||||
reader.Scan()
|
reader.Scan()
|
||||||
|
|
||||||
words := cleanInput(reader.Text())
|
words := cleanInput(reader.Text())
|
||||||
if len(words) == 0 {
|
if len(words) == 0 {
|
||||||
continue
|
continue
|
||||||
|
} else if len(words) > 2 {
|
||||||
|
fmt.Printf("Commands can only take one argument!")
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
commandName := words[0]
|
commandName := words[0]
|
||||||
|
|
||||||
command, valid := getCommands()[commandName]
|
command, valid := getCommands()[commandName]
|
||||||
if !valid {
|
if !valid {
|
||||||
fmt.Println("Unknown command.")
|
fmt.Println("Unknown command.")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := command.callback(&pokedexConfig, cache); err != nil {
|
|
||||||
fmt.Printf("Encountered error running command: %v\nErr: %v", command.name, err)
|
arg := ""
|
||||||
|
if len(words) == 2 {
|
||||||
|
arg = words[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := command.callback(&pokedexConfig, &arg); err != nil {
|
||||||
|
fmt.Printf("Encountered error running command: %v\nErr: %v\n\n", command.name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,27 +115,47 @@ func cleanInput(text string) []string {
|
|||||||
return words
|
return words
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCommands() map[string]cliCommand{
|
func getCommands() map[string]cliCommand {
|
||||||
return map[string]cliCommand{
|
return map[string]cliCommand{
|
||||||
"help": {
|
"help": {
|
||||||
name: "help",
|
name: "help",
|
||||||
description: "Prints this help menu.",
|
description: "Prints this help menu.",
|
||||||
callback: commandHelp,
|
callback: commandHelp,
|
||||||
},
|
},
|
||||||
"exit": {
|
"exit": {
|
||||||
name: "exit",
|
name: "exit",
|
||||||
description: "Exits the Pokedex",
|
description: "Exits the Pokedex",
|
||||||
callback: commandExit,
|
callback: commandExit,
|
||||||
},
|
},
|
||||||
"map": {
|
"map": {
|
||||||
name: "map",
|
name: "map",
|
||||||
description: "Print Pokemon world locations.",
|
description: "Print Pokemon world locations.",
|
||||||
callback: commandMap,
|
callback: commandMap,
|
||||||
},
|
},
|
||||||
"mapb": {
|
"mapb": {
|
||||||
name: "mapb",
|
name: "mapb",
|
||||||
description: "Print previoud Pokemon locationsi.",
|
description: "Print previous Pokemon locations.",
|
||||||
callback: commandMapb,
|
callback: commandMapb,
|
||||||
|
},
|
||||||
|
"explore": {
|
||||||
|
name: "explore",
|
||||||
|
description: "Print Pokemon found in specified area. Requires AREA_NAME argument.",
|
||||||
|
callback: commandExplore,
|
||||||
|
},
|
||||||
|
"catch": {
|
||||||
|
name: "catch",
|
||||||
|
description: "Attempt to catch a Pokemon present in current area. Requires POKEMON_NAME argument.",
|
||||||
|
callback: commandCatch,
|
||||||
|
},
|
||||||
|
"inspect": {
|
||||||
|
name: "inspect",
|
||||||
|
description: "Inspect a caught Pokemon. Requires POKEMON_NAME argument.",
|
||||||
|
callback: commandInspect,
|
||||||
|
},
|
||||||
|
"pokedex": {
|
||||||
|
name: "pokedex",
|
||||||
|
description: "Inspect the Pokedex contents.",
|
||||||
|
callback: commandPokedex,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
22
repl_test.go
22
repl_test.go
@ -1,26 +1,26 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCleanInput(t * testing.T) {
|
func TestCleanInput(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
input string
|
input string
|
||||||
expected []string
|
expected []string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
input: " hello world ",
|
input: " hello world ",
|
||||||
expected: []string{"hello", "world"},
|
expected: []string{"hello", "world"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "Charmander Bulbasaur PIKACHU",
|
input: "Charmander Bulbasaur PIKACHU",
|
||||||
expected: []string{"charmander", "bulbasaur", "pikachu"},
|
expected: []string{"charmander", "bulbasaur", "pikachu"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "",
|
input: "",
|
||||||
expected: []string{},
|
expected: []string{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
successCount := 0
|
successCount := 0
|
||||||
@ -51,7 +51,7 @@ Output: %v
|
|||||||
Input: %v
|
Input: %v
|
||||||
Expected: %v
|
Expected: %v
|
||||||
Output: %v
|
Output: %v
|
||||||
`, c.input, c.expected, output)
|
`, c.input, c.expected, output)
|
||||||
successCount++
|
successCount++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user