Skip to content

Commit

Permalink
add 'map' cli command to provide map information (#100)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
bcambl authored Aug 9, 2022
1 parent 91106ae commit ffeb401
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 0 deletions.
19 changes: 19 additions & 0 deletions cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```

### 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
```
$ battlesnake play --width 3 --height 3 --url http://redacted:4567/ --url http://redacted:4568/ --name Bob --name Sue
Expand Down
78 changes: 78 additions & 0 deletions cli/commands/info.go
Original file line number Diff line number Diff line change
@@ -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 changes: 22 additions & 0 deletions cli/commands/list.go
Original file line number Diff line number Diff line change
@@ -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 changes: 24 additions & 0 deletions cli/commands/map.go
Original file line number Diff line number Diff line change
@@ -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
}
6 changes: 6 additions & 0 deletions cli/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ var rootCmd = &cobra.Command{
func Execute() {
rootCmd.AddCommand(NewPlayCommand())

mapCommand := NewMapCommand()
mapCommand.AddCommand(NewMapListCommand())
mapCommand.AddCommand(NewMapInfoCommand())

rootCmd.AddCommand(mapCommand)

if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
Expand Down
16 changes: 16 additions & 0 deletions maps/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package maps

import (
"fmt"
"sort"

"github.com/BattlesnakeOfficial/rules"
)
Expand All @@ -21,6 +22,16 @@ func (registry MapRegistry) RegisterMap(id string, m GameMap) {
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.
func (registry MapRegistry) GetMap(id string) (GameMap, error) {
if m, ok := registry[id]; ok {
Expand All @@ -34,6 +45,11 @@ func GetMap(id string) (GameMap, error) {
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.
func RegisterMap(id string, m GameMap) {
globalRegistry.RegisterMap(id, m)
Expand Down
12 changes: 12 additions & 0 deletions maps/registry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,15 @@ func pickSize(meta Metadata) Dimensions {
// For fixed, just pick the first supported size
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)
}

0 comments on commit ffeb401

Please sign in to comment.