DEV 559: Refactor CLI and add customizations (#57)
* move snake API structs into a new client package * add customizations to snake objects * refactor and add support for passing snake customizations in games
This commit is contained in:
parent
6140f232c2
commit
4a9dbbcaef
10 changed files with 665 additions and 197 deletions
90
client/fixtures_test.go
Normal file
90
client/fixtures_test.go
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
package client
|
||||
|
||||
func exampleSnakeRequest() SnakeRequest {
|
||||
return SnakeRequest{
|
||||
Game: Game{
|
||||
ID: "game-id",
|
||||
Ruleset: Ruleset{
|
||||
Name: "test-ruleset-name",
|
||||
Version: "cli",
|
||||
Settings: exampleRulesetSettings,
|
||||
},
|
||||
Timeout: 33,
|
||||
Source: "league",
|
||||
},
|
||||
Turn: 11,
|
||||
Board: Board{
|
||||
Height: 22,
|
||||
Width: 11,
|
||||
Snakes: []Snake{
|
||||
{
|
||||
ID: "snake-0",
|
||||
Name: "snake-0-name",
|
||||
Latency: "snake-0-latency",
|
||||
Health: 100,
|
||||
Body: []Coord{{X: 1, Y: 2}, {X: 1, Y: 3}, {X: 1, Y: 4}},
|
||||
Head: Coord{X: 1, Y: 2},
|
||||
Length: 3,
|
||||
Shout: "snake-0-shout",
|
||||
Squad: "",
|
||||
Customizations: Customizations{
|
||||
Head: "safe",
|
||||
Tail: "curled",
|
||||
Color: "#123456",
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "snake-1",
|
||||
Name: "snake-1-name",
|
||||
Latency: "snake-1-latency",
|
||||
Health: 200,
|
||||
Body: []Coord{{X: 2, Y: 2}, {X: 2, Y: 3}, {X: 2, Y: 4}},
|
||||
Head: Coord{X: 2, Y: 2},
|
||||
Length: 3,
|
||||
Shout: "snake-1-shout",
|
||||
Squad: "snake-1-squad",
|
||||
Customizations: Customizations{
|
||||
Head: "silly",
|
||||
Tail: "bolt",
|
||||
Color: "#654321",
|
||||
},
|
||||
},
|
||||
},
|
||||
Food: []Coord{{X: 2, Y: 2}},
|
||||
Hazards: []Coord{{X: 8, Y: 8}, {X: 9, Y: 9}},
|
||||
},
|
||||
You: Snake{
|
||||
ID: "snake-1",
|
||||
Name: "snake-1-name",
|
||||
Latency: "snake-1-latency",
|
||||
Health: 200,
|
||||
Body: []Coord{{X: 2, Y: 2}, {X: 2, Y: 3}, {X: 2, Y: 4}},
|
||||
Head: Coord{X: 2, Y: 2},
|
||||
Length: 3,
|
||||
Shout: "snake-1-shout",
|
||||
Squad: "snake-1-squad",
|
||||
Customizations: Customizations{
|
||||
Head: "silly",
|
||||
Tail: "bolt",
|
||||
Color: "#654321",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var exampleRulesetSettings = RulesetSettings{
|
||||
FoodSpawnChance: 10,
|
||||
MinimumFood: 20,
|
||||
HazardDamagePerTurn: 30,
|
||||
|
||||
RoyaleSettings: RoyaleSettings{
|
||||
ShrinkEveryNTurns: 40,
|
||||
},
|
||||
|
||||
SquadSettings: SquadSettings{
|
||||
AllowBodyCollisions: true,
|
||||
SharedElimination: true,
|
||||
SharedHealth: true,
|
||||
SharedLength: true,
|
||||
},
|
||||
}
|
||||
107
client/models.go
Normal file
107
client/models.go
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
package client
|
||||
|
||||
import "github.com/BattlesnakeOfficial/rules"
|
||||
|
||||
// The top-level message sent in /start, /move, and /end requests
|
||||
type SnakeRequest struct {
|
||||
Game Game `json:"game"`
|
||||
Turn int32 `json:"turn"`
|
||||
Board Board `json:"board"`
|
||||
You Snake `json:"you"`
|
||||
}
|
||||
|
||||
// Game represents the current game state
|
||||
type Game struct {
|
||||
ID string `json:"id"`
|
||||
Ruleset Ruleset `json:"ruleset"`
|
||||
Timeout int32 `json:"timeout"`
|
||||
Source string `json:"source"`
|
||||
}
|
||||
|
||||
// Board provides information about the game board
|
||||
type Board struct {
|
||||
Height int32 `json:"height"`
|
||||
Width int32 `json:"width"`
|
||||
Snakes []Snake `json:"snakes"`
|
||||
Food []Coord `json:"food"`
|
||||
Hazards []Coord `json:"hazards"`
|
||||
}
|
||||
|
||||
// Snake represents information about a snake in the game
|
||||
type Snake struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Latency string `json:"latency"`
|
||||
Health int32 `json:"health"`
|
||||
Body []Coord `json:"body"`
|
||||
Head Coord `json:"head"`
|
||||
Length int32 `json:"length"`
|
||||
Shout string `json:"shout"`
|
||||
Squad string `json:"squad"`
|
||||
Customizations Customizations `json:"customizations"`
|
||||
}
|
||||
|
||||
type Customizations struct {
|
||||
Color string `json:"color"`
|
||||
Head string `json:"head"`
|
||||
Tail string `json:"tail"`
|
||||
}
|
||||
|
||||
type Ruleset struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Settings RulesetSettings `json:"settings"`
|
||||
}
|
||||
|
||||
type RulesetSettings struct {
|
||||
FoodSpawnChance int32 `json:"foodSpawnChance"`
|
||||
MinimumFood int32 `json:"minimumFood"`
|
||||
HazardDamagePerTurn int32 `json:"hazardDamagePerTurn"`
|
||||
RoyaleSettings RoyaleSettings `json:"royale"`
|
||||
SquadSettings SquadSettings `json:"squad"`
|
||||
}
|
||||
|
||||
type RoyaleSettings struct {
|
||||
ShrinkEveryNTurns int32 `json:"shrinkEveryNTurns"`
|
||||
}
|
||||
|
||||
type SquadSettings struct {
|
||||
AllowBodyCollisions bool `json:"allowBodyCollisions"`
|
||||
SharedElimination bool `json:"sharedElimination"`
|
||||
SharedHealth bool `json:"sharedHealth"`
|
||||
SharedLength bool `json:"sharedLength"`
|
||||
}
|
||||
|
||||
// Coord represents a point on the board
|
||||
type Coord struct {
|
||||
X int32 `json:"x"`
|
||||
Y int32 `json:"y"`
|
||||
}
|
||||
|
||||
// The expected format of the response body from a /move request
|
||||
type MoveResponse struct {
|
||||
Move string `json:"move"`
|
||||
Shout string `json:"shout"`
|
||||
}
|
||||
|
||||
// The expected format of the response body from a GET request to a Battlesnake's index URL
|
||||
type SnakeMetadataResponse struct {
|
||||
APIVersion string `json:"apiversion,omitempty"`
|
||||
Author string `json:"author,omitempty"`
|
||||
Color string `json:"color,omitempty"`
|
||||
Head string `json:"head,omitempty"`
|
||||
Tail string `json:"tail,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
func CoordFromPoint(pt rules.Point) Coord {
|
||||
return Coord{X: pt.X, Y: pt.Y}
|
||||
}
|
||||
|
||||
func CoordFromPointArray(ptArray []rules.Point) []Coord {
|
||||
a := make([]Coord, 0)
|
||||
for _, pt := range ptArray {
|
||||
a = append(a, CoordFromPoint(pt))
|
||||
}
|
||||
return a
|
||||
}
|
||||
26
client/models_test.go
Normal file
26
client/models_test.go
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/BattlesnakeOfficial/rules/test"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestBuildSnakeRequestJSON(t *testing.T) {
|
||||
snakeRequest := exampleSnakeRequest()
|
||||
data, err := json.MarshalIndent(snakeRequest, "", " ")
|
||||
require.NoError(t, err)
|
||||
|
||||
test.RequireJSONMatchesFixture(t, "testdata/snake_request.json", string(data))
|
||||
}
|
||||
|
||||
func TestBuildSnakeRequestJSONEmptyRulesetSettings(t *testing.T) {
|
||||
snakeRequest := exampleSnakeRequest()
|
||||
snakeRequest.Game.Ruleset.Settings = RulesetSettings{}
|
||||
data, err := json.MarshalIndent(snakeRequest, "", " ")
|
||||
require.NoError(t, err)
|
||||
|
||||
test.RequireJSONMatchesFixture(t, "testdata/snake_request_empty_ruleset_settings.json", string(data))
|
||||
}
|
||||
144
client/testdata/snake_request.json
vendored
Normal file
144
client/testdata/snake_request.json
vendored
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
{
|
||||
"game": {
|
||||
"id": "game-id",
|
||||
"ruleset": {
|
||||
"name": "test-ruleset-name",
|
||||
"version": "cli",
|
||||
"settings": {
|
||||
"foodSpawnChance": 10,
|
||||
"minimumFood": 20,
|
||||
"hazardDamagePerTurn": 30,
|
||||
"royale": {
|
||||
"shrinkEveryNTurns": 40
|
||||
},
|
||||
"squad": {
|
||||
"allowBodyCollisions": true,
|
||||
"sharedElimination": true,
|
||||
"sharedHealth": true,
|
||||
"sharedLength": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"timeout": 33,
|
||||
"source": "league"
|
||||
},
|
||||
"turn": 11,
|
||||
"board": {
|
||||
"height": 22,
|
||||
"width": 11,
|
||||
"snakes": [
|
||||
{
|
||||
"id": "snake-0",
|
||||
"name": "snake-0-name",
|
||||
"latency": "snake-0-latency",
|
||||
"health": 100,
|
||||
"body": [
|
||||
{
|
||||
"x": 1,
|
||||
"y": 2
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 3
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 4
|
||||
}
|
||||
],
|
||||
"head": {
|
||||
"x": 1,
|
||||
"y": 2
|
||||
},
|
||||
"length": 3,
|
||||
"shout": "snake-0-shout",
|
||||
"squad": "",
|
||||
"customizations": {
|
||||
"color": "#123456",
|
||||
"head": "safe",
|
||||
"tail": "curled"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "snake-1",
|
||||
"name": "snake-1-name",
|
||||
"latency": "snake-1-latency",
|
||||
"health": 200,
|
||||
"body": [
|
||||
{
|
||||
"x": 2,
|
||||
"y": 2
|
||||
},
|
||||
{
|
||||
"x": 2,
|
||||
"y": 3
|
||||
},
|
||||
{
|
||||
"x": 2,
|
||||
"y": 4
|
||||
}
|
||||
],
|
||||
"head": {
|
||||
"x": 2,
|
||||
"y": 2
|
||||
},
|
||||
"length": 3,
|
||||
"shout": "snake-1-shout",
|
||||
"squad": "snake-1-squad",
|
||||
"customizations": {
|
||||
"color": "#654321",
|
||||
"head": "silly",
|
||||
"tail": "bolt"
|
||||
}
|
||||
}
|
||||
],
|
||||
"food": [
|
||||
{
|
||||
"x": 2,
|
||||
"y": 2
|
||||
}
|
||||
],
|
||||
"hazards": [
|
||||
{
|
||||
"x": 8,
|
||||
"y": 8
|
||||
},
|
||||
{
|
||||
"x": 9,
|
||||
"y": 9
|
||||
}
|
||||
]
|
||||
},
|
||||
"you": {
|
||||
"id": "snake-1",
|
||||
"name": "snake-1-name",
|
||||
"latency": "snake-1-latency",
|
||||
"health": 200,
|
||||
"body": [
|
||||
{
|
||||
"x": 2,
|
||||
"y": 2
|
||||
},
|
||||
{
|
||||
"x": 2,
|
||||
"y": 3
|
||||
},
|
||||
{
|
||||
"x": 2,
|
||||
"y": 4
|
||||
}
|
||||
],
|
||||
"head": {
|
||||
"x": 2,
|
||||
"y": 2
|
||||
},
|
||||
"length": 3,
|
||||
"shout": "snake-1-shout",
|
||||
"squad": "snake-1-squad",
|
||||
"customizations": {
|
||||
"color": "#654321",
|
||||
"head": "silly",
|
||||
"tail": "bolt"
|
||||
}
|
||||
}
|
||||
}
|
||||
144
client/testdata/snake_request_empty_ruleset_settings.json
vendored
Normal file
144
client/testdata/snake_request_empty_ruleset_settings.json
vendored
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
{
|
||||
"game": {
|
||||
"id": "game-id",
|
||||
"ruleset": {
|
||||
"name": "test-ruleset-name",
|
||||
"version": "cli",
|
||||
"settings": {
|
||||
"foodSpawnChance": 0,
|
||||
"minimumFood": 0,
|
||||
"hazardDamagePerTurn": 0,
|
||||
"royale": {
|
||||
"shrinkEveryNTurns": 0
|
||||
},
|
||||
"squad": {
|
||||
"allowBodyCollisions": false,
|
||||
"sharedElimination": false,
|
||||
"sharedHealth": false,
|
||||
"sharedLength": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"timeout": 33,
|
||||
"source": "league"
|
||||
},
|
||||
"turn": 11,
|
||||
"board": {
|
||||
"height": 22,
|
||||
"width": 11,
|
||||
"snakes": [
|
||||
{
|
||||
"id": "snake-0",
|
||||
"name": "snake-0-name",
|
||||
"latency": "snake-0-latency",
|
||||
"health": 100,
|
||||
"body": [
|
||||
{
|
||||
"x": 1,
|
||||
"y": 2
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 3
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 4
|
||||
}
|
||||
],
|
||||
"head": {
|
||||
"x": 1,
|
||||
"y": 2
|
||||
},
|
||||
"length": 3,
|
||||
"shout": "snake-0-shout",
|
||||
"squad": "",
|
||||
"customizations": {
|
||||
"color": "#123456",
|
||||
"head": "safe",
|
||||
"tail": "curled"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "snake-1",
|
||||
"name": "snake-1-name",
|
||||
"latency": "snake-1-latency",
|
||||
"health": 200,
|
||||
"body": [
|
||||
{
|
||||
"x": 2,
|
||||
"y": 2
|
||||
},
|
||||
{
|
||||
"x": 2,
|
||||
"y": 3
|
||||
},
|
||||
{
|
||||
"x": 2,
|
||||
"y": 4
|
||||
}
|
||||
],
|
||||
"head": {
|
||||
"x": 2,
|
||||
"y": 2
|
||||
},
|
||||
"length": 3,
|
||||
"shout": "snake-1-shout",
|
||||
"squad": "snake-1-squad",
|
||||
"customizations": {
|
||||
"color": "#654321",
|
||||
"head": "silly",
|
||||
"tail": "bolt"
|
||||
}
|
||||
}
|
||||
],
|
||||
"food": [
|
||||
{
|
||||
"x": 2,
|
||||
"y": 2
|
||||
}
|
||||
],
|
||||
"hazards": [
|
||||
{
|
||||
"x": 8,
|
||||
"y": 8
|
||||
},
|
||||
{
|
||||
"x": 9,
|
||||
"y": 9
|
||||
}
|
||||
]
|
||||
},
|
||||
"you": {
|
||||
"id": "snake-1",
|
||||
"name": "snake-1-name",
|
||||
"latency": "snake-1-latency",
|
||||
"health": 200,
|
||||
"body": [
|
||||
{
|
||||
"x": 2,
|
||||
"y": 2
|
||||
},
|
||||
{
|
||||
"x": 2,
|
||||
"y": 3
|
||||
},
|
||||
{
|
||||
"x": 2,
|
||||
"y": 4
|
||||
}
|
||||
],
|
||||
"head": {
|
||||
"x": 2,
|
||||
"y": 2
|
||||
},
|
||||
"length": 3,
|
||||
"shout": "snake-1-shout",
|
||||
"squad": "snake-1-squad",
|
||||
"customizations": {
|
||||
"color": "#654321",
|
||||
"head": "silly",
|
||||
"tail": "bolt"
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue