Move bearing into proto file
This commit is contained in:
parent
3796ee09a3
commit
4e0e55af88
10 changed files with 281 additions and 306 deletions
|
@ -1,97 +0,0 @@
|
|||
package maths
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Bearing describes a compass direction
|
||||
type Bearing int
|
||||
|
||||
const (
|
||||
// North describes a 0,1 vector
|
||||
North Bearing = iota
|
||||
// NorthEast describes a 1,1 vector
|
||||
NorthEast
|
||||
// East describes a 1,0 vector
|
||||
East
|
||||
// SouthEast describes a 1,-1 vector
|
||||
SouthEast
|
||||
// South describes a 0,-1 vector
|
||||
South
|
||||
// SouthWest describes a -1,-1 vector
|
||||
SouthWest
|
||||
// West describes a -1,0 vector
|
||||
West
|
||||
// NorthWest describes a -1,1 vector
|
||||
NorthWest
|
||||
)
|
||||
|
||||
// bearingString simply describes the strings associated with a direction
|
||||
type bearingString struct {
|
||||
Long string
|
||||
Short string
|
||||
}
|
||||
|
||||
// bearingStrings is the set of strings for each direction
|
||||
var bearingStrings = []bearingString{
|
||||
{"North", "N"},
|
||||
{"NorthEast", "NE"},
|
||||
{"East", "E"},
|
||||
{"SouthEast", "SE"},
|
||||
{"South", "S"},
|
||||
{"SouthWest", "SW"},
|
||||
{"West", "W"},
|
||||
{"NorthWest", "NW"},
|
||||
}
|
||||
|
||||
// String converts a Direction to a String
|
||||
func (d Bearing) String() string {
|
||||
return bearingStrings[d].Long
|
||||
}
|
||||
|
||||
// ShortString converts a Direction to a short string version
|
||||
func (d Bearing) ShortString() string {
|
||||
return bearingStrings[d].Short
|
||||
}
|
||||
|
||||
// BearingFromString gets the Direction from a string
|
||||
func BearingFromString(s string) (Bearing, error) {
|
||||
for i, d := range bearingStrings {
|
||||
if strings.EqualFold(d.Long, s) || strings.EqualFold(d.Short, s) {
|
||||
return Bearing(i), nil
|
||||
}
|
||||
}
|
||||
return -1, fmt.Errorf("unknown bearing: %s", s)
|
||||
}
|
||||
|
||||
var bearingVectors = []Vector{
|
||||
{X: 0, Y: 1}, // N
|
||||
{X: 1, Y: 1}, // NE
|
||||
{X: 1, Y: 0}, // E
|
||||
{X: 1, Y: -1}, // SE
|
||||
{X: 0, Y: -1}, // S
|
||||
{X: -1, Y: -1}, // SW
|
||||
{X: -1, Y: 0}, // W
|
||||
{X: -1, Y: 1}, // NW
|
||||
}
|
||||
|
||||
// Vector converts a Direction to a Vector
|
||||
func (d Bearing) Vector() Vector {
|
||||
return bearingVectors[d]
|
||||
}
|
||||
|
||||
// IsCardinal returns if this is a cardinal (NESW)
|
||||
func (d Bearing) IsCardinal() bool {
|
||||
switch d {
|
||||
case North:
|
||||
fallthrough
|
||||
case East:
|
||||
fallthrough
|
||||
case South:
|
||||
fallthrough
|
||||
case West:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
package maths
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDirection(t *testing.T) {
|
||||
dir := North
|
||||
|
||||
assert.Equal(t, "North", dir.String())
|
||||
assert.Equal(t, "N", dir.ShortString())
|
||||
assert.Equal(t, Vector{X: 0, Y: 1}, dir.Vector())
|
||||
|
||||
dir, err := BearingFromString("N")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, North, dir)
|
||||
|
||||
dir, err = BearingFromString("n")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, North, dir)
|
||||
|
||||
dir, err = BearingFromString("north")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, North, dir)
|
||||
|
||||
dir, err = BearingFromString("NorthWest")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, NorthWest, dir)
|
||||
}
|
|
@ -2,6 +2,8 @@ package maths
|
|||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/mdiluz/rove/proto/roveapi"
|
||||
)
|
||||
|
||||
// Vector desribes a 3D vector
|
||||
|
@ -81,3 +83,19 @@ func Min2(v1 Vector, v2 Vector) Vector {
|
|||
func Max2(v1 Vector, v2 Vector) Vector {
|
||||
return Vector{Max(v1.X, v2.X), Max(v1.Y, v2.Y)}
|
||||
}
|
||||
|
||||
// BearingToVector converts a bearing to a vector
|
||||
func BearingToVector(b roveapi.Bearing) Vector {
|
||||
switch b {
|
||||
case roveapi.Bearing_North:
|
||||
return Vector{Y: 1}
|
||||
case roveapi.Bearing_East:
|
||||
return Vector{X: 1}
|
||||
case roveapi.Bearing_South:
|
||||
return Vector{Y: -1}
|
||||
case roveapi.Bearing_West:
|
||||
return Vector{X: -1}
|
||||
}
|
||||
|
||||
return Vector{}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ type Command struct {
|
|||
Command roveapi.CommandType `json:"command"`
|
||||
|
||||
// Used in the move command
|
||||
Bearing string `json:"bearing,omitempty"`
|
||||
Bearing roveapi.Bearing `json:"bearing,omitempty"`
|
||||
|
||||
// Used in the broadcast command
|
||||
Message []byte `json:"message,omitempty"`
|
||||
|
|
|
@ -21,7 +21,7 @@ func TestCommand_Move(t *testing.T) {
|
|||
assert.NoError(t, err, "Failed to set position for rover")
|
||||
|
||||
// Try the move command
|
||||
moveCommand := Command{Command: roveapi.CommandType_move, Bearing: "N"}
|
||||
moveCommand := Command{Command: roveapi.CommandType_move, Bearing: roveapi.Bearing_North}
|
||||
assert.NoError(t, world.Enqueue(a, moveCommand), "Failed to execute move command")
|
||||
|
||||
// Tick the world
|
||||
|
@ -47,7 +47,7 @@ func TestCommand_Recharge(t *testing.T) {
|
|||
assert.NoError(t, err, "Failed to set position for rover")
|
||||
|
||||
// Move to use up some charge
|
||||
moveCommand := Command{Command: roveapi.CommandType_move, Bearing: "N"}
|
||||
moveCommand := Command{Command: roveapi.CommandType_move, Bearing: roveapi.Bearing_North}
|
||||
assert.NoError(t, world.Enqueue(a, moveCommand), "Failed to queue move command")
|
||||
|
||||
// Tick the world
|
||||
|
|
|
@ -277,7 +277,7 @@ func (w *World) WarpRover(rover string, pos maths.Vector) error {
|
|||
}
|
||||
|
||||
// MoveRover attempts to move a rover in a specific direction
|
||||
func (w *World) MoveRover(rover string, b maths.Bearing) (maths.Vector, error) {
|
||||
func (w *World) MoveRover(rover string, b roveapi.Bearing) (maths.Vector, error) {
|
||||
w.worldMutex.Lock()
|
||||
defer w.worldMutex.Unlock()
|
||||
|
||||
|
@ -293,7 +293,7 @@ func (w *World) MoveRover(rover string, b maths.Bearing) (maths.Vector, error) {
|
|||
i.Charge--
|
||||
|
||||
// Try the new move position
|
||||
newPos := i.Pos.Added(b.Vector())
|
||||
newPos := i.Pos.Added(maths.BearingToVector(b))
|
||||
|
||||
// Get the tile and verify it's empty
|
||||
_, obj := w.Atlas.QueryPosition(newPos)
|
||||
|
@ -426,9 +426,7 @@ func (w *World) Enqueue(rover string, commands ...Command) error {
|
|||
for _, c := range commands {
|
||||
switch c.Command {
|
||||
case roveapi.CommandType_move:
|
||||
if b, err := maths.BearingFromString(c.Bearing); err != nil {
|
||||
return fmt.Errorf("unknown bearing: %s", c.Bearing)
|
||||
} else if !b.IsCardinal() {
|
||||
if c.Bearing == roveapi.Bearing_BearingUnknown {
|
||||
return fmt.Errorf("bearing must be cardinal")
|
||||
}
|
||||
case roveapi.CommandType_broadcast:
|
||||
|
@ -507,9 +505,7 @@ func (w *World) ExecuteCommand(c *Command, rover string) (err error) {
|
|||
|
||||
switch c.Command {
|
||||
case roveapi.CommandType_move:
|
||||
if dir, err := maths.BearingFromString(c.Bearing); err != nil {
|
||||
return err
|
||||
} else if _, err := w.MoveRover(rover, dir); err != nil {
|
||||
if _, err := w.MoveRover(rover, c.Bearing); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ func TestWorld_GetSetMovePosition(t *testing.T) {
|
|||
assert.NoError(t, err, "Failed to set position for rover")
|
||||
assert.Equal(t, pos, newPos, "Failed to correctly set position for rover")
|
||||
|
||||
b := maths.North
|
||||
b := roveapi.Bearing_North
|
||||
newPos, err = world.MoveRover(a, b)
|
||||
assert.NoError(t, err, "Failed to set position for rover")
|
||||
pos.Add(maths.Vector{X: 0, Y: 1})
|
||||
|
@ -223,7 +223,7 @@ func TestWorld_RoverDamage(t *testing.T) {
|
|||
|
||||
world.Atlas.SetObject(maths.Vector{X: 0.0, Y: 1.0}, atlas.Object{Type: roveapi.Object_RockLarge})
|
||||
|
||||
vec, err := world.MoveRover(a, maths.North)
|
||||
vec, err := world.MoveRover(a, roveapi.Bearing_North)
|
||||
assert.NoError(t, err, "Failed to move rover")
|
||||
assert.Equal(t, pos, vec, "Rover managed to move into large rock")
|
||||
|
||||
|
@ -260,7 +260,7 @@ func TestWorld_RoverRepair(t *testing.T) {
|
|||
world.Atlas.SetObject(maths.Vector{X: 0.0, Y: 1.0}, atlas.Object{Type: roveapi.Object_RockLarge})
|
||||
|
||||
// Try and bump into the rock
|
||||
vec, err := world.MoveRover(a, maths.North)
|
||||
vec, err := world.MoveRover(a, roveapi.Bearing_North)
|
||||
assert.NoError(t, err, "Failed to move rover")
|
||||
assert.Equal(t, pos, vec, "Rover managed to move into large rock")
|
||||
|
||||
|
@ -307,13 +307,13 @@ func TestWorld_Charge(t *testing.T) {
|
|||
assert.NoError(t, err, "Failed to get position for rover")
|
||||
|
||||
// Ensure the path ahead is empty
|
||||
world.Atlas.SetTile(initialPos.Added(maths.North.Vector()), roveapi.Tile_Rock)
|
||||
world.Atlas.SetObject(initialPos.Added(maths.North.Vector()), atlas.Object{Type: roveapi.Object_ObjectUnknown})
|
||||
world.Atlas.SetTile(initialPos.Added(maths.BearingToVector(roveapi.Bearing_North)), roveapi.Tile_Rock)
|
||||
world.Atlas.SetObject(initialPos.Added(maths.BearingToVector(roveapi.Bearing_North)), atlas.Object{Type: roveapi.Object_ObjectUnknown})
|
||||
|
||||
// Try and move north (along unblocked path)
|
||||
newPos, err := world.MoveRover(a, maths.North)
|
||||
newPos, err := world.MoveRover(a, roveapi.Bearing_North)
|
||||
assert.NoError(t, err, "Failed to set position for rover")
|
||||
assert.Equal(t, initialPos.Added(maths.North.Vector()), newPos, "Failed to correctly move position for rover")
|
||||
assert.Equal(t, initialPos.Added(maths.BearingToVector(roveapi.Bearing_North)), newPos, "Failed to correctly move position for rover")
|
||||
|
||||
// Ensure rover lost charge
|
||||
rover, err := world.GetRover(a)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue