Add "EliminatedBy" to snake eliminations. (#11)

* add eliminated by

* add test

* make sure largest snake is listed as eliminator on head to head collisions

* remove unused type def

* Reduce memory usage during elimination checks.

Co-authored-by: Daniel Steuernol <dlsteuer@gmail.com>
This commit is contained in:
Brad Van Vugt 2020-02-19 11:44:48 -08:00 committed by GitHub
parent a241c526b2
commit 8153585f57
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 70 additions and 21 deletions

View file

@ -3,6 +3,7 @@ package rules
import (
"errors"
"math/rand"
"sort"
)
type StandardRuleset struct{}
@ -256,6 +257,19 @@ func (r *StandardRuleset) reduceSnakeHealth(b *BoardState) error {
}
func (r *StandardRuleset) eliminateSnakes(b *BoardState) error {
// First order snake indices by length.
// In multi-collision scenarios we want to always attribute elimination to the longest snake.
snakeIndicesByLength := make([]int, len(b.Snakes))
for i := 0; i < len(b.Snakes); i++ {
snakeIndicesByLength[i] = i
}
sort.Slice(snakeIndicesByLength, func(i int, j int) bool {
lenI := len(b.Snakes[snakeIndicesByLength[i]].Body)
lenJ := len(b.Snakes[snakeIndicesByLength[j]].Body)
return lenI > lenJ
})
// Iterate through snakes checking for eliminations.
for i := 0; i < len(b.Snakes); i++ {
snake := &b.Snakes[i]
if len(snake.Body) <= 0 {
@ -273,14 +287,15 @@ func (r *StandardRuleset) eliminateSnakes(b *BoardState) error {
}
// Always check body collisions before head-to-heads
for j := 0; j < len(b.Snakes); j++ {
other := &b.Snakes[j]
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
}
snake.EliminatedBy = other.ID
break
}
}
@ -288,11 +303,12 @@ func (r *StandardRuleset) eliminateSnakes(b *BoardState) error {
continue
}
// Always check body collisions before head-to-heads
for j := 0; j < len(b.Snakes); j++ {
other := &b.Snakes[j]
// Always check head-to-heads after body collisions
for _, otherIndex := range snakeIndicesByLength {
other := &b.Snakes[otherIndex]
if snake.ID != other.ID && r.snakeHasLostHeadToHead(snake, other) {
snake.EliminatedCause = EliminatedByHeadToHeadCollision
snake.EliminatedBy = other.ID
break
}
}