Prioritize self-collisions over other collisions. Fixes #16.
This commit is contained in:
parent
c74436e709
commit
5aec70de2b
3 changed files with 103 additions and 7 deletions
|
|
@ -338,3 +338,54 @@ func TestSquadIsGameOver(t *testing.T) {
|
|||
require.Equal(t, test.Expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue16Regression(t *testing.T) {
|
||||
// This is a specific test case to detect this issue:
|
||||
// https://github.com/BattlesnakeOfficial/rules/issues/16
|
||||
boardState := &BoardState{
|
||||
Width: 11,
|
||||
Height: 11,
|
||||
Snakes: []Snake{
|
||||
{ID: "teamBoi", Health: 10, Body: []Point{{1, 4}, {1, 3}, {0, 3}, {0, 2}, {1, 2}, {2, 2}}},
|
||||
{ID: "Node-Red-Bellied-Black-Snake", Health: 10, Body: []Point{{1, 8}, {2, 8}, {2, 9}, {3, 9}, {4, 9}, {4, 10}}},
|
||||
{ID: "Crash Override", Health: 10, Body: []Point{{2, 7}, {2, 6}, {3, 6}, {4, 6}, {4, 5}, {5, 5}, {6, 5}}},
|
||||
{ID: "Zero Cool", Health: 10, Body: []Point{{6, 5}, {5, 5}, {5, 4}, {5, 3}, {4, 3}, {3, 3}, {3, 4}}},
|
||||
},
|
||||
}
|
||||
squadMap := map[string]string{
|
||||
"teamBoi": "BirdSnakers",
|
||||
"Node-Red-Bellied-Black-Snake": "BirdSnakers",
|
||||
"Crash Override": "Hackers",
|
||||
"Zero Cool": "Hackers",
|
||||
}
|
||||
snakeMoves := []SnakeMove{
|
||||
{ID: "teamBoi", Move: "down"},
|
||||
{ID: "Node-Red-Bellied-Black-Snake", Move: "left"},
|
||||
{ID: "Crash Override", Move: "left"},
|
||||
{ID: "Zero Cool", Move: "left"},
|
||||
}
|
||||
|
||||
require.Equal(t, len(squadMap), len(boardState.Snakes), "squad map is wrong size, error in test setup")
|
||||
|
||||
r := SquadRuleset{
|
||||
AllowBodyCollisions: true,
|
||||
SquadMap: squadMap,
|
||||
}
|
||||
|
||||
nextBoardState, err := r.CreateNextBoardState(boardState, snakeMoves)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(boardState.Snakes), len(nextBoardState.Snakes))
|
||||
|
||||
expectedSnakes := []Snake{
|
||||
{ID: "teamBoi", Body: []Point{{1, 5}, {1, 4}, {1, 3}, {0, 3}, {0, 2}, {1, 2}}},
|
||||
{ID: "Node-Red-Bellied-Black-Snake", Body: []Point{{0, 8}, {1, 8}, {2, 8}, {2, 9}, {3, 9}, {4, 9}}},
|
||||
{ID: "Crash Override", Body: []Point{{1, 7}, {2, 7}, {2, 6}, {3, 6}, {4, 6}, {4, 5}, {5, 5}}},
|
||||
{ID: "Zero Cool", Body: []Point{{5, 5}, {6, 5}, {5, 5}, {5, 4}, {5, 3}, {4, 3}, {3, 3}}, EliminatedCause: EliminatedBySelfCollision, EliminatedBy: "Zero Cool"},
|
||||
}
|
||||
for i, snake := range nextBoardState.Snakes {
|
||||
require.Equal(t, expectedSnakes[i].ID, snake.ID, snake.ID)
|
||||
require.Equal(t, expectedSnakes[i].Body, snake.Body, snake.ID)
|
||||
require.Equal(t, expectedSnakes[i].EliminatedCause, snake.EliminatedCause, snake.ID)
|
||||
require.Equal(t, expectedSnakes[i].EliminatedBy, snake.EliminatedBy, snake.ID)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
18
standard.go
18
standard.go
|
|
@ -349,15 +349,21 @@ func (r *StandardRuleset) maybeEliminateSnakes(b *BoardState) error {
|
|||
continue
|
||||
}
|
||||
|
||||
// Always check body collisions before head-to-heads
|
||||
// Check for self-collisions first
|
||||
if r.snakeHasBodyCollided(snake, snake) {
|
||||
snake.EliminatedCause = EliminatedBySelfCollision
|
||||
snake.EliminatedBy = snake.ID
|
||||
continue
|
||||
}
|
||||
|
||||
// Check for body collisions with other snakes second
|
||||
for _, otherIndex := range snakeIndicesByLength {
|
||||
other := &b.Snakes[otherIndex]
|
||||
if r.snakeHasBodyCollided(snake, other) {
|
||||
if snake.ID == other.ID {
|
||||
snake.EliminatedCause = EliminatedBySelfCollision
|
||||
} else {
|
||||
snake.EliminatedCause = EliminatedByCollision
|
||||
continue
|
||||
}
|
||||
if r.snakeHasBodyCollided(snake, other) {
|
||||
snake.EliminatedCause = EliminatedByCollision
|
||||
snake.EliminatedBy = other.ID
|
||||
break
|
||||
}
|
||||
|
|
@ -366,7 +372,7 @@ func (r *StandardRuleset) maybeEliminateSnakes(b *BoardState) error {
|
|||
continue
|
||||
}
|
||||
|
||||
// Always check head-to-heads after body collisions
|
||||
// Check for head-to-heads last
|
||||
for _, otherIndex := range snakeIndicesByLength {
|
||||
other := &b.Snakes[otherIndex]
|
||||
if snake.ID != other.ID && r.snakeHasLostHeadToHead(snake, other) {
|
||||
|
|
|
|||
|
|
@ -1266,6 +1266,45 @@ func TestMaybeEliminateSnakes(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestMaybeEliminateSnakesPriority(t *testing.T) {
|
||||
tests := []struct {
|
||||
Snakes []Snake
|
||||
ExpectedEliminatedCauses []string
|
||||
ExpectedEliminatedBy []string
|
||||
}{
|
||||
{
|
||||
[]Snake{
|
||||
{ID: "1", Health: 0, Body: []Point{{-1, 0}, {0, 0}, {1, 0}}},
|
||||
{ID: "2", Health: 1, Body: []Point{{-1, 0}, {0, 0}, {1, 0}}},
|
||||
{ID: "3", Health: 1, Body: []Point{{1, 0}, {0, 0}, {1, 0}}},
|
||||
{ID: "4", Health: 1, Body: []Point{{1, 0}, {1, 1}, {1, 2}}},
|
||||
{ID: "5", Health: 1, Body: []Point{{2, 2}, {2, 1}, {2, 0}}},
|
||||
{ID: "6", Health: 1, Body: []Point{{2, 2}, {2, 3}, {2, 4}, {2, 5}}},
|
||||
},
|
||||
[]string{
|
||||
EliminatedByStarvation,
|
||||
EliminatedByOutOfBounds,
|
||||
EliminatedBySelfCollision,
|
||||
EliminatedByCollision,
|
||||
EliminatedByHeadToHeadCollision,
|
||||
NotEliminated,
|
||||
},
|
||||
[]string{"", "", "3", "1", "6", ""},
|
||||
},
|
||||
}
|
||||
|
||||
r := StandardRuleset{}
|
||||
for _, test := range tests {
|
||||
b := &BoardState{Width: 10, Height: 10, Snakes: test.Snakes}
|
||||
err := r.maybeEliminateSnakes(b)
|
||||
require.NoError(t, err)
|
||||
for i, snake := range b.Snakes {
|
||||
require.Equal(t, test.ExpectedEliminatedCauses[i], snake.EliminatedCause)
|
||||
require.Equal(t, test.ExpectedEliminatedBy[i], snake.EliminatedBy)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaybeFeedSnakes(t *testing.T) {
|
||||
tests := []struct {
|
||||
Name string
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue