Convert bearings to compass points and locations to int coords

This commit is contained in:
Marc Di Luzio 2020-06-05 16:37:52 +01:00
parent ae369715ec
commit be0f4f1aff
10 changed files with 187 additions and 35 deletions

View file

@ -6,7 +6,7 @@ import "github.com/google/uuid"
type Command func() error
// CommandMove will move the rover in question
func (w *World) CommandMove(id uuid.UUID, bearing float64, duration float64) Command {
func (w *World) CommandMove(id uuid.UUID, bearing Direction, duration int) Command {
return func() error {
_, err := w.MoveRover(id, bearing, duration)
return err

View file

@ -20,14 +20,14 @@ func TestCommand_Move(t *testing.T) {
err = world.WarpRover(a, pos)
assert.NoError(t, err, "Failed to set position for rover")
bearing := 0.0
duration := 1.0
bearing := North
duration := 1
// Try the move command
moveCommand := world.CommandMove(a, bearing, duration)
assert.NoError(t, world.Execute(moveCommand), "Failed to execute move command")
newpos, err := world.RoverPosition(a)
assert.NoError(t, err, "Failed to set position for rover")
pos.Add(Vector{0.0, float64(duration) * attribs.Speed}) // We should have moved duration*speed north
pos.Add(Vector{0.0, duration * attribs.Speed}) // We should have moved duration*speed north
assert.Equal(t, pos, newpos, "Failed to correctly set position for rover")
}

View file

@ -1,11 +1,15 @@
package game
import "math"
import (
"fmt"
"math"
"strings"
)
// Vector desribes a 3D vector
type Vector struct {
X float64 `json:"x"`
Y float64 `json:"y"`
X int `json:"x"`
Y int `json:"y"`
}
// Add adds one vector to another
@ -27,7 +31,7 @@ func (v Vector) Negated() Vector {
// Length returns the length of the vector
func (v Vector) Length() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
return math.Sqrt(float64(v.X*v.X + v.Y*v.Y))
}
// Distance returns the distance between two vectors
@ -35,3 +39,76 @@ func (v Vector) Distance(v2 Vector) float64 {
// Negate the two vectors and calciate the length
return v.Added(v2.Negated()).Length()
}
// Multiplied returns the vector multiplied by an int
func (v Vector) Multiplied(val int) Vector {
return Vector{v.X * val, v.Y * val}
}
// Direction describes a compass direction
type Direction int
const (
North Direction = iota
NorthEast
East
SouthEast
South
SouthWest
West
NorthWest
)
// DirectionString simply describes the strings associated with a direction
type DirectionString struct {
Long string
Short string
}
// DirectionStrings is the set of strings for each direction
var DirectionStrings = []DirectionString{
{"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 Direction) String() string {
return DirectionStrings[d].Long
}
// ShortString converts a Direction to a short string version
func (d Direction) ShortString() string {
return DirectionStrings[d].Short
}
// DirectionFromString gets the Direction from a string
func DirectionFromString(s string) (Direction, error) {
for i, d := range DirectionStrings {
if strings.ToLower(d.Long) == strings.ToLower(s) || strings.ToLower(d.Short) == strings.ToLower(s) {
return Direction(i), nil
}
}
return -1, fmt.Errorf("Unknown direction: %s", s)
}
var DirectionVectors = []Vector{
{0, 1}, // N
{1, 1}, // NE
{1, 0}, // E
{1, -1}, // SE
{0, -1}, // S
{-1, 1}, // SW
{-1, 0}, // W
{-1, 1}, // NW
}
// Vector converts a Direction to a Vector
func (d Direction) Vector() Vector {
return DirectionVectors[d]
}

View file

@ -169,3 +169,61 @@ func TestVector_Distance(t *testing.T) {
})
}
}
func TestVector_Multiplied(t *testing.T) {
tests := []struct {
name string
vec Vector
arg int
want Vector
}{
{
name: "Basic multiply 1",
vec: North.Vector(),
arg: 2,
want: Vector{0, 2},
},
{
name: "Basic multiply 2",
vec: NorthWest.Vector(),
arg: -1,
want: SouthEast.Vector(),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
v := Vector{
X: tt.vec.X,
Y: tt.vec.Y,
}
if got := v.Multiplied(tt.arg); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Vector.Multiplied() = %v, want %v", got, tt.want)
}
})
}
}
func TestDirection(t *testing.T) {
dir := North
assert.Equal(t, "North", dir.String())
assert.Equal(t, "N", dir.ShortString())
assert.Equal(t, Vector{0, 1}, dir.Vector())
dir, err := DirectionFromString("N")
assert.NoError(t, err)
assert.Equal(t, North, dir)
dir, err = DirectionFromString("n")
assert.NoError(t, err)
assert.Equal(t, North, dir)
dir, err = DirectionFromString("north")
assert.NoError(t, err)
assert.Equal(t, North, dir)
dir, err = DirectionFromString("NorthWest")
assert.NoError(t, err)
assert.Equal(t, NorthWest, dir)
}

View file

@ -2,7 +2,6 @@ package game
import (
"fmt"
"math"
"github.com/google/uuid"
)
@ -16,10 +15,10 @@ type World struct {
// RoverAttributes contains attributes of a rover
type RoverAttributes struct {
// Speed represents the Speed that the rover will move per second
Speed float64 `json:"speed"`
Speed int `json:"speed"`
// Range represents the distance the unit's radar can see
Range float64 `json:"range"`
Range int `json:"range"`
}
// Rover describes a single rover in the world
@ -103,16 +102,13 @@ func (w *World) WarpRover(id uuid.UUID, pos Vector) error {
}
// SetPosition sets an rovers position
func (w *World) MoveRover(id uuid.UUID, bearing float64, duration float64) (Vector, error) {
func (w *World) MoveRover(id uuid.UUID, bearing Direction, duration int) (Vector, error) {
if i, ok := w.Rovers[id]; ok {
// Calculate the distance
distance := i.Attributes.Speed * float64(duration)
distance := i.Attributes.Speed * duration
// Calculate the full movement based on the bearing
move := Vector{
X: math.Sin(bearing) * distance,
Y: math.Cos(bearing) * distance,
}
move := bearing.Vector().Multiplied(distance)
// Increment the position by the movement
i.Pos.Add(move)
@ -138,7 +134,7 @@ func (w World) RadarFromRover(id uuid.UUID) (RadarDescription, error) {
// Gather nearby rovers within the range
for _, r2 := range w.Rovers {
if r1.Id != r2.Id && r1.Pos.Distance(r2.Pos) < r1.Attributes.Range {
if r1.Id != r2.Id && r1.Pos.Distance(r2.Pos) < float64(r1.Attributes.Range) {
desc.Rovers = append(desc.Rovers, r2.Pos)
}
}

View file

@ -71,11 +71,11 @@ 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")
bearing := 0.0
duration := 1.0
bearing := North
duration := 1
newpos, err = world.MoveRover(a, bearing, duration)
assert.NoError(t, err, "Failed to set position for rover")
pos.Add(Vector{0, attribs.Speed * float64(duration)}) // We should have move one unit of the speed north
pos.Add(Vector{0, attribs.Speed * duration}) // We should have move one unit of the speed north
assert.Equal(t, pos, newpos, "Failed to correctly move position for rover")
}