generated from templates/go-generic
Dan Anglin
4152a9d14f
Add the initial code for the PokeDex project. For now the code can list the next and previous 20 location areas within the Pokemon world.
174 lines
3 KiB
Go
174 lines
3 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"maps"
|
|
"net/http"
|
|
"os"
|
|
"slices"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
baseURL string = "https://pokeapi.co/api/v2"
|
|
locationAreaEndpoint string = "/location-area"
|
|
)
|
|
|
|
type State struct {
|
|
Previous *string
|
|
Next *string
|
|
}
|
|
|
|
var state State
|
|
|
|
type command struct {
|
|
name string
|
|
description string
|
|
callback func() error
|
|
}
|
|
|
|
func main() {
|
|
run()
|
|
}
|
|
|
|
func run() {
|
|
fmt.Print("pokedex > ")
|
|
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
|
|
for scanner.Scan() {
|
|
command := scanner.Text()
|
|
|
|
cmdMap := getCommandMap()
|
|
if _, ok := cmdMap[command]; !ok {
|
|
fmt.Println("ERROR: Unrecognised command.")
|
|
|
|
fmt.Print("\npokedex > ")
|
|
|
|
continue
|
|
}
|
|
|
|
if err := cmdMap[command].callback(); err != nil {
|
|
fmt.Printf("ERROR: %v.\n", err)
|
|
}
|
|
|
|
fmt.Print("pokedex > ")
|
|
}
|
|
}
|
|
|
|
func getCommandMap() map[string]command {
|
|
return map[string]command{
|
|
"exit": {
|
|
name: "exit",
|
|
description: "Exit the Pokedex",
|
|
callback: commandExit,
|
|
},
|
|
"help": {
|
|
name: "help",
|
|
description: "Displays a help message",
|
|
callback: commandHelp,
|
|
},
|
|
"map": {
|
|
name: "map",
|
|
description: "Displays the next 20 locations in the Pokemon world",
|
|
callback: commandMap,
|
|
},
|
|
"mapb": {
|
|
name: "map back",
|
|
description: "Displays the previous 20 locations in the Pokemon world",
|
|
callback: commandMapB,
|
|
},
|
|
}
|
|
}
|
|
|
|
func commandHelp() error {
|
|
cmdMap := getCommandMap()
|
|
|
|
keys := []string{}
|
|
|
|
for key := range maps.All(cmdMap) {
|
|
keys = append(keys, key)
|
|
}
|
|
|
|
slices.Sort(keys)
|
|
|
|
fmt.Printf("\nWelcome to the Pokedex!\nUsage:\n")
|
|
|
|
for _, key := range slices.All(keys) {
|
|
fmt.Printf("\n%s: %s", key, cmdMap[key].description)
|
|
}
|
|
|
|
fmt.Println("\n")
|
|
|
|
return nil
|
|
}
|
|
|
|
func commandExit() error {
|
|
os.Exit(0)
|
|
|
|
return nil
|
|
}
|
|
|
|
func commandMap() error {
|
|
url := state.Next
|
|
if url == nil {
|
|
url = new(string)
|
|
*url = baseURL + locationAreaEndpoint
|
|
}
|
|
|
|
return printMap(*url)
|
|
}
|
|
|
|
func commandMapB() error {
|
|
url := state.Previous
|
|
if url == nil {
|
|
return fmt.Errorf("no previous locations available")
|
|
}
|
|
|
|
return printMap(*url)
|
|
}
|
|
|
|
func printMap(url string) error {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
|
if err != nil {
|
|
return fmt.Errorf("error creating the HTTP request: %w", err)
|
|
}
|
|
|
|
client := http.Client{}
|
|
|
|
resp, err := client.Do(request)
|
|
if err != nil {
|
|
return fmt.Errorf("error getting the response from the server: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode >= 400 {
|
|
return fmt.Errorf(
|
|
"received a bad status from %s: (%d) %s",
|
|
url,
|
|
resp.StatusCode,
|
|
resp.Status,
|
|
)
|
|
}
|
|
|
|
var result NamedAPIResourceList
|
|
|
|
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
|
return fmt.Errorf("unable to decode the JSON response: %w", err)
|
|
}
|
|
|
|
state.Next = result.Next
|
|
state.Previous = result.Previous
|
|
|
|
for _, location := range slices.All(result.Results) {
|
|
fmt.Println(location.Name)
|
|
}
|
|
|
|
return nil
|
|
}
|