diff --git a/pkg/rove/command_test.go b/pkg/rove/command_test.go index f55c6cb..d73b25c 100644 --- a/pkg/rove/command_test.go +++ b/pkg/rove/command_test.go @@ -3,6 +3,7 @@ package rove import ( "testing" + "github.com/mdiluz/rove/pkg/maths" "github.com/mdiluz/rove/proto/roveapi" "github.com/stretchr/testify/assert" ) @@ -48,17 +49,93 @@ func TestCommand_Turn(t *testing.T) { } func TestCommand_Stash(t *testing.T) { - // TODO: Test the stash command + w := NewWorld(8) + name, err := w.SpawnRover() + assert.NoError(t, err) + + info, err := w.GetRover(name) + assert.NoError(t, err) + assert.Empty(t, info.Inventory) + + // Drop a pickup below us + w.Atlas.SetObject(info.Pos, Object{Type: roveapi.Object_RockSmall}) + + // Try and stash it + err = w.Enqueue(name, &roveapi.Command{Command: roveapi.CommandType_stash}) + assert.NoError(t, err) + w.Tick() + + // Check we now have it in the inventory + info, err = w.GetRover(name) + assert.NoError(t, err) + assert.Equal(t, 1, len(info.Inventory)) + assert.Equal(t, Object{Type: roveapi.Object_RockSmall}, info.Inventory[0]) + + // Check it's no longer on the atlas + _, obj := w.Atlas.QueryPosition(info.Pos) + assert.Equal(t, Object{Type: roveapi.Object_ObjectUnknown}, obj) } func TestCommand_Repair(t *testing.T) { - // TODO: Test the repair command + w := NewWorld(8) + name, err := w.SpawnRover() + assert.NoError(t, err) + + info, err := w.GetRover(name) + assert.NoError(t, err) + assert.Equal(t, info.MaximumIntegrity, info.Integrity) + + // Put a blocking rock to the north + w.Atlas.SetObject(info.Pos.Added(maths.Vector{X: 0, Y: 1}), Object{Type: roveapi.Object_RockLarge}) + + // Try and move and make sure we're blocked + newpos, err := w.TryMoveRover(name, roveapi.Bearing_North) + assert.NoError(t, err) + assert.Equal(t, info.Pos, newpos) + + // Check we're damaged + info, err = w.GetRover(name) + assert.NoError(t, err) + assert.Equal(t, info.MaximumIntegrity-1, info.Integrity) + + // Stash a repair object + w.Atlas.SetObject(info.Pos, Object{Type: roveapi.Object_RockSmall}) + obj, err := w.RoverStash(name) + assert.NoError(t, err) + assert.Equal(t, roveapi.Object_RockSmall, obj) + + // Enqueue the repair and tick + err = w.Enqueue(name, &roveapi.Command{Command: roveapi.CommandType_repair}) + assert.NoError(t, err) + w.Tick() + + // Check we're repaired + info, err = w.GetRover(name) + assert.NoError(t, err) + assert.Equal(t, info.MaximumIntegrity, info.Integrity) + assert.Equal(t, 0, len(info.Inventory)) } func TestCommand_Broadcast(t *testing.T) { - // TODO: Test the stash command + w := NewWorld(8) + name, err := w.SpawnRover() + assert.NoError(t, err) + + // Enqueue the broadcast and tick + err = w.Enqueue(name, &roveapi.Command{Command: roveapi.CommandType_broadcast, Broadcast: []byte("ABC")}) + assert.NoError(t, err) + w.Tick() + + info, err := w.GetRover(name) + assert.NoError(t, err) + assert.Contains(t, info.Logs[len(info.Logs)-1].Text, "ABC") } func TestCommand_Invalid(t *testing.T) { - // TODO: Test an invalid command + w := NewWorld(8) + name, err := w.SpawnRover() + assert.NoError(t, err) + + err = w.Enqueue(name, &roveapi.Command{Command: roveapi.CommandType_none}) + assert.Error(t, err) } diff --git a/pkg/rove/rover.go b/pkg/rove/rover.go index fb13ddc..ce0edcd 100644 --- a/pkg/rove/rover.go +++ b/pkg/rove/rover.go @@ -13,6 +13,10 @@ import ( "github.com/mdiluz/rove/proto/roveapi" ) +const ( + maxLogEntries = 16 +) + // RoverLogEntry describes a single log entry for the rover type RoverLogEntry struct { // Time is the timestamp of the entry @@ -89,6 +93,11 @@ func (r *Rover) AddLogEntryf(format string, args ...interface{}) { Text: text, }, ) + + // Limit the number of logs + if len(r.Logs) > maxLogEntries { + r.Logs = r.Logs[len(r.Logs)-maxLogEntries:] + } } var wordsFile = os.Getenv("WORDS_FILE") diff --git a/pkg/rove/world.go b/pkg/rove/world.go index ea91fbc..a81cf05 100644 --- a/pkg/rove/world.go +++ b/pkg/rove/world.go @@ -11,7 +11,8 @@ import ( ) const ( - TicksPerNormalMove = 4 + // ticksPerNormalMove defines the number of ticks it should take for a "normal" speed move + ticksPerNormalMove = 4 ) // CommandStream is a list of commands to execute in order @@ -515,16 +516,16 @@ func (w *World) Tick() { switch diff { case 0: // Going with the wind, travel at base speed of once every 4 ticks - ticksToMove = TicksPerNormalMove + ticksToMove = ticksPerNormalMove case 1: // At a slight angle, we can go a little faster - ticksToMove = TicksPerNormalMove / 2 + ticksToMove = ticksPerNormalMove / 2 case 2: // Perpendicular to wind, max speed ticksToMove = 1 case 3: // Heading at 45 degrees into the wind, back to min speed - ticksToMove = TicksPerNormalMove + ticksToMove = ticksPerNormalMove case 4: // Heading durectly into the wind, no movement at all default: diff --git a/pkg/rove/world_test.go b/pkg/rove/world_test.go index a3c2f47..db9fcb6 100644 --- a/pkg/rove/world_test.go +++ b/pkg/rove/world_test.go @@ -419,7 +419,7 @@ func TestWorld_Sailing(t *testing.T) { assert.Equal(t, maths.Vector{Y: 0}, info.Pos) // Loop a few more times - for i := 0; i < TicksPerNormalMove-2; i++ { + for i := 0; i < ticksPerNormalMove-2; i++ { world.Tick() info, err := world.GetRover(name) assert.NoError(t, err) @@ -441,7 +441,7 @@ func TestWorld_Sailing(t *testing.T) { assert.Equal(t, roveapi.Bearing_South, b) // Tick a bunch, we should never move - for i := 0; i < TicksPerNormalMove*2; i++ { + for i := 0; i < ticksPerNormalMove*2; i++ { world.Tick() info, err := world.GetRover(name) assert.NoError(t, err)