allow placement of up to 16 snakes on xlarge board (#90)

This commit is contained in:
Torben 2022-06-29 14:26:18 -07:00 committed by GitHub
parent 04a34dd8c7
commit 61aeee31d6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 85 additions and 4 deletions

View file

@ -84,9 +84,14 @@ func CreateDefaultBoardState(rand Rand, width int, height int, snakeIDs []string
// PlaceSnakesAutomatically initializes the array of snakes based on the provided snake IDs and the size of the board. // PlaceSnakesAutomatically initializes the array of snakes based on the provided snake IDs and the size of the board.
func PlaceSnakesAutomatically(rand Rand, b *BoardState, snakeIDs []string) error { func PlaceSnakesAutomatically(rand Rand, b *BoardState, snakeIDs []string) error {
if isKnownBoardSize(b) { if isFixedBoardSize(b) {
return PlaceSnakesFixed(rand, b, snakeIDs) return PlaceSnakesFixed(rand, b, snakeIDs)
} }
if isExtraLargeBoardSize(b) {
return PlaceManySnakesDistributed(rand, b, snakeIDs)
}
return PlaceSnakesRandomly(rand, b, snakeIDs) return PlaceSnakesRandomly(rand, b, snakeIDs)
} }
@ -148,6 +153,76 @@ func PlaceSnakesFixed(rand Rand, b *BoardState, snakeIDs []string) error {
return nil return nil
} }
// PlaceManySnakesDistributed is a placement algorithm that works for up to 16 snakes
// It is intended for use on large boards and distributes snakes relatively evenly,
// and randomly, across quadrants.
func PlaceManySnakesDistributed(rand Rand, b *BoardState, snakeIDs []string) error {
// this placement algorithm supports up to 16 snakes
if len(snakeIDs) > 16 {
return ErrorTooManySnakes
}
b.Snakes = make([]Snake, len(snakeIDs))
for i := 0; i < len(snakeIDs); i++ {
b.Snakes[i] = Snake{
ID: snakeIDs[i],
Health: SnakeMaxHealth,
}
}
quadHSpace := b.Width / 2
quadVSpace := b.Height / 2
hOffset := quadHSpace / 3
vOffset := quadVSpace / 3
quads := make([]randomPositionBucket, 4)
// quad 1
quads[0] = randomPositionBucket{}
quads[0].fill(
Point{X: hOffset, Y: vOffset},
Point{X: quadHSpace - hOffset, Y: vOffset},
Point{X: hOffset, Y: quadVSpace - vOffset},
Point{X: quadHSpace - hOffset, Y: quadVSpace - vOffset},
)
// quad 2
quads[1] = randomPositionBucket{}
for _, p := range quads[0].positions {
quads[1].fill(Point{X: b.Width - p.X - 1, Y: p.Y})
}
// quad 3
quads[2] = randomPositionBucket{}
for _, p := range quads[0].positions {
quads[2].fill(Point{X: p.X, Y: b.Height - p.Y - 1})
}
// quad 4
quads[3] = randomPositionBucket{}
for _, p := range quads[0].positions {
quads[3].fill(Point{X: b.Width - p.X - 1, Y: b.Height - p.Y - 1})
}
currentQuad := rand.Intn(4) // randomly pick a quadrant to start from
// evenly distribute snakes across quadrants, randomly, by rotating through the quadrants
for i := 0; i < len(b.Snakes); i++ {
p, err := quads[currentQuad].take(rand)
if err != nil {
return err
}
for j := 0; j < SnakeStartSize; j++ {
b.Snakes[i].Body = append(b.Snakes[i].Body, p)
}
currentQuad = (currentQuad + 1) % 4
}
return nil
}
func PlaceSnakesInQuadrants(rand Rand, b *BoardState, quadrants [][]Point) error { func PlaceSnakesInQuadrants(rand Rand, b *BoardState, quadrants [][]Point) error {
if len(quadrants) != 4 { if len(quadrants) != 4 {
@ -265,9 +340,10 @@ func PlaceSnake(b *BoardState, snakeID string, body []Point) error {
// PlaceFoodAutomatically initializes the array of food based on the size of the board and the number of snakes. // PlaceFoodAutomatically initializes the array of food based on the size of the board and the number of snakes.
func PlaceFoodAutomatically(rand Rand, b *BoardState) error { func PlaceFoodAutomatically(rand Rand, b *BoardState) error {
if isKnownBoardSize(b) { if isFixedBoardSize(b) || isExtraLargeBoardSize(b) {
return PlaceFoodFixed(rand, b) return PlaceFoodFixed(rand, b)
} }
return PlaceFoodRandomly(rand, b, len(b.Snakes)) return PlaceFoodRandomly(rand, b, len(b.Snakes))
} }
@ -443,7 +519,12 @@ func getDistanceBetweenPoints(a, b Point) int {
return absInt(a.X-b.X) + absInt(a.Y-b.Y) return absInt(a.X-b.X) + absInt(a.Y-b.Y)
} }
func isKnownBoardSize(b *BoardState) bool { func isExtraLargeBoardSize(b *BoardState) bool {
// We can do placement for any square, large board using the distributed placement algorithm
return b.Width == b.Height && b.Width >= 21
}
func isFixedBoardSize(b *BoardState) bool {
if b.Height == BoardSizeSmall && b.Width == BoardSizeSmall { if b.Height == BoardSizeSmall && b.Width == BoardSizeSmall {
return true return true
} }

View file

@ -656,7 +656,7 @@ func TestIsKnownBoardSize(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
result := isKnownBoardSize(&BoardState{Width: test.Width, Height: test.Height}) result := isFixedBoardSize(&BoardState{Width: test.Width, Height: test.Height})
require.Equal(t, test.Expected, result) require.Equal(t, test.Expected, result)
} }
} }