add 'map' cli command to provide map information (#100)
* add 'map' cli command - provides the following map information functions: - list all available maps in the global registry - display map metadata - update docs with map command examples * add list and info subcommands to map cli command * rename map command list and info factory functions * add --all flag to map info subcommand * handle cmd.Help error
This commit is contained in:
parent
91106aec09
commit
ffeb401377
7 changed files with 177 additions and 0 deletions
|
|
@ -78,6 +78,25 @@ Example creating a 7x7 Standard game with two Battlesnakes:
|
||||||
battlesnake play --width 7 --height 7 --name Snake1 --url http://snake1-url-whatever --name Snake2 --url http://snake2-url-whatever
|
battlesnake play --width 7 --height 7 --name Snake1 --url http://snake1-url-whatever --name Snake2 --url http://snake2-url-whatever
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Maps
|
||||||
|
The `map` command provides map information for use with the `play` command.
|
||||||
|
|
||||||
|
List all available maps using the `list` subcommand:
|
||||||
|
```
|
||||||
|
battlesnake map list
|
||||||
|
```
|
||||||
|
Display map information using the `info` subcommand:
|
||||||
|
```
|
||||||
|
battlesnake map info standard
|
||||||
|
Name: Standard
|
||||||
|
Author: Battlesnake
|
||||||
|
Description: Standard snake placement and food spawning
|
||||||
|
Version: 2
|
||||||
|
Min Players: 1
|
||||||
|
Max Players: 16
|
||||||
|
Board Sizes (WxH): 7x7 9x9 11x11 13x13 15x15 17x17 19x19 21x21 23x23 25x25
|
||||||
|
```
|
||||||
|
|
||||||
### Sample Output
|
### Sample Output
|
||||||
```
|
```
|
||||||
$ battlesnake play --width 3 --height 3 --url http://redacted:4567/ --url http://redacted:4568/ --name Bob --name Sue
|
$ battlesnake play --width 3 --height 3 --url http://redacted:4567/ --url http://redacted:4568/ --name Bob --name Sue
|
||||||
|
|
|
||||||
78
cli/commands/info.go
Normal file
78
cli/commands/info.go
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/BattlesnakeOfficial/rules/maps"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
type mapInfo struct {
|
||||||
|
All bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMapInfoCommand() *cobra.Command {
|
||||||
|
info := mapInfo{}
|
||||||
|
var infoCmd = &cobra.Command{
|
||||||
|
Use: "info [flags] map_name [...map_name]",
|
||||||
|
Short: "Display metadata for given map(s)",
|
||||||
|
Long: "Display metadata for given map(s)",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
// handle --all flag first as there would be no args
|
||||||
|
if info.All {
|
||||||
|
mapList := maps.List()
|
||||||
|
for i, m := range mapList {
|
||||||
|
info.display(m)
|
||||||
|
if i < (len(mapList) - 1) {
|
||||||
|
fmt.Print("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// display help when no map(s) provided via args
|
||||||
|
if len(args) < 1 {
|
||||||
|
err := cmd.Help()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// display all maps via command args
|
||||||
|
for i, m := range args {
|
||||||
|
info.display(m)
|
||||||
|
if i < (len(args) - 1) {
|
||||||
|
fmt.Print("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
infoCmd.Flags().BoolVarP(&info.All, "all", "a", false, "Display information for all maps")
|
||||||
|
|
||||||
|
return infoCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mapInfo) display(id string) {
|
||||||
|
gameMap, err := maps.GetMap(id)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to load game map %#v: %v", id, err)
|
||||||
|
}
|
||||||
|
meta := gameMap.Meta()
|
||||||
|
fmt.Println("Name:", meta.Name)
|
||||||
|
fmt.Println("Author:", meta.Author)
|
||||||
|
fmt.Println("Description:", meta.Description)
|
||||||
|
fmt.Println("Version:", meta.Version)
|
||||||
|
fmt.Println("Min Players:", meta.MinPlayers)
|
||||||
|
fmt.Println("Max Players:", meta.MaxPlayers)
|
||||||
|
fmt.Print("Board Sizes (WxH):")
|
||||||
|
for i, s := range meta.BoardSizes {
|
||||||
|
fmt.Printf(" %dx%d", s.Width, s.Height)
|
||||||
|
if i == (len(meta.BoardSizes) - 1) {
|
||||||
|
fmt.Print("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
22
cli/commands/list.go
Normal file
22
cli/commands/list.go
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/BattlesnakeOfficial/rules/maps"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewMapListCommand() *cobra.Command {
|
||||||
|
var listCmd = &cobra.Command{
|
||||||
|
Use: "list",
|
||||||
|
Short: "List available game maps",
|
||||||
|
Long: "List available game maps",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
for _, m := range maps.List() {
|
||||||
|
fmt.Println(m)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return listCmd
|
||||||
|
}
|
||||||
24
cli/commands/map.go
Normal file
24
cli/commands/map.go
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewMapCommand() *cobra.Command {
|
||||||
|
|
||||||
|
var mapCmd = &cobra.Command{
|
||||||
|
Use: "map",
|
||||||
|
Short: "Display map information",
|
||||||
|
Long: "Display map information",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
err := cmd.Help()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapCmd
|
||||||
|
}
|
||||||
|
|
@ -21,6 +21,12 @@ var rootCmd = &cobra.Command{
|
||||||
func Execute() {
|
func Execute() {
|
||||||
rootCmd.AddCommand(NewPlayCommand())
|
rootCmd.AddCommand(NewPlayCommand())
|
||||||
|
|
||||||
|
mapCommand := NewMapCommand()
|
||||||
|
mapCommand.AddCommand(NewMapListCommand())
|
||||||
|
mapCommand.AddCommand(NewMapInfoCommand())
|
||||||
|
|
||||||
|
rootCmd.AddCommand(mapCommand)
|
||||||
|
|
||||||
if err := rootCmd.Execute(); err != nil {
|
if err := rootCmd.Execute(); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package maps
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"github.com/BattlesnakeOfficial/rules"
|
"github.com/BattlesnakeOfficial/rules"
|
||||||
)
|
)
|
||||||
|
|
@ -21,6 +22,16 @@ func (registry MapRegistry) RegisterMap(id string, m GameMap) {
|
||||||
registry[id] = m
|
registry[id] = m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// List returns all registered map IDs in alphabetical order
|
||||||
|
func (registry MapRegistry) List() []string {
|
||||||
|
var keys []string
|
||||||
|
for k, _ := range registry {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
// GetMap returns the map associated with the given ID.
|
// GetMap returns the map associated with the given ID.
|
||||||
func (registry MapRegistry) GetMap(id string) (GameMap, error) {
|
func (registry MapRegistry) GetMap(id string) (GameMap, error) {
|
||||||
if m, ok := registry[id]; ok {
|
if m, ok := registry[id]; ok {
|
||||||
|
|
@ -34,6 +45,11 @@ func GetMap(id string) (GameMap, error) {
|
||||||
return globalRegistry.GetMap(id)
|
return globalRegistry.GetMap(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// List returns a list of maps registered to the global registry.
|
||||||
|
func List() []string {
|
||||||
|
return globalRegistry.List()
|
||||||
|
}
|
||||||
|
|
||||||
// RegisterMap adds a map to the global registry.
|
// RegisterMap adds a map to the global registry.
|
||||||
func RegisterMap(id string, m GameMap) {
|
func RegisterMap(id string, m GameMap) {
|
||||||
globalRegistry.RegisterMap(id, m)
|
globalRegistry.RegisterMap(id, m)
|
||||||
|
|
|
||||||
|
|
@ -112,3 +112,15 @@ func pickSize(meta Metadata) Dimensions {
|
||||||
// For fixed, just pick the first supported size
|
// For fixed, just pick the first supported size
|
||||||
return meta.BoardSizes[0]
|
return meta.BoardSizes[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestListRegisteredMaps(t *testing.T) {
|
||||||
|
keys := globalRegistry.List()
|
||||||
|
mapCount := 0
|
||||||
|
for k := range globalRegistry {
|
||||||
|
// every registry key should exist in List results
|
||||||
|
require.Contains(t, keys, k)
|
||||||
|
mapCount++
|
||||||
|
}
|
||||||
|
// List should equal number of maps in the global registry
|
||||||
|
require.Equal(t, len(keys), mapCount)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue