Fix world spawning and radar
Also expand test coverage a little to ensure it's correct
This commit is contained in:
parent
fba75960f8
commit
43588c0e4b
8 changed files with 130 additions and 45 deletions
|
@ -174,10 +174,10 @@ func InnerMain(command string) error {
|
|||
return fmt.Errorf("Server returned failure: %s", response.Error)
|
||||
|
||||
} else {
|
||||
// Print the radar
|
||||
// Print out the radar
|
||||
num := int(math.Sqrt(float64(len(response.Tiles))))
|
||||
for i := 0; i < num; i++ {
|
||||
for j := num - 1; j >= 0; j-- {
|
||||
for j := num - 1; j >= 0; j-- {
|
||||
for i := 0; i < num; i++ {
|
||||
fmt.Printf("%d", response.Tiles[i+num*j])
|
||||
}
|
||||
fmt.Print("\n")
|
||||
|
|
|
@ -47,8 +47,8 @@ func NewAtlas(size int, chunkSize int) Atlas {
|
|||
return a
|
||||
}
|
||||
|
||||
// SpawnWorld spawns the current world
|
||||
func (a *Atlas) SpawnWorld() error {
|
||||
// SpawnRocks peppers the world with rocks
|
||||
func (a *Atlas) SpawnRocks() error {
|
||||
extent := a.ChunkSize * (a.Size / 2)
|
||||
|
||||
// Pepper the current world with rocks
|
||||
|
@ -62,16 +62,23 @@ func (a *Atlas) SpawnWorld() error {
|
|||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SpawnWalls spawns the around the world
|
||||
func (a *Atlas) SpawnWalls() error {
|
||||
extent := a.ChunkSize * (a.Size / 2)
|
||||
|
||||
// Surround the atlas in walls
|
||||
for i := -extent; i < extent; i++ {
|
||||
|
||||
if err := a.SetTile(Vector{i, extent - 1}, TileWall); err != nil {
|
||||
if err := a.SetTile(Vector{i, extent - 1}, TileWall); err != nil { // N
|
||||
return err
|
||||
} else if a.SetTile(Vector{extent - 1, i}, TileWall); err != nil {
|
||||
} else if a.SetTile(Vector{extent - 1, i}, TileWall); err != nil { // E
|
||||
return err
|
||||
} else if a.SetTile(Vector{-extent, i}, TileWall); err != nil {
|
||||
} else if a.SetTile(Vector{i, -extent}, TileWall); err != nil { // S
|
||||
return err
|
||||
} else if a.SetTile(Vector{i, extent - 1}, TileWall); err != nil {
|
||||
} else if a.SetTile(Vector{-extent, i}, TileWall); err != nil { // W
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -137,16 +137,32 @@ func TestAtlas_Grown(t *testing.T) {
|
|||
|
||||
func TestAtlas_SpawnWorld(t *testing.T) {
|
||||
// Start with a small example
|
||||
a := NewAtlas(2, 2)
|
||||
a := NewAtlas(2, 4)
|
||||
assert.NotNil(t, a)
|
||||
assert.Equal(t, 4, len(a.Chunks))
|
||||
assert.NoError(t, a.SpawnWalls())
|
||||
|
||||
assert.NoError(t, a.SpawnWorld())
|
||||
tile, err := a.GetTile(Vector{1, 1})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, TileWall, tile)
|
||||
for i := -4; i < 4; i++ {
|
||||
tile, err := a.GetTile(Vector{i, -4})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, TileWall, tile)
|
||||
}
|
||||
|
||||
tile, err = a.GetTile(Vector{-2, -2})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, TileWall, tile)
|
||||
for i := -4; i < 4; i++ {
|
||||
tile, err := a.GetTile(Vector{-4, i})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, TileWall, tile)
|
||||
}
|
||||
|
||||
for i := -4; i < 4; i++ {
|
||||
tile, err := a.GetTile(Vector{3, i})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, TileWall, tile)
|
||||
}
|
||||
|
||||
for i := -4; i < 4; i++ {
|
||||
tile, err := a.GetTile(Vector{i, 3})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, TileWall, tile)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
)
|
||||
|
||||
func TestCommand_Move(t *testing.T) {
|
||||
world := NewWorld()
|
||||
world := NewWorld(2, 4)
|
||||
a, err := world.SpawnRover()
|
||||
assert.NoError(t, err)
|
||||
pos := Vector{
|
||||
|
|
|
@ -28,17 +28,20 @@ type World struct {
|
|||
}
|
||||
|
||||
// NewWorld creates a new world object
|
||||
func NewWorld() *World {
|
||||
func NewWorld(size int, chunkSize int) *World {
|
||||
return &World{
|
||||
Rovers: make(map[uuid.UUID]Rover),
|
||||
CommandQueue: make(map[uuid.UUID]CommandStream),
|
||||
Atlas: NewAtlas(4, 8), // TODO: Choose an appropriate world size
|
||||
Atlas: NewAtlas(size, chunkSize), // TODO: Choose an appropriate world size
|
||||
}
|
||||
}
|
||||
|
||||
// SpawnWorld spawns a border at the edge of the world atlas
|
||||
func (w *World) SpawnWorld() error {
|
||||
return w.Atlas.SpawnWorld()
|
||||
if err := w.Atlas.SpawnRocks(); err != nil {
|
||||
return err
|
||||
}
|
||||
return w.Atlas.SpawnWalls()
|
||||
}
|
||||
|
||||
// SpawnRover adds an rover to the game
|
||||
|
@ -120,6 +123,20 @@ func (w *World) RoverAttributes(id uuid.UUID) (RoverAttributes, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// SetRoverAttributes sets the attributes of a requested rover
|
||||
func (w *World) SetRoverAttributes(id uuid.UUID, attributes RoverAttributes) error {
|
||||
w.worldMutex.Lock()
|
||||
defer w.worldMutex.Unlock()
|
||||
|
||||
if i, ok := w.Rovers[id]; ok {
|
||||
i.Attributes = attributes
|
||||
w.Rovers[id] = i
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("no rover matching id")
|
||||
}
|
||||
}
|
||||
|
||||
// WarpRover sets an rovers position
|
||||
func (w *World) WarpRover(id uuid.UUID, pos Vector) error {
|
||||
w.worldMutex.Lock()
|
||||
|
@ -214,8 +231,8 @@ func (w *World) RadarFromRover(id uuid.UUID) ([]Tile, error) {
|
|||
|
||||
// Gather up all tiles within the range
|
||||
var radar = make([]Tile, radarSpan*radarSpan)
|
||||
for i := scanMin.X; i < scanMax.X; i++ {
|
||||
for j := scanMin.Y; j < scanMax.Y; j++ {
|
||||
for j := scanMin.Y; j <= scanMax.Y; j++ {
|
||||
for i := scanMin.X; i <= scanMax.X; i++ {
|
||||
q := Vector{i, j}
|
||||
|
||||
if tile, err := w.Atlas.GetTile(q); err != nil {
|
||||
|
@ -224,7 +241,8 @@ func (w *World) RadarFromRover(id uuid.UUID) ([]Tile, error) {
|
|||
} else {
|
||||
// Get the position relative to the bottom left of the radar
|
||||
relative := q.Added(radarMin.Negated())
|
||||
radar[relative.X+relative.Y*radarSpan] = tile
|
||||
index := relative.X + relative.Y*radarSpan
|
||||
radar[index] = tile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,14 +8,14 @@ import (
|
|||
|
||||
func TestNewWorld(t *testing.T) {
|
||||
// Very basic for now, nothing to verify
|
||||
world := NewWorld()
|
||||
world := NewWorld(4, 4)
|
||||
if world == nil {
|
||||
t.Error("Failed to create world")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorld_CreateRover(t *testing.T) {
|
||||
world := NewWorld()
|
||||
world := NewWorld(2, 8)
|
||||
a, err := world.SpawnRover()
|
||||
assert.NoError(t, err)
|
||||
b, err := world.SpawnRover()
|
||||
|
@ -30,7 +30,7 @@ func TestWorld_CreateRover(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWorld_RoverAttributes(t *testing.T) {
|
||||
world := NewWorld()
|
||||
world := NewWorld(2, 4)
|
||||
a, err := world.SpawnRover()
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
@ -41,7 +41,7 @@ func TestWorld_RoverAttributes(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWorld_DestroyRover(t *testing.T) {
|
||||
world := NewWorld()
|
||||
world := NewWorld(4, 1)
|
||||
a, err := world.SpawnRover()
|
||||
assert.NoError(t, err)
|
||||
b, err := world.SpawnRover()
|
||||
|
@ -59,7 +59,7 @@ func TestWorld_DestroyRover(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWorld_GetSetMovePosition(t *testing.T) {
|
||||
world := NewWorld()
|
||||
world := NewWorld(4, 4)
|
||||
a, err := world.SpawnRover()
|
||||
assert.NoError(t, err)
|
||||
attribs, err := world.RoverAttributes(a)
|
||||
|
@ -91,29 +91,52 @@ func TestWorld_GetSetMovePosition(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWorld_RadarFromRover(t *testing.T) {
|
||||
world := NewWorld()
|
||||
// Create world that should have visible walls on the radar
|
||||
world := NewWorld(4, 2)
|
||||
a, err := world.SpawnRover()
|
||||
assert.NoError(t, err)
|
||||
b, err := world.SpawnRover()
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Get a's attributes
|
||||
// Set the rover range to a predictable value
|
||||
attrib, err := world.RoverAttributes(a)
|
||||
assert.NoError(t, err, "Failed to get rover attribs")
|
||||
attrib.Range = 4 // Set the range to 4 so we can predict the radar fully
|
||||
err = world.SetRoverAttributes(a, attrib)
|
||||
assert.NoError(t, err, "Failed to set rover attribs")
|
||||
|
||||
// Warp the rovers so a can see b
|
||||
bpos := Vector{-attrib.Range, -attrib.Range}
|
||||
// Warp the rovers into position
|
||||
bpos := Vector{-3, -3}
|
||||
assert.NoError(t, world.WarpRover(a, Vector{0, 0}), "Failed to warp rover")
|
||||
assert.NoError(t, world.WarpRover(b, bpos), "Failed to warp rover")
|
||||
|
||||
// Spawn the world wall
|
||||
err = world.Atlas.SpawnWalls()
|
||||
assert.NoError(t, err)
|
||||
|
||||
radar, err := world.RadarFromRover(a)
|
||||
assert.NoError(t, err, "Failed to get radar from rover")
|
||||
fullRange := attrib.Range + attrib.Range + 1
|
||||
assert.Equal(t, fullRange*fullRange, len(radar), "Radar returned wrong number of rovers")
|
||||
fullRange := 4 + 4 + 1
|
||||
assert.Equal(t, fullRange*fullRange, len(radar), "Radar returned wrong length")
|
||||
|
||||
// bottom left should be a rover (we put one there with bpos)
|
||||
assert.Equal(t, radar[0], TileRover, "Rover not found on radar in expected position")
|
||||
// Centre should be rover
|
||||
assert.Equal(t, radar[fullRange*fullRange/2], TileRover, "Rover not found on radar in expected position")
|
||||
// It should look like:
|
||||
// ---------
|
||||
// OOOOOOOO-
|
||||
// O------O-
|
||||
// O------O-
|
||||
// O---R--O-
|
||||
// O------O-
|
||||
// O------O-
|
||||
// OR-----O-
|
||||
// OOOOOOOO-
|
||||
|
||||
// Test all expected values
|
||||
assert.Equal(t, TileRover, radar[1+fullRange])
|
||||
assert.Equal(t, TileRover, radar[4+4*fullRange])
|
||||
for i := 0; i < 8; i++ {
|
||||
assert.Equal(t, TileWall, radar[i])
|
||||
assert.Equal(t, TileWall, radar[i+(7*9)])
|
||||
assert.Equal(t, TileWall, radar[i*9])
|
||||
assert.Equal(t, TileWall, radar[(i*9)+7])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,15 +140,21 @@ func TestHandleRadar(t *testing.T) {
|
|||
assert.NoError(t, err, "Error registering account")
|
||||
|
||||
// Spawn the rover rover for the account
|
||||
_, id, err := s.SpawnRoverForAccount(a.Id)
|
||||
attrib, id, err := s.SpawnRoverForAccount(a.Id)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Warp this rover to 0
|
||||
// Warp this rover to 0,0
|
||||
assert.NoError(t, s.world.WarpRover(id, game.Vector{}))
|
||||
|
||||
// Set a tile to wall below this rover
|
||||
wallPos := game.Vector{X: 0, Y: -1}
|
||||
assert.NoError(t, s.world.Atlas.SetTile(wallPos, game.TileWall))
|
||||
// Explicity set a few nearby tiles
|
||||
wallPos1 := game.Vector{X: 0, Y: -1}
|
||||
wallPos2 := game.Vector{X: 1, Y: 1}
|
||||
rockPos := game.Vector{X: 1, Y: 3}
|
||||
emptyPos := game.Vector{X: -2, Y: -3}
|
||||
assert.NoError(t, s.world.Atlas.SetTile(wallPos1, game.TileWall))
|
||||
assert.NoError(t, s.world.Atlas.SetTile(wallPos2, game.TileWall))
|
||||
assert.NoError(t, s.world.Atlas.SetTile(rockPos, game.TileRock))
|
||||
assert.NoError(t, s.world.Atlas.SetTile(emptyPos, game.TileEmpty))
|
||||
|
||||
request, _ := http.NewRequest(http.MethodGet, path.Join("/", a.Id.String(), "/radar"), nil)
|
||||
response := httptest.NewRecorder()
|
||||
|
@ -163,7 +169,22 @@ func TestHandleRadar(t *testing.T) {
|
|||
t.Errorf("got false for /radar: %s", status.Error)
|
||||
}
|
||||
|
||||
scope := attrib.Range*2 + 1
|
||||
radarOrigin := game.Vector{X: -attrib.Range, Y: -attrib.Range}
|
||||
|
||||
// Make sure the rover tile is correct
|
||||
assert.Equal(t, game.TileRover, status.Tiles[len(status.Tiles)/2])
|
||||
|
||||
// Check our other tiles
|
||||
wallPos1.Add(radarOrigin.Negated())
|
||||
wallPos2.Add(radarOrigin.Negated())
|
||||
rockPos.Add(radarOrigin.Negated())
|
||||
emptyPos.Add(radarOrigin.Negated())
|
||||
assert.Equal(t, game.TileWall, status.Tiles[wallPos1.X+wallPos1.Y*scope])
|
||||
assert.Equal(t, game.TileWall, status.Tiles[wallPos2.X+wallPos2.Y*scope])
|
||||
assert.Equal(t, game.TileRock, status.Tiles[rockPos.X+rockPos.Y*scope])
|
||||
assert.Equal(t, game.TileEmpty, status.Tiles[emptyPos.X+emptyPos.Y*scope])
|
||||
|
||||
}
|
||||
|
||||
func TestHandleRover(t *testing.T) {
|
||||
|
|
|
@ -98,7 +98,7 @@ func NewServer(opts ...ServerOption) *Server {
|
|||
|
||||
// Create the accountant
|
||||
s.accountant = accounts.NewAccountant()
|
||||
s.world = game.NewWorld()
|
||||
s.world = game.NewWorld(4, 8) // TODO: Configure this
|
||||
|
||||
return s
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue