DEV-1479 ensure snake elimination turn is set (#93)
* ensure snake elimination turn is set - centralise elimination update logic to a single place to ensure consistency * doc the method * testing
This commit is contained in:
parent
663c377cc4
commit
e1289af5fb
6 changed files with 143 additions and 73 deletions
11
board.go
11
board.go
|
|
@ -57,6 +57,7 @@ func (prevState *BoardState) Clone() *BoardState {
|
||||||
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].EliminatedCause = prevState.Snakes[i].EliminatedCause
|
||||||
|
nextState.Snakes[i].EliminatedOnTurn = prevState.Snakes[i].EliminatedOnTurn
|
||||||
nextState.Snakes[i].EliminatedBy = prevState.Snakes[i].EliminatedBy
|
nextState.Snakes[i].EliminatedBy = prevState.Snakes[i].EliminatedBy
|
||||||
}
|
}
|
||||||
return nextState
|
return nextState
|
||||||
|
|
@ -551,3 +552,13 @@ func getDistanceBetweenPoints(a, b Point) int {
|
||||||
func isSquareBoard(b *BoardState) bool {
|
func isSquareBoard(b *BoardState) bool {
|
||||||
return b.Width == b.Height
|
return b.Width == b.Height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EliminateSnake updates a snake's state to reflect that it was eliminated.
|
||||||
|
// - "cause" identifies what type of event caused the snake to be eliminated
|
||||||
|
// - "by" identifies which snake (if any, use empty string "" if none) eliminated the snake.
|
||||||
|
// - "turn" is the turn number that this snake was eliminated on.
|
||||||
|
func EliminateSnake(s *Snake, cause, by string, turn int) {
|
||||||
|
s.EliminatedCause = cause
|
||||||
|
s.EliminatedBy = by
|
||||||
|
s.EliminatedOnTurn = turn
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -881,3 +881,11 @@ func TestPlaceFoodRandomly(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, len(b.Food), 0)
|
require.Equal(t, len(b.Food), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEliminateSnake(t *testing.T) {
|
||||||
|
s := &Snake{}
|
||||||
|
EliminateSnake(s, "test-cause", "", 2)
|
||||||
|
require.Equal(t, "test-cause", s.EliminatedCause)
|
||||||
|
require.Equal(t, "", s.EliminatedBy)
|
||||||
|
require.Equal(t, 2, s.EliminatedOnTurn)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ func TestConstrictorRulesetInterface(t *testing.T) {
|
||||||
var constrictorMoveAndCollideMAD = gameTestCase{
|
var constrictorMoveAndCollideMAD = gameTestCase{
|
||||||
"Constrictor Case Move and Collide",
|
"Constrictor Case Move and Collide",
|
||||||
&BoardState{
|
&BoardState{
|
||||||
|
Turn: 41,
|
||||||
Width: 10,
|
Width: 10,
|
||||||
Height: 10,
|
Height: 10,
|
||||||
Snakes: []Snake{
|
Snakes: []Snake{
|
||||||
|
|
@ -47,6 +48,7 @@ var constrictorMoveAndCollideMAD = gameTestCase{
|
||||||
Health: 100,
|
Health: 100,
|
||||||
EliminatedCause: EliminatedByCollision,
|
EliminatedCause: EliminatedByCollision,
|
||||||
EliminatedBy: "two",
|
EliminatedBy: "two",
|
||||||
|
EliminatedOnTurn: 42,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "two",
|
ID: "two",
|
||||||
|
|
@ -54,6 +56,7 @@ var constrictorMoveAndCollideMAD = gameTestCase{
|
||||||
Health: 100,
|
Health: 100,
|
||||||
EliminatedCause: EliminatedByCollision,
|
EliminatedCause: EliminatedByCollision,
|
||||||
EliminatedBy: "one",
|
EliminatedBy: "one",
|
||||||
|
EliminatedOnTurn: 42,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Food: []Point{},
|
Food: []Point{},
|
||||||
|
|
|
||||||
31
solo_test.go
31
solo_test.go
|
|
@ -116,3 +116,34 @@ func TestSoloCreateNextBoardState(t *testing.T) {
|
||||||
gc.requireValidNextState(t, NewRulesetBuilder().PipelineRuleset(GameTypeSolo, NewPipeline(soloRulesetStages...)))
|
gc.requireValidNextState(t, NewRulesetBuilder().PipelineRuleset(GameTypeSolo, NewPipeline(soloRulesetStages...)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test a snake running right into the wall is properly eliminated
|
||||||
|
func TestSoloEliminationOutOfBounds(t *testing.T) {
|
||||||
|
r := SoloRuleset{}
|
||||||
|
|
||||||
|
// Using MaxRand is important because it ensures that the snakes are consistently placed in a way this test will work.
|
||||||
|
// Actually random placement could result in the assumptions made by this test being incorrect.
|
||||||
|
initialState, err := CreateDefaultBoardState(MaxRand, 2, 2, []string{"one"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, next, err := r.Execute(
|
||||||
|
initialState,
|
||||||
|
r.Settings(),
|
||||||
|
[]SnakeMove{{ID: "one", Move: "right"}},
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, initialState)
|
||||||
|
|
||||||
|
ended, next, err := r.Execute(
|
||||||
|
next,
|
||||||
|
r.Settings(),
|
||||||
|
[]SnakeMove{{ID: "one", Move: "right"}},
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, initialState)
|
||||||
|
|
||||||
|
require.True(t, ended)
|
||||||
|
require.Equal(t, EliminatedByOutOfBounds, next.Snakes[0].EliminatedCause)
|
||||||
|
require.Equal(t, "", next.Snakes[0].EliminatedBy)
|
||||||
|
require.Equal(t, 1, next.Snakes[0].EliminatedOnTurn)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,7 @@ func DamageHazardsStandard(b *BoardState, settings Settings, moves []SnakeMove)
|
||||||
snake.Health = SnakeMaxHealth
|
snake.Health = SnakeMaxHealth
|
||||||
}
|
}
|
||||||
if snakeIsOutOfHealth(snake) {
|
if snakeIsOutOfHealth(snake) {
|
||||||
snake.EliminatedCause = EliminatedByOutOfHealth
|
EliminateSnake(snake, EliminatedByOutOfHealth, "", b.Turn+1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -221,12 +221,12 @@ func EliminateSnakesStandard(b *BoardState, settings Settings, moves []SnakeMove
|
||||||
}
|
}
|
||||||
|
|
||||||
if snakeIsOutOfHealth(snake) {
|
if snakeIsOutOfHealth(snake) {
|
||||||
snake.EliminatedCause = EliminatedByOutOfHealth
|
EliminateSnake(snake, EliminatedByOutOfHealth, "", b.Turn+1)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if snakeIsOutOfBounds(snake, b.Width, b.Height) {
|
if snakeIsOutOfBounds(snake, b.Width, b.Height) {
|
||||||
snake.EliminatedCause = EliminatedByOutOfBounds
|
EliminateSnake(snake, EliminatedByOutOfBounds, "", b.Turn+1)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -306,8 +306,7 @@ func EliminateSnakesStandard(b *BoardState, settings Settings, moves []SnakeMove
|
||||||
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.ID == elimination.ID {
|
if snake.ID == elimination.ID {
|
||||||
snake.EliminatedCause = elimination.Cause
|
EliminateSnake(snake, elimination.Cause, elimination.By, b.Turn+1)
|
||||||
snake.EliminatedBy = elimination.By
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,7 @@ var standardCaseMoveEatAndGrow = gameTestCase{
|
||||||
var standardMoveAndCollideMAD = gameTestCase{
|
var standardMoveAndCollideMAD = gameTestCase{
|
||||||
"Standard Case Move and Collide",
|
"Standard Case Move and Collide",
|
||||||
&BoardState{
|
&BoardState{
|
||||||
|
Turn: 0,
|
||||||
Width: 10,
|
Width: 10,
|
||||||
Height: 10,
|
Height: 10,
|
||||||
Snakes: []Snake{
|
Snakes: []Snake{
|
||||||
|
|
@ -196,6 +197,7 @@ var standardMoveAndCollideMAD = gameTestCase{
|
||||||
Health: 98,
|
Health: 98,
|
||||||
EliminatedCause: EliminatedByCollision,
|
EliminatedCause: EliminatedByCollision,
|
||||||
EliminatedBy: "two",
|
EliminatedBy: "two",
|
||||||
|
EliminatedOnTurn: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "two",
|
ID: "two",
|
||||||
|
|
@ -203,6 +205,7 @@ var standardMoveAndCollideMAD = gameTestCase{
|
||||||
Health: 98,
|
Health: 98,
|
||||||
EliminatedCause: EliminatedByCollision,
|
EliminatedCause: EliminatedByCollision,
|
||||||
EliminatedBy: "one",
|
EliminatedBy: "one",
|
||||||
|
EliminatedOnTurn: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Food: []Point{},
|
Food: []Point{},
|
||||||
|
|
@ -279,6 +282,7 @@ func TestEatingOnLastMove(t *testing.T) {
|
||||||
Body: []Point{{3, 1}, {3, 2}, {3, 3}},
|
Body: []Point{{3, 1}, {3, 2}, {3, 3}},
|
||||||
Health: 0,
|
Health: 0,
|
||||||
EliminatedCause: EliminatedByOutOfHealth,
|
EliminatedCause: EliminatedByOutOfHealth,
|
||||||
|
EliminatedOnTurn: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Food: []Point{{9, 9}},
|
Food: []Point{{9, 9}},
|
||||||
|
|
@ -315,6 +319,7 @@ func TestHeadToHeadOnFood(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
&BoardState{
|
&BoardState{
|
||||||
|
Turn: 41,
|
||||||
Width: 10,
|
Width: 10,
|
||||||
Height: 10,
|
Height: 10,
|
||||||
Snakes: []Snake{
|
Snakes: []Snake{
|
||||||
|
|
@ -346,6 +351,7 @@ func TestHeadToHeadOnFood(t *testing.T) {
|
||||||
Health: 100,
|
Health: 100,
|
||||||
EliminatedCause: EliminatedByHeadToHeadCollision,
|
EliminatedCause: EliminatedByHeadToHeadCollision,
|
||||||
EliminatedBy: "two",
|
EliminatedBy: "two",
|
||||||
|
EliminatedOnTurn: 42,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "two",
|
ID: "two",
|
||||||
|
|
@ -353,6 +359,7 @@ func TestHeadToHeadOnFood(t *testing.T) {
|
||||||
Health: 100,
|
Health: 100,
|
||||||
EliminatedCause: EliminatedByHeadToHeadCollision,
|
EliminatedCause: EliminatedByHeadToHeadCollision,
|
||||||
EliminatedBy: "one",
|
EliminatedBy: "one",
|
||||||
|
EliminatedOnTurn: 42,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Food: []Point{{9, 9}},
|
Food: []Point{{9, 9}},
|
||||||
|
|
@ -360,6 +367,7 @@ func TestHeadToHeadOnFood(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
&BoardState{
|
&BoardState{
|
||||||
|
Turn: 41,
|
||||||
Width: 10,
|
Width: 10,
|
||||||
Height: 10,
|
Height: 10,
|
||||||
Snakes: []Snake{
|
Snakes: []Snake{
|
||||||
|
|
@ -391,6 +399,7 @@ func TestHeadToHeadOnFood(t *testing.T) {
|
||||||
Health: 100,
|
Health: 100,
|
||||||
EliminatedCause: EliminatedByHeadToHeadCollision,
|
EliminatedCause: EliminatedByHeadToHeadCollision,
|
||||||
EliminatedBy: "two",
|
EliminatedBy: "two",
|
||||||
|
EliminatedOnTurn: 42,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "two",
|
ID: "two",
|
||||||
|
|
@ -1277,6 +1286,7 @@ func TestMaybeDamageHazards(t *testing.T) {
|
||||||
Food []Point
|
Food []Point
|
||||||
ExpectedEliminatedCauses []string
|
ExpectedEliminatedCauses []string
|
||||||
ExpectedEliminatedByIDs []string
|
ExpectedEliminatedByIDs []string
|
||||||
|
ExpectedEliminatedOnTurns []int
|
||||||
}{
|
}{
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
|
|
@ -1284,12 +1294,14 @@ func TestMaybeDamageHazards(t *testing.T) {
|
||||||
Hazards: []Point{},
|
Hazards: []Point{},
|
||||||
ExpectedEliminatedCauses: []string{NotEliminated},
|
ExpectedEliminatedCauses: []string{NotEliminated},
|
||||||
ExpectedEliminatedByIDs: []string{""},
|
ExpectedEliminatedByIDs: []string{""},
|
||||||
|
ExpectedEliminatedOnTurns: []int{0},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Snakes: []Snake{{Body: []Point{{0, 0}}}},
|
Snakes: []Snake{{Body: []Point{{0, 0}}}},
|
||||||
Hazards: []Point{{0, 0}},
|
Hazards: []Point{{0, 0}},
|
||||||
ExpectedEliminatedCauses: []string{EliminatedByOutOfHealth},
|
ExpectedEliminatedCauses: []string{EliminatedByOutOfHealth},
|
||||||
ExpectedEliminatedByIDs: []string{""},
|
ExpectedEliminatedByIDs: []string{""},
|
||||||
|
ExpectedEliminatedOnTurns: []int{42},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Snakes: []Snake{{Body: []Point{{0, 0}}}},
|
Snakes: []Snake{{Body: []Point{{0, 0}}}},
|
||||||
|
|
@ -1297,12 +1309,14 @@ func TestMaybeDamageHazards(t *testing.T) {
|
||||||
Food: []Point{{0, 0}},
|
Food: []Point{{0, 0}},
|
||||||
ExpectedEliminatedCauses: []string{NotEliminated},
|
ExpectedEliminatedCauses: []string{NotEliminated},
|
||||||
ExpectedEliminatedByIDs: []string{""},
|
ExpectedEliminatedByIDs: []string{""},
|
||||||
|
ExpectedEliminatedOnTurns: []int{0},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Snakes: []Snake{{Body: []Point{{0, 0}, {1, 0}, {2, 0}}}},
|
Snakes: []Snake{{Body: []Point{{0, 0}, {1, 0}, {2, 0}}}},
|
||||||
Hazards: []Point{{1, 0}, {2, 0}},
|
Hazards: []Point{{1, 0}, {2, 0}},
|
||||||
ExpectedEliminatedCauses: []string{NotEliminated},
|
ExpectedEliminatedCauses: []string{NotEliminated},
|
||||||
ExpectedEliminatedByIDs: []string{""},
|
ExpectedEliminatedByIDs: []string{""},
|
||||||
|
ExpectedEliminatedOnTurns: []int{0},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Snakes: []Snake{
|
Snakes: []Snake{
|
||||||
|
|
@ -1312,6 +1326,7 @@ func TestMaybeDamageHazards(t *testing.T) {
|
||||||
Hazards: []Point{{1, 0}, {2, 0}, {3, 4}, {3, 5}, {3, 6}},
|
Hazards: []Point{{1, 0}, {2, 0}, {3, 4}, {3, 5}, {3, 6}},
|
||||||
ExpectedEliminatedCauses: []string{NotEliminated, NotEliminated},
|
ExpectedEliminatedCauses: []string{NotEliminated, NotEliminated},
|
||||||
ExpectedEliminatedByIDs: []string{"", ""},
|
ExpectedEliminatedByIDs: []string{"", ""},
|
||||||
|
ExpectedEliminatedOnTurns: []int{0, 0},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Snakes: []Snake{
|
Snakes: []Snake{
|
||||||
|
|
@ -1321,17 +1336,20 @@ func TestMaybeDamageHazards(t *testing.T) {
|
||||||
Hazards: []Point{{3, 3}},
|
Hazards: []Point{{3, 3}},
|
||||||
ExpectedEliminatedCauses: []string{NotEliminated, EliminatedByOutOfHealth},
|
ExpectedEliminatedCauses: []string{NotEliminated, EliminatedByOutOfHealth},
|
||||||
ExpectedEliminatedByIDs: []string{"", ""},
|
ExpectedEliminatedByIDs: []string{"", ""},
|
||||||
|
ExpectedEliminatedOnTurns: []int{0, 42},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
b := &BoardState{Snakes: test.Snakes, Hazards: test.Hazards, Food: test.Food}
|
b := &BoardState{Turn: 41, Snakes: test.Snakes, Hazards: test.Hazards, Food: test.Food}
|
||||||
r := StandardRuleset{HazardDamagePerTurn: 100}
|
r := StandardRuleset{HazardDamagePerTurn: 100}
|
||||||
_, err := DamageHazardsStandard(b, r.Settings(), mockSnakeMoves())
|
_, err := DamageHazardsStandard(b, r.Settings(), mockSnakeMoves())
|
||||||
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)
|
||||||
|
require.Equal(t, test.ExpectedEliminatedByIDs[i], snake.EliminatedBy)
|
||||||
|
require.Equal(t, test.ExpectedEliminatedOnTurns[i], snake.EliminatedOnTurn)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue