Allow previous game state to include eliminated snakes. Fixes #19.
This commit is contained in:
parent
5fecc99934
commit
92592c2aba
2 changed files with 221 additions and 74 deletions
186
standard.go
186
standard.go
|
|
@ -201,6 +201,8 @@ func (r *StandardRuleset) CreateNextBoardState(prevState *BoardState, moves []Sn
|
||||||
nextState.Snakes[i].ID = prevState.Snakes[i].ID
|
nextState.Snakes[i].ID = prevState.Snakes[i].ID
|
||||||
nextState.Snakes[i].Health = prevState.Snakes[i].Health
|
nextState.Snakes[i].Health = prevState.Snakes[i].Health
|
||||||
nextState.Snakes[i].Body = append([]Point{}, prevState.Snakes[i].Body...)
|
nextState.Snakes[i].Body = append([]Point{}, prevState.Snakes[i].Body...)
|
||||||
|
nextState.Snakes[i].EliminatedCause = prevState.Snakes[i].EliminatedCause
|
||||||
|
nextState.Snakes[i].EliminatedBy = prevState.Snakes[i].EliminatedBy
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Gut check the BoardState?
|
// TODO: Gut check the BoardState?
|
||||||
|
|
@ -244,67 +246,71 @@ func (r *StandardRuleset) CreateNextBoardState(prevState *BoardState, moves []Sn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *StandardRuleset) moveSnakes(b *BoardState, moves []SnakeMove) error {
|
func (r *StandardRuleset) moveSnakes(b *BoardState, moves []SnakeMove) error {
|
||||||
|
// Sanity check that all non-eliminated snakes have moves and bodies.
|
||||||
for i := 0; i < len(b.Snakes); i++ {
|
for i := 0; i < len(b.Snakes); i++ {
|
||||||
if len(b.Snakes[i].Body) == 0 {
|
snake := &b.Snakes[i]
|
||||||
return errors.New("found snake with zero size body")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(moves) < len(b.Snakes) {
|
|
||||||
return errors.New("not enough snake moves")
|
|
||||||
}
|
|
||||||
if len(moves) > len(b.Snakes) {
|
|
||||||
return errors.New("too many snake moves")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, move := range moves {
|
|
||||||
var snake *Snake
|
|
||||||
for i := 0; i < len(b.Snakes); i++ {
|
|
||||||
if b.Snakes[i].ID == move.ID {
|
|
||||||
snake = &b.Snakes[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if snake == nil {
|
|
||||||
return errors.New("snake not found for move")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not move eliminated snakes
|
|
||||||
if snake.EliminatedCause != NotEliminated {
|
if snake.EliminatedCause != NotEliminated {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var newHead = Point{}
|
if len(snake.Body) == 0 {
|
||||||
switch move.Move {
|
return errors.New("found snake with zero size body")
|
||||||
case MoveDown:
|
}
|
||||||
newHead.X = snake.Body[0].X
|
moveFound := false
|
||||||
newHead.Y = snake.Body[0].Y + 1
|
for _, move := range moves {
|
||||||
case MoveLeft:
|
if snake.ID == move.ID {
|
||||||
newHead.X = snake.Body[0].X - 1
|
moveFound = true
|
||||||
newHead.Y = snake.Body[0].Y
|
break
|
||||||
case MoveRight:
|
|
||||||
newHead.X = snake.Body[0].X + 1
|
|
||||||
newHead.Y = snake.Body[0].Y
|
|
||||||
case MoveUp:
|
|
||||||
newHead.X = snake.Body[0].X
|
|
||||||
newHead.Y = snake.Body[0].Y - 1
|
|
||||||
default:
|
|
||||||
// Default to UP
|
|
||||||
var dX int32 = 0
|
|
||||||
var dY int32 = -1
|
|
||||||
// If neck is available, use neck to determine last direction
|
|
||||||
if len(snake.Body) >= 2 {
|
|
||||||
dX = snake.Body[0].X - snake.Body[1].X
|
|
||||||
dY = snake.Body[0].Y - snake.Body[1].Y
|
|
||||||
if dX == 0 && dY == 0 {
|
|
||||||
dY = -1 // Move up if no last move was made
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Apply
|
}
|
||||||
newHead.X = snake.Body[0].X + dX
|
if !moveFound {
|
||||||
newHead.Y = snake.Body[0].Y + dY
|
return errors.New("move not provided for snake")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(b.Snakes); i++ {
|
||||||
|
snake := &b.Snakes[i]
|
||||||
|
if snake.EliminatedCause != NotEliminated {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append new head, pop old tail
|
for _, move := range moves {
|
||||||
snake.Body = append([]Point{newHead}, snake.Body[:len(snake.Body)-1]...)
|
if move.ID == snake.ID {
|
||||||
|
var newHead = Point{}
|
||||||
|
switch move.Move {
|
||||||
|
case MoveDown:
|
||||||
|
newHead.X = snake.Body[0].X
|
||||||
|
newHead.Y = snake.Body[0].Y + 1
|
||||||
|
case MoveLeft:
|
||||||
|
newHead.X = snake.Body[0].X - 1
|
||||||
|
newHead.Y = snake.Body[0].Y
|
||||||
|
case MoveRight:
|
||||||
|
newHead.X = snake.Body[0].X + 1
|
||||||
|
newHead.Y = snake.Body[0].Y
|
||||||
|
case MoveUp:
|
||||||
|
newHead.X = snake.Body[0].X
|
||||||
|
newHead.Y = snake.Body[0].Y - 1
|
||||||
|
default:
|
||||||
|
// Default to UP
|
||||||
|
var dX int32 = 0
|
||||||
|
var dY int32 = -1
|
||||||
|
// If neck is available, use neck to determine last direction
|
||||||
|
if len(snake.Body) >= 2 {
|
||||||
|
dX = snake.Body[0].X - snake.Body[1].X
|
||||||
|
dY = snake.Body[0].Y - snake.Body[1].Y
|
||||||
|
if dX == 0 && dY == 0 {
|
||||||
|
dY = -1 // Move up if no last move was made
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Apply
|
||||||
|
newHead.X = snake.Body[0].X + dX
|
||||||
|
newHead.Y = snake.Body[0].Y + dY
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append new head, pop old tail
|
||||||
|
snake.Body = append([]Point{newHead}, snake.Body[:len(snake.Body)-1]...)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -331,9 +337,13 @@ func (r *StandardRuleset) maybeEliminateSnakes(b *BoardState) error {
|
||||||
return lenI > lenJ
|
return lenI > lenJ
|
||||||
})
|
})
|
||||||
|
|
||||||
// Iterate through snakes checking for eliminations.
|
// First, iterate over all non-eliminated snakes and eliminate the ones
|
||||||
|
// that are out of health or have moved out of bounds.
|
||||||
for i := 0; i < len(b.Snakes); i++ {
|
for i := 0; i < len(b.Snakes); i++ {
|
||||||
snake := &b.Snakes[i]
|
snake := &b.Snakes[i]
|
||||||
|
if snake.EliminatedCause != NotEliminated {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if len(snake.Body) <= 0 {
|
if len(snake.Body) <= 0 {
|
||||||
return errors.New("snake is length zero")
|
return errors.New("snake is length zero")
|
||||||
}
|
}
|
||||||
|
|
@ -347,40 +357,90 @@ func (r *StandardRuleset) maybeEliminateSnakes(b *BoardState) error {
|
||||||
snake.EliminatedCause = EliminatedByOutOfBounds
|
snake.EliminatedCause = EliminatedByOutOfBounds
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next, look for any collisions. Note we apply collision eliminations
|
||||||
|
// after this check so that snakes can collide with each other and be properly eliminated.
|
||||||
|
type CollisionElimination struct {
|
||||||
|
ID string
|
||||||
|
Cause string
|
||||||
|
By string
|
||||||
|
}
|
||||||
|
collisionEliminations := []CollisionElimination{}
|
||||||
|
for i := 0; i < len(b.Snakes); i++ {
|
||||||
|
snake := &b.Snakes[i]
|
||||||
|
if snake.EliminatedCause != NotEliminated {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(snake.Body) <= 0 {
|
||||||
|
return errors.New("snake is length zero")
|
||||||
|
}
|
||||||
|
|
||||||
// Check for self-collisions first
|
// Check for self-collisions first
|
||||||
if r.snakeHasBodyCollided(snake, snake) {
|
if r.snakeHasBodyCollided(snake, snake) {
|
||||||
snake.EliminatedCause = EliminatedBySelfCollision
|
collisionEliminations = append(collisionEliminations, CollisionElimination{
|
||||||
snake.EliminatedBy = snake.ID
|
ID: snake.ID,
|
||||||
|
Cause: EliminatedBySelfCollision,
|
||||||
|
By: snake.ID,
|
||||||
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for body collisions with other snakes second
|
// Check for body collisions with other snakes second
|
||||||
|
hasBodyCollided := false
|
||||||
for _, otherIndex := range snakeIndicesByLength {
|
for _, otherIndex := range snakeIndicesByLength {
|
||||||
other := &b.Snakes[otherIndex]
|
other := &b.Snakes[otherIndex]
|
||||||
if snake.ID == other.ID {
|
if other.EliminatedCause != NotEliminated {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if r.snakeHasBodyCollided(snake, other) {
|
if snake.ID != other.ID && r.snakeHasBodyCollided(snake, other) {
|
||||||
snake.EliminatedCause = EliminatedByCollision
|
collisionEliminations = append(collisionEliminations, CollisionElimination{
|
||||||
snake.EliminatedBy = other.ID
|
ID: snake.ID,
|
||||||
|
Cause: EliminatedByCollision,
|
||||||
|
By: other.ID,
|
||||||
|
})
|
||||||
|
hasBodyCollided = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if snake.EliminatedCause != NotEliminated {
|
if hasBodyCollided {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for head-to-heads last
|
// Check for head-to-heads last
|
||||||
|
hasHeadCollided := false
|
||||||
for _, otherIndex := range snakeIndicesByLength {
|
for _, otherIndex := range snakeIndicesByLength {
|
||||||
other := &b.Snakes[otherIndex]
|
other := &b.Snakes[otherIndex]
|
||||||
|
if other.EliminatedCause != NotEliminated {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if snake.ID != other.ID && r.snakeHasLostHeadToHead(snake, other) {
|
if snake.ID != other.ID && r.snakeHasLostHeadToHead(snake, other) {
|
||||||
snake.EliminatedCause = EliminatedByHeadToHeadCollision
|
collisionEliminations = append(collisionEliminations, CollisionElimination{
|
||||||
snake.EliminatedBy = other.ID
|
ID: snake.ID,
|
||||||
|
Cause: EliminatedByHeadToHeadCollision,
|
||||||
|
By: other.ID,
|
||||||
|
})
|
||||||
|
hasHeadCollided = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hasHeadCollided {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply collision eliminations
|
||||||
|
for _, elimination := range collisionEliminations {
|
||||||
|
for i := 0; i < len(b.Snakes); i++ {
|
||||||
|
snake := &b.Snakes[i]
|
||||||
|
if snake.ID == elimination.ID {
|
||||||
|
snake.EliminatedCause = elimination.Cause
|
||||||
|
snake.EliminatedBy = elimination.By
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
109
standard_test.go
109
standard_test.go
|
|
@ -487,7 +487,7 @@ func TestCreateNextBoardState(t *testing.T) {
|
||||||
Food: []Point{{0, 0}, {1, 0}},
|
Food: []Point{{0, 0}, {1, 0}},
|
||||||
},
|
},
|
||||||
[]SnakeMove{},
|
[]SnakeMove{},
|
||||||
errors.New("not enough snake moves"),
|
errors.New("move not provided for snake"),
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -530,12 +530,19 @@ func TestCreateNextBoardState(t *testing.T) {
|
||||||
Body: []Point{{3, 4}, {3, 3}},
|
Body: []Point{{3, 4}, {3, 3}},
|
||||||
Health: 100,
|
Health: 100,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ID: "three",
|
||||||
|
Body: []Point{},
|
||||||
|
Health: 100,
|
||||||
|
EliminatedCause: EliminatedByOutOfBounds,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Food: []Point{{0, 0}, {1, 0}},
|
Food: []Point{{0, 0}, {1, 0}},
|
||||||
},
|
},
|
||||||
[]SnakeMove{
|
[]SnakeMove{
|
||||||
{ID: "one", Move: MoveUp},
|
{ID: "one", Move: MoveUp},
|
||||||
{ID: "two", Move: MoveDown},
|
{ID: "two", Move: MoveDown},
|
||||||
|
{ID: "three", Move: MoveLeft}, // Should be ignored
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
&BoardState{
|
&BoardState{
|
||||||
|
|
@ -552,6 +559,12 @@ func TestCreateNextBoardState(t *testing.T) {
|
||||||
Body: []Point{{3, 5}, {3, 4}},
|
Body: []Point{{3, 5}, {3, 4}},
|
||||||
Health: 99,
|
Health: 99,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ID: "three",
|
||||||
|
Body: []Point{},
|
||||||
|
Health: 100,
|
||||||
|
EliminatedCause: EliminatedByOutOfBounds,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Food: []Point{{0, 0}},
|
Food: []Point{{0, 0}},
|
||||||
},
|
},
|
||||||
|
|
@ -561,8 +574,8 @@ func TestCreateNextBoardState(t *testing.T) {
|
||||||
r := StandardRuleset{}
|
r := StandardRuleset{}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
nextState, err := r.CreateNextBoardState(test.prevState, test.moves)
|
nextState, err := r.CreateNextBoardState(test.prevState, test.moves)
|
||||||
require.Equal(t, err, test.expectedError)
|
require.Equal(t, test.expectedError, err)
|
||||||
require.Equal(t, nextState, test.expectedState)
|
require.Equal(t, test.expectedState, nextState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -634,7 +647,7 @@ func TestEatingOnLastMove(t *testing.T) {
|
||||||
func TestHeadToHeadOnFood(t *testing.T) {
|
func TestHeadToHeadOnFood(t *testing.T) {
|
||||||
// We want to specifically ensure that snakes that collide head-to-head
|
// We want to specifically ensure that snakes that collide head-to-head
|
||||||
// on top of food successfully remove the food - that's the core behaviour this test
|
// on top of food successfully remove the food - that's the core behaviour this test
|
||||||
// is enforicing. There's a known side effect of this though, in that both snakes will
|
// is enforcing. There's a known side effect of this though, in that both snakes will
|
||||||
// have eaten prior to being evaluated on the head-to-head (+1 length, full health).
|
// have eaten prior to being evaluated on the head-to-head (+1 length, full health).
|
||||||
// We're okay with that since it does not impact the result of the head-to-head,
|
// We're okay with that since it does not impact the result of the head-to-head,
|
||||||
// however that behaviour could change in the future and this test could be updated.
|
// however that behaviour could change in the future and this test could be updated.
|
||||||
|
|
@ -734,6 +747,78 @@ func TestHeadToHeadOnFood(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rand.Seed(0) // Seed with a value that will reliably not spawn food
|
||||||
|
r := StandardRuleset{}
|
||||||
|
for _, test := range tests {
|
||||||
|
nextState, err := r.CreateNextBoardState(test.prevState, test.moves)
|
||||||
|
require.Equal(t, test.expectedError, err)
|
||||||
|
require.Equal(t, test.expectedState, nextState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRegressionIssue19(t *testing.T) {
|
||||||
|
// Eliminated snakes passed to CreateNextBoardState should not impact next game state
|
||||||
|
tests := []struct {
|
||||||
|
prevState *BoardState
|
||||||
|
moves []SnakeMove
|
||||||
|
expectedError error
|
||||||
|
expectedState *BoardState
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
&BoardState{
|
||||||
|
Width: 10,
|
||||||
|
Height: 10,
|
||||||
|
Snakes: []Snake{
|
||||||
|
{
|
||||||
|
ID: "one",
|
||||||
|
Body: []Point{{0, 2}, {0, 1}, {0, 0}},
|
||||||
|
Health: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "two",
|
||||||
|
Body: []Point{{0, 5}, {0, 6}, {0, 7}},
|
||||||
|
Health: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "eliminated",
|
||||||
|
Body: []Point{{0, 0}, {0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}},
|
||||||
|
Health: 0,
|
||||||
|
EliminatedCause: EliminatedByStarvation,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Food: []Point{{9, 9}},
|
||||||
|
},
|
||||||
|
[]SnakeMove{
|
||||||
|
{ID: "one", Move: MoveDown},
|
||||||
|
{ID: "two", Move: MoveUp},
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
&BoardState{
|
||||||
|
Width: 10,
|
||||||
|
Height: 10,
|
||||||
|
Snakes: []Snake{
|
||||||
|
{
|
||||||
|
ID: "one",
|
||||||
|
Body: []Point{{0, 3}, {0, 2}, {0, 1}},
|
||||||
|
Health: 99,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "two",
|
||||||
|
Body: []Point{{0, 4}, {0, 5}, {0, 6}},
|
||||||
|
Health: 99,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "eliminated",
|
||||||
|
Body: []Point{{0, 0}, {0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}},
|
||||||
|
Health: 0,
|
||||||
|
EliminatedCause: EliminatedByStarvation,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Food: []Point{{9, 9}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
rand.Seed(0) // Seed with a value that will reliably not spawn food
|
rand.Seed(0) // Seed with a value that will reliably not spawn food
|
||||||
r := StandardRuleset{}
|
r := StandardRuleset{}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
|
@ -741,6 +826,7 @@ func TestHeadToHeadOnFood(t *testing.T) {
|
||||||
require.Equal(t, err, test.expectedError)
|
require.Equal(t, err, test.expectedError)
|
||||||
require.Equal(t, nextState, test.expectedState)
|
require.Equal(t, nextState, test.expectedState)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMoveSnakes(t *testing.T) {
|
func TestMoveSnakes(t *testing.T) {
|
||||||
|
|
@ -853,7 +939,7 @@ func TestMoveSnakesWrongID(t *testing.T) {
|
||||||
|
|
||||||
r := StandardRuleset{}
|
r := StandardRuleset{}
|
||||||
err := r.moveSnakes(b, moves)
|
err := r.moveSnakes(b, moves)
|
||||||
require.Equal(t, err, errors.New("snake not found for move"))
|
require.Equal(t, errors.New("move not provided for snake"), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMoveSnakesNotEnoughMoves(t *testing.T) {
|
func TestMoveSnakesNotEnoughMoves(t *testing.T) {
|
||||||
|
|
@ -878,10 +964,10 @@ func TestMoveSnakesNotEnoughMoves(t *testing.T) {
|
||||||
|
|
||||||
r := StandardRuleset{}
|
r := StandardRuleset{}
|
||||||
err := r.moveSnakes(b, moves)
|
err := r.moveSnakes(b, moves)
|
||||||
require.Equal(t, err, errors.New("not enough snake moves"))
|
require.Equal(t, errors.New("move not provided for snake"), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMoveSnakesTooManyMoves(t *testing.T) {
|
func TestMoveSnakesExtraMovesIgnored(t *testing.T) {
|
||||||
b := &BoardState{
|
b := &BoardState{
|
||||||
Snakes: []Snake{
|
Snakes: []Snake{
|
||||||
{
|
{
|
||||||
|
|
@ -903,7 +989,8 @@ func TestMoveSnakesTooManyMoves(t *testing.T) {
|
||||||
|
|
||||||
r := StandardRuleset{}
|
r := StandardRuleset{}
|
||||||
err := r.moveSnakes(b, moves)
|
err := r.moveSnakes(b, moves)
|
||||||
require.Equal(t, err, errors.New("too many snake moves"))
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, []Point{{1, 0}}, b.Snakes[0].Body)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIsKnownBoardSize(t *testing.T) {
|
func TestIsKnownBoardSize(t *testing.T) {
|
||||||
|
|
@ -1466,7 +1553,7 @@ func TestMaybeEliminateSnakesPriority(t *testing.T) {
|
||||||
EliminatedByHeadToHeadCollision,
|
EliminatedByHeadToHeadCollision,
|
||||||
NotEliminated,
|
NotEliminated,
|
||||||
},
|
},
|
||||||
[]string{"", "", "3", "1", "6", ""},
|
[]string{"", "", "3", "3", "6", ""},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1476,8 +1563,8 @@ func TestMaybeEliminateSnakesPriority(t *testing.T) {
|
||||||
err := r.maybeEliminateSnakes(b)
|
err := r.maybeEliminateSnakes(b)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
for i, snake := range b.Snakes {
|
for i, snake := range b.Snakes {
|
||||||
require.Equal(t, test.ExpectedEliminatedCauses[i], snake.EliminatedCause)
|
require.Equal(t, test.ExpectedEliminatedCauses[i], snake.EliminatedCause, snake.ID)
|
||||||
require.Equal(t, test.ExpectedEliminatedBy[i], snake.EliminatedBy)
|
require.Equal(t, test.ExpectedEliminatedBy[i], snake.EliminatedBy, snake.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue