2020-01-05 17:08:05 -08:00
|
|
|
package rules
|
2019-12-31 20:43:45 -08:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"math"
|
2020-01-01 17:23:23 -08:00
|
|
|
"math/rand"
|
2019-12-31 20:43:45 -08:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
)
|
|
|
|
|
|
2020-05-17 14:38:39 -07:00
|
|
|
func TestStandardRulesetInterface(t *testing.T) {
|
|
|
|
|
var _ Ruleset = (*StandardRuleset)(nil)
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-31 20:43:45 -08:00
|
|
|
func TestSanity(t *testing.T) {
|
|
|
|
|
r := StandardRuleset{}
|
2020-01-02 16:10:33 -08:00
|
|
|
|
2022-05-11 08:26:28 -07:00
|
|
|
state, err := CreateDefaultBoardState(MaxRand, 0, 0, []string{})
|
2021-08-23 17:13:58 -07:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.NotNil(t, state)
|
|
|
|
|
|
|
|
|
|
state, err = r.ModifyInitialBoardState(state)
|
2020-01-02 16:10:33 -08:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.NotNil(t, state)
|
2022-05-25 11:17:41 -07:00
|
|
|
require.Equal(t, 0, state.Width)
|
|
|
|
|
require.Equal(t, 0, state.Height)
|
2020-01-02 16:10:33 -08:00
|
|
|
require.Len(t, state.Food, 0)
|
|
|
|
|
require.Len(t, state.Snakes, 0)
|
|
|
|
|
|
2020-02-20 10:24:44 -08:00
|
|
|
next, err := r.CreateNextBoardState(
|
2020-01-01 17:23:23 -08:00
|
|
|
&BoardState{},
|
2020-01-02 16:10:33 -08:00
|
|
|
[]SnakeMove{},
|
2019-12-31 20:43:45 -08:00
|
|
|
)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.NotNil(t, next)
|
2022-05-25 11:17:41 -07:00
|
|
|
require.Equal(t, 0, state.Width)
|
|
|
|
|
require.Equal(t, 0, state.Height)
|
2020-01-02 16:10:33 -08:00
|
|
|
require.Len(t, state.Snakes, 0)
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-02 20:00:19 -07:00
|
|
|
func TestStandardName(t *testing.T) {
|
|
|
|
|
r := StandardRuleset{}
|
|
|
|
|
require.Equal(t, "standard", r.Name())
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-15 16:41:39 -07:00
|
|
|
// Checks that the error for a snake missing a move is returned
|
|
|
|
|
var standardCaseErrNoMoveFound = gameTestCase{
|
|
|
|
|
"Standard Case Error No Move Found",
|
|
|
|
|
&BoardState{
|
|
|
|
|
Width: 10,
|
|
|
|
|
Height: 10,
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{
|
|
|
|
|
ID: "one",
|
|
|
|
|
Body: []Point{{1, 1}, {1, 2}},
|
|
|
|
|
Health: 100,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ID: "two",
|
|
|
|
|
Body: []Point{{3, 4}, {3, 3}},
|
|
|
|
|
Health: 100,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Food: []Point{{0, 0}, {1, 0}},
|
|
|
|
|
Hazards: []Point{},
|
|
|
|
|
},
|
2022-03-16 16:58:05 -07:00
|
|
|
[]SnakeMove{
|
|
|
|
|
{ID: "one", Move: MoveUp},
|
|
|
|
|
},
|
2022-03-15 16:41:39 -07:00
|
|
|
ErrorNoMoveFound,
|
|
|
|
|
nil,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Checks that the error for a snake with no points is returned
|
|
|
|
|
var standardCaseErrZeroLengthSnake = gameTestCase{
|
|
|
|
|
"Standard Case Error Zero Length Snake",
|
|
|
|
|
&BoardState{
|
|
|
|
|
Width: 10,
|
|
|
|
|
Height: 10,
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{
|
|
|
|
|
ID: "one",
|
|
|
|
|
Body: []Point{{1, 1}, {1, 2}},
|
|
|
|
|
Health: 100,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ID: "two",
|
|
|
|
|
Body: []Point{},
|
|
|
|
|
Health: 100,
|
2020-05-28 19:26:44 +01:00
|
|
|
},
|
|
|
|
|
},
|
2022-03-15 16:41:39 -07:00
|
|
|
Food: []Point{{0, 0}, {1, 0}},
|
|
|
|
|
Hazards: []Point{},
|
|
|
|
|
},
|
|
|
|
|
[]SnakeMove{
|
|
|
|
|
{ID: "one", Move: MoveUp},
|
|
|
|
|
{ID: "two", Move: MoveDown},
|
|
|
|
|
},
|
|
|
|
|
ErrorZeroLengthSnake,
|
|
|
|
|
nil,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Checks a basic state where a snake moves, eats and grows
|
|
|
|
|
var standardCaseMoveEatAndGrow = gameTestCase{
|
|
|
|
|
"Standard Case Move Eat and Grow",
|
|
|
|
|
&BoardState{
|
|
|
|
|
Width: 10,
|
|
|
|
|
Height: 10,
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{
|
|
|
|
|
ID: "one",
|
|
|
|
|
Body: []Point{{1, 1}, {1, 2}},
|
|
|
|
|
Health: 100,
|
2020-05-28 19:26:44 +01:00
|
|
|
},
|
2022-03-15 16:41:39 -07:00
|
|
|
{
|
|
|
|
|
ID: "two",
|
|
|
|
|
Body: []Point{{3, 4}, {3, 3}},
|
|
|
|
|
Health: 100,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ID: "three",
|
|
|
|
|
Body: []Point{},
|
|
|
|
|
Health: 100,
|
|
|
|
|
EliminatedCause: EliminatedByOutOfBounds,
|
2020-05-28 19:26:44 +01:00
|
|
|
},
|
|
|
|
|
},
|
2022-03-15 16:41:39 -07:00
|
|
|
Food: []Point{{0, 0}, {1, 0}},
|
|
|
|
|
Hazards: []Point{},
|
|
|
|
|
},
|
|
|
|
|
[]SnakeMove{
|
|
|
|
|
{ID: "one", Move: MoveDown},
|
|
|
|
|
{ID: "two", Move: MoveUp},
|
|
|
|
|
{ID: "three", Move: MoveLeft}, // Should be ignored
|
|
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
&BoardState{
|
|
|
|
|
Width: 10,
|
|
|
|
|
Height: 10,
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{
|
|
|
|
|
ID: "one",
|
|
|
|
|
Body: []Point{{1, 0}, {1, 1}, {1, 1}},
|
|
|
|
|
Health: 100,
|
2020-05-28 19:26:44 +01:00
|
|
|
},
|
2022-03-15 16:41:39 -07:00
|
|
|
{
|
|
|
|
|
ID: "two",
|
|
|
|
|
Body: []Point{{3, 5}, {3, 4}},
|
|
|
|
|
Health: 99,
|
2020-05-28 19:26:44 +01:00
|
|
|
},
|
2022-03-15 16:41:39 -07:00
|
|
|
{
|
|
|
|
|
ID: "three",
|
|
|
|
|
Body: []Point{},
|
|
|
|
|
Health: 100,
|
|
|
|
|
EliminatedCause: EliminatedByOutOfBounds,
|
2020-05-28 19:26:44 +01:00
|
|
|
},
|
|
|
|
|
},
|
2022-03-15 16:41:39 -07:00
|
|
|
Food: []Point{{0, 0}},
|
|
|
|
|
Hazards: []Point{},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Checks a basic state where two snakes of equal sizes collide, and both should
|
|
|
|
|
// be eliminated as a result.
|
|
|
|
|
var standardMoveAndCollideMAD = gameTestCase{
|
|
|
|
|
"Standard Case Move and Collide",
|
|
|
|
|
&BoardState{
|
2022-07-21 14:26:56 -07:00
|
|
|
Turn: 0,
|
2022-03-15 16:41:39 -07:00
|
|
|
Width: 10,
|
|
|
|
|
Height: 10,
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{
|
|
|
|
|
ID: "one",
|
|
|
|
|
Body: []Point{{1, 1}, {2, 1}},
|
|
|
|
|
Health: 99,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ID: "two",
|
|
|
|
|
Body: []Point{{1, 2}, {2, 2}},
|
|
|
|
|
Health: 99,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Food: []Point{},
|
|
|
|
|
Hazards: []Point{},
|
|
|
|
|
},
|
|
|
|
|
[]SnakeMove{
|
|
|
|
|
{ID: "one", Move: MoveUp},
|
|
|
|
|
{ID: "two", Move: MoveDown},
|
|
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
&BoardState{
|
|
|
|
|
Width: 10,
|
|
|
|
|
Height: 10,
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{
|
2022-07-21 14:26:56 -07:00
|
|
|
ID: "one",
|
|
|
|
|
Body: []Point{{1, 2}, {1, 1}},
|
|
|
|
|
Health: 98,
|
|
|
|
|
EliminatedCause: EliminatedByCollision,
|
|
|
|
|
EliminatedBy: "two",
|
|
|
|
|
EliminatedOnTurn: 1,
|
2022-03-15 16:41:39 -07:00
|
|
|
},
|
|
|
|
|
{
|
2022-07-21 14:26:56 -07:00
|
|
|
ID: "two",
|
|
|
|
|
Body: []Point{{1, 1}, {1, 2}},
|
|
|
|
|
Health: 98,
|
|
|
|
|
EliminatedCause: EliminatedByCollision,
|
|
|
|
|
EliminatedBy: "one",
|
|
|
|
|
EliminatedOnTurn: 1,
|
2022-03-15 16:41:39 -07:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Food: []Point{},
|
|
|
|
|
Hazards: []Point{},
|
|
|
|
|
},
|
|
|
|
|
}
|
2020-05-28 19:26:44 +01:00
|
|
|
|
2022-03-15 16:41:39 -07:00
|
|
|
func TestStandardCreateNextBoardState(t *testing.T) {
|
|
|
|
|
cases := []gameTestCase{
|
|
|
|
|
standardCaseErrNoMoveFound,
|
|
|
|
|
standardCaseErrZeroLengthSnake,
|
|
|
|
|
standardCaseMoveEatAndGrow,
|
|
|
|
|
standardMoveAndCollideMAD,
|
|
|
|
|
}
|
2020-05-28 19:26:44 +01:00
|
|
|
r := StandardRuleset{}
|
2022-04-19 15:52:57 -07:00
|
|
|
rb := NewRulesetBuilder().WithParams(map[string]string{
|
|
|
|
|
ParamGameType: GameTypeStandard,
|
|
|
|
|
})
|
2022-03-15 16:41:39 -07:00
|
|
|
for _, gc := range cases {
|
|
|
|
|
gc.requireValidNextState(t, &r)
|
2022-04-19 15:52:57 -07:00
|
|
|
// also test a RulesBuilder constructed instance
|
|
|
|
|
gc.requireValidNextState(t, rb.Ruleset())
|
|
|
|
|
// also test a pipeline with the same settings
|
|
|
|
|
gc.requireValidNextState(t, NewRulesetBuilder().PipelineRuleset(GameTypeStandard, NewPipeline(standardRulesetStages...)))
|
2020-05-28 19:26:44 +01:00
|
|
|
}
|
2019-12-31 20:43:45 -08:00
|
|
|
}
|
|
|
|
|
|
2020-08-31 13:18:03 -07:00
|
|
|
func TestEatingOnLastMove(t *testing.T) {
|
|
|
|
|
// We want to specifically ensure that snakes eating food on their last turn
|
|
|
|
|
// survive. It used to be that this wasn't the case, and snakes were eliminated
|
|
|
|
|
// if they moved onto food with their final move. This behaviour wasn't "wrong" or incorrect,
|
|
|
|
|
// it just was less fun to watch. So let's ensure we're always giving snakes every possible
|
|
|
|
|
// changes to reach food before eliminating them.
|
|
|
|
|
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: 1,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ID: "two",
|
|
|
|
|
Body: []Point{{3, 2}, {3, 3}, {3, 4}},
|
|
|
|
|
Health: 1,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Food: []Point{{0, 3}, {9, 9}},
|
|
|
|
|
},
|
|
|
|
|
[]SnakeMove{
|
2021-01-19 15:33:05 -08:00
|
|
|
{ID: "one", Move: MoveUp},
|
|
|
|
|
{ID: "two", Move: MoveDown},
|
2020-08-31 13:18:03 -07:00
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
&BoardState{
|
|
|
|
|
Width: 10,
|
|
|
|
|
Height: 10,
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{
|
|
|
|
|
ID: "one",
|
|
|
|
|
Body: []Point{{0, 3}, {0, 2}, {0, 1}, {0, 1}},
|
|
|
|
|
Health: 100,
|
|
|
|
|
},
|
|
|
|
|
{
|
2022-07-21 14:26:56 -07:00
|
|
|
ID: "two",
|
|
|
|
|
Body: []Point{{3, 1}, {3, 2}, {3, 3}},
|
|
|
|
|
Health: 0,
|
|
|
|
|
EliminatedCause: EliminatedByOutOfHealth,
|
|
|
|
|
EliminatedOnTurn: 1,
|
2020-08-31 13:18:03 -07:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Food: []Point{{9, 9}},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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, err, test.expectedError)
|
2021-08-17 16:47:06 -07:00
|
|
|
if test.expectedState != nil {
|
|
|
|
|
require.Equal(t, test.expectedState.Width, nextState.Width)
|
|
|
|
|
require.Equal(t, test.expectedState.Height, nextState.Height)
|
|
|
|
|
require.Equal(t, test.expectedState.Food, nextState.Food)
|
|
|
|
|
require.Equal(t, test.expectedState.Snakes, nextState.Snakes)
|
|
|
|
|
}
|
2020-08-31 13:18:03 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-31 13:30:09 -07:00
|
|
|
func TestHeadToHeadOnFood(t *testing.T) {
|
|
|
|
|
// 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
|
2020-09-10 11:49:41 -07:00
|
|
|
// is enforcing. There's a known side effect of this though, in that both snakes will
|
2020-08-31 13:30:09 -07:00
|
|
|
// 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,
|
|
|
|
|
// however that behaviour could change in the future and this test could be updated.
|
|
|
|
|
tests := []struct {
|
|
|
|
|
prevState *BoardState
|
|
|
|
|
moves []SnakeMove
|
|
|
|
|
expectedError error
|
|
|
|
|
expectedState *BoardState
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
&BoardState{
|
2022-07-21 14:26:56 -07:00
|
|
|
Turn: 41,
|
2020-08-31 13:30:09 -07:00
|
|
|
Width: 10,
|
|
|
|
|
Height: 10,
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{
|
|
|
|
|
ID: "one",
|
|
|
|
|
Body: []Point{{0, 2}, {0, 1}, {0, 0}},
|
|
|
|
|
Health: 10,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ID: "two",
|
|
|
|
|
Body: []Point{{0, 4}, {0, 5}, {0, 6}},
|
|
|
|
|
Health: 10,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Food: []Point{{0, 3}, {9, 9}},
|
|
|
|
|
},
|
|
|
|
|
[]SnakeMove{
|
2021-01-19 15:33:05 -08:00
|
|
|
{ID: "one", Move: MoveUp},
|
|
|
|
|
{ID: "two", Move: MoveDown},
|
2020-08-31 13:30:09 -07:00
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
&BoardState{
|
|
|
|
|
Width: 10,
|
|
|
|
|
Height: 10,
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{
|
2022-07-21 14:26:56 -07:00
|
|
|
ID: "one",
|
|
|
|
|
Body: []Point{{0, 3}, {0, 2}, {0, 1}, {0, 1}},
|
|
|
|
|
Health: 100,
|
|
|
|
|
EliminatedCause: EliminatedByHeadToHeadCollision,
|
|
|
|
|
EliminatedBy: "two",
|
|
|
|
|
EliminatedOnTurn: 42,
|
2020-08-31 13:30:09 -07:00
|
|
|
},
|
|
|
|
|
{
|
2022-07-21 14:26:56 -07:00
|
|
|
ID: "two",
|
|
|
|
|
Body: []Point{{0, 3}, {0, 4}, {0, 5}, {0, 5}},
|
|
|
|
|
Health: 100,
|
|
|
|
|
EliminatedCause: EliminatedByHeadToHeadCollision,
|
|
|
|
|
EliminatedBy: "one",
|
|
|
|
|
EliminatedOnTurn: 42,
|
2020-08-31 13:30:09 -07:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Food: []Point{{9, 9}},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
&BoardState{
|
2022-07-21 14:26:56 -07:00
|
|
|
Turn: 41,
|
2020-08-31 13:30:09 -07:00
|
|
|
Width: 10,
|
|
|
|
|
Height: 10,
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{
|
|
|
|
|
ID: "one",
|
|
|
|
|
Body: []Point{{0, 2}, {0, 1}, {0, 0}},
|
|
|
|
|
Health: 10,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ID: "two",
|
|
|
|
|
Body: []Point{{0, 4}, {0, 5}, {0, 6}, {0, 7}},
|
|
|
|
|
Health: 10,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Food: []Point{{0, 3}, {9, 9}},
|
|
|
|
|
},
|
|
|
|
|
[]SnakeMove{
|
2021-01-19 15:33:05 -08:00
|
|
|
{ID: "one", Move: MoveUp},
|
|
|
|
|
{ID: "two", Move: MoveDown},
|
2020-08-31 13:30:09 -07:00
|
|
|
},
|
|
|
|
|
nil,
|
|
|
|
|
&BoardState{
|
|
|
|
|
Width: 10,
|
|
|
|
|
Height: 10,
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{
|
2022-07-21 14:26:56 -07:00
|
|
|
ID: "one",
|
|
|
|
|
Body: []Point{{0, 3}, {0, 2}, {0, 1}, {0, 1}},
|
|
|
|
|
Health: 100,
|
|
|
|
|
EliminatedCause: EliminatedByHeadToHeadCollision,
|
|
|
|
|
EliminatedBy: "two",
|
|
|
|
|
EliminatedOnTurn: 42,
|
2020-08-31 13:30:09 -07:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ID: "two",
|
|
|
|
|
Body: []Point{{0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 6}},
|
|
|
|
|
Health: 100,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Food: []Point{{9, 9}},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-10 11:49:41 -07:00
|
|
|
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)
|
2021-08-17 16:47:06 -07:00
|
|
|
if test.expectedState != nil {
|
|
|
|
|
require.Equal(t, test.expectedState.Width, nextState.Width)
|
|
|
|
|
require.Equal(t, test.expectedState.Height, nextState.Height)
|
|
|
|
|
require.Equal(t, test.expectedState.Food, nextState.Food)
|
|
|
|
|
require.Equal(t, test.expectedState.Snakes, nextState.Snakes)
|
|
|
|
|
}
|
2020-09-10 11:49:41 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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,
|
2020-09-10 12:00:56 -07:00
|
|
|
EliminatedCause: EliminatedByOutOfHealth,
|
2020-09-10 11:49:41 -07:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Food: []Point{{9, 9}},
|
|
|
|
|
},
|
|
|
|
|
[]SnakeMove{
|
2021-01-19 15:33:05 -08:00
|
|
|
{ID: "one", Move: MoveUp},
|
|
|
|
|
{ID: "two", Move: MoveDown},
|
2020-09-10 11:49:41 -07:00
|
|
|
},
|
|
|
|
|
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,
|
2020-09-10 12:00:56 -07:00
|
|
|
EliminatedCause: EliminatedByOutOfHealth,
|
2020-09-10 11:49:41 -07:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Food: []Point{{9, 9}},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-31 13:30:09 -07:00
|
|
|
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, err, test.expectedError)
|
2021-08-17 16:47:06 -07:00
|
|
|
if test.expectedState != nil {
|
|
|
|
|
require.Equal(t, test.expectedState.Width, nextState.Width)
|
|
|
|
|
require.Equal(t, test.expectedState.Height, nextState.Height)
|
|
|
|
|
require.Equal(t, test.expectedState.Food, nextState.Food)
|
|
|
|
|
require.Equal(t, test.expectedState.Snakes, nextState.Snakes)
|
|
|
|
|
}
|
2020-08-31 13:30:09 -07:00
|
|
|
}
|
2020-09-10 11:49:41 -07:00
|
|
|
|
2020-08-31 13:30:09 -07:00
|
|
|
}
|
|
|
|
|
|
2019-12-31 20:43:45 -08:00
|
|
|
func TestMoveSnakes(t *testing.T) {
|
2020-01-01 17:23:23 -08:00
|
|
|
b := &BoardState{
|
2020-01-02 16:10:33 -08:00
|
|
|
Snakes: []Snake{
|
2019-12-31 20:43:45 -08:00
|
|
|
{
|
|
|
|
|
ID: "one",
|
2020-01-02 16:10:33 -08:00
|
|
|
Body: []Point{{10, 110}, {11, 110}},
|
2019-12-31 20:43:45 -08:00
|
|
|
Health: 111111,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ID: "two",
|
2020-01-02 16:10:33 -08:00
|
|
|
Body: []Point{{23, 220}, {22, 220}, {21, 220}, {20, 220}},
|
2019-12-31 20:43:45 -08:00
|
|
|
Health: 222222,
|
|
|
|
|
},
|
2020-01-03 12:56:33 -08:00
|
|
|
{
|
|
|
|
|
ID: "three",
|
|
|
|
|
Body: []Point{{0, 0}},
|
|
|
|
|
Health: 1,
|
|
|
|
|
EliminatedCause: EliminatedByOutOfBounds,
|
|
|
|
|
},
|
2019-12-31 20:43:45 -08:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tests := []struct {
|
2020-01-03 12:56:33 -08:00
|
|
|
MoveOne string
|
|
|
|
|
ExpectedOne []Point
|
|
|
|
|
MoveTwo string
|
|
|
|
|
ExpectedTwo []Point
|
|
|
|
|
MoveThree string
|
|
|
|
|
ExpectedThree []Point
|
2019-12-31 20:43:45 -08:00
|
|
|
}{
|
|
|
|
|
{
|
2021-01-19 15:33:05 -08:00
|
|
|
MoveDown, []Point{{10, 109}, {10, 110}},
|
|
|
|
|
MoveUp, []Point{{23, 221}, {23, 220}, {22, 220}, {21, 220}},
|
|
|
|
|
MoveDown, []Point{{0, 0}},
|
2019-12-31 20:43:45 -08:00
|
|
|
},
|
|
|
|
|
{
|
2020-01-02 16:10:33 -08:00
|
|
|
MoveRight, []Point{{11, 109}, {10, 109}},
|
|
|
|
|
MoveLeft, []Point{{22, 221}, {23, 221}, {23, 220}, {22, 220}},
|
2021-01-19 15:33:05 -08:00
|
|
|
MoveDown, []Point{{0, 0}},
|
2019-12-31 20:43:45 -08:00
|
|
|
},
|
|
|
|
|
{
|
2020-01-02 16:10:33 -08:00
|
|
|
MoveRight, []Point{{12, 109}, {11, 109}},
|
|
|
|
|
MoveLeft, []Point{{21, 221}, {22, 221}, {23, 221}, {23, 220}},
|
2021-01-19 15:33:05 -08:00
|
|
|
MoveDown, []Point{{0, 0}},
|
2019-12-31 20:43:45 -08:00
|
|
|
},
|
|
|
|
|
{
|
2020-01-02 16:10:33 -08:00
|
|
|
MoveRight, []Point{{13, 109}, {12, 109}},
|
|
|
|
|
MoveLeft, []Point{{20, 221}, {21, 221}, {22, 221}, {23, 221}},
|
2021-01-19 15:33:05 -08:00
|
|
|
MoveDown, []Point{{0, 0}},
|
2019-12-31 20:43:45 -08:00
|
|
|
},
|
|
|
|
|
{
|
2021-01-19 15:33:05 -08:00
|
|
|
MoveDown, []Point{{13, 108}, {13, 109}},
|
|
|
|
|
MoveUp, []Point{{20, 222}, {20, 221}, {21, 221}, {22, 221}},
|
|
|
|
|
MoveDown, []Point{{0, 0}},
|
2019-12-31 20:43:45 -08:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r := StandardRuleset{}
|
|
|
|
|
for _, test := range tests {
|
2020-01-02 16:10:33 -08:00
|
|
|
moves := []SnakeMove{
|
|
|
|
|
{ID: "one", Move: test.MoveOne},
|
|
|
|
|
{ID: "two", Move: test.MoveTwo},
|
2020-01-03 12:56:33 -08:00
|
|
|
{ID: "three", Move: test.MoveThree},
|
2019-12-31 20:43:45 -08:00
|
|
|
}
|
2022-04-19 15:52:57 -07:00
|
|
|
_, err := MoveSnakesStandard(b, r.Settings(), moves)
|
2019-12-31 20:43:45 -08:00
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
2020-01-03 12:56:33 -08:00
|
|
|
require.Len(t, b.Snakes, 3)
|
|
|
|
|
|
2022-05-25 11:17:41 -07:00
|
|
|
require.Equal(t, 111111, b.Snakes[0].Health)
|
|
|
|
|
require.Equal(t, 222222, b.Snakes[1].Health)
|
|
|
|
|
require.Equal(t, 1, b.Snakes[2].Health)
|
2020-01-03 12:56:33 -08:00
|
|
|
|
2020-01-01 17:23:23 -08:00
|
|
|
require.Len(t, b.Snakes[0].Body, 2)
|
|
|
|
|
require.Len(t, b.Snakes[1].Body, 4)
|
2020-01-03 12:56:33 -08:00
|
|
|
require.Len(t, b.Snakes[2].Body, 1)
|
2019-12-31 20:43:45 -08:00
|
|
|
|
2020-01-01 17:23:23 -08:00
|
|
|
require.Equal(t, len(b.Snakes[0].Body), len(test.ExpectedOne))
|
2019-12-31 20:43:45 -08:00
|
|
|
for i, e := range test.ExpectedOne {
|
2020-01-02 16:10:33 -08:00
|
|
|
require.Equal(t, e, b.Snakes[0].Body[i])
|
2019-12-31 20:43:45 -08:00
|
|
|
}
|
2020-01-01 17:23:23 -08:00
|
|
|
require.Equal(t, len(b.Snakes[1].Body), len(test.ExpectedTwo))
|
2019-12-31 20:43:45 -08:00
|
|
|
for i, e := range test.ExpectedTwo {
|
2020-01-02 16:10:33 -08:00
|
|
|
require.Equal(t, e, b.Snakes[1].Body[i])
|
2019-12-31 20:43:45 -08:00
|
|
|
}
|
2020-01-03 12:56:33 -08:00
|
|
|
require.Equal(t, len(b.Snakes[2].Body), len(test.ExpectedThree))
|
|
|
|
|
for i, e := range test.ExpectedThree {
|
|
|
|
|
require.Equal(t, e, b.Snakes[2].Body[i])
|
|
|
|
|
}
|
2019-12-31 20:43:45 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-05 21:03:54 -08:00
|
|
|
func TestMoveSnakesWrongID(t *testing.T) {
|
|
|
|
|
b := &BoardState{
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{
|
|
|
|
|
ID: "one",
|
|
|
|
|
Body: []Point{{1, 1}},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
moves := []SnakeMove{
|
|
|
|
|
{
|
|
|
|
|
ID: "not found",
|
|
|
|
|
Move: MoveUp,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r := StandardRuleset{}
|
2022-04-19 15:52:57 -07:00
|
|
|
_, err := MoveSnakesStandard(b, r.Settings(), moves)
|
2020-12-11 10:05:19 -08:00
|
|
|
require.Equal(t, ErrorNoMoveFound, err)
|
2020-01-05 21:03:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestMoveSnakesNotEnoughMoves(t *testing.T) {
|
|
|
|
|
b := &BoardState{
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{
|
|
|
|
|
ID: "one",
|
|
|
|
|
Body: []Point{{1, 1}},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ID: "two",
|
|
|
|
|
Body: []Point{{2, 2}},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
moves := []SnakeMove{
|
|
|
|
|
{
|
|
|
|
|
ID: "two",
|
|
|
|
|
Move: MoveUp,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r := StandardRuleset{}
|
2022-04-19 15:52:57 -07:00
|
|
|
_, err := MoveSnakesStandard(b, r.Settings(), moves)
|
2020-12-11 12:50:52 -05:00
|
|
|
require.Equal(t, ErrorNoMoveFound, err)
|
2020-01-05 21:03:54 -08:00
|
|
|
}
|
|
|
|
|
|
2020-09-10 11:49:41 -07:00
|
|
|
func TestMoveSnakesExtraMovesIgnored(t *testing.T) {
|
2020-01-05 21:03:54 -08:00
|
|
|
b := &BoardState{
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{
|
|
|
|
|
ID: "one",
|
|
|
|
|
Body: []Point{{1, 1}},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
moves := []SnakeMove{
|
|
|
|
|
{
|
|
|
|
|
ID: "one",
|
2021-01-19 15:33:05 -08:00
|
|
|
Move: MoveDown,
|
2020-01-05 21:03:54 -08:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
ID: "two",
|
2021-01-19 15:33:05 -08:00
|
|
|
Move: MoveLeft,
|
2020-01-05 21:03:54 -08:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r := StandardRuleset{}
|
2022-04-19 15:52:57 -07:00
|
|
|
_, err := MoveSnakesStandard(b, r.Settings(), moves)
|
2020-09-10 11:49:41 -07:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Equal(t, []Point{{1, 0}}, b.Snakes[0].Body)
|
2020-01-05 21:03:54 -08:00
|
|
|
}
|
|
|
|
|
|
2019-12-31 20:43:45 -08:00
|
|
|
func TestMoveSnakesDefault(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
2020-01-02 16:10:33 -08:00
|
|
|
Body []Point
|
2019-12-31 20:43:45 -08:00
|
|
|
Move string
|
2020-01-02 16:10:33 -08:00
|
|
|
Expected []Point
|
2019-12-31 20:43:45 -08:00
|
|
|
}{
|
|
|
|
|
{
|
2020-01-02 16:10:33 -08:00
|
|
|
Body: []Point{{0, 0}},
|
2020-01-03 12:56:33 -08:00
|
|
|
Move: "invalid",
|
2021-01-19 15:33:05 -08:00
|
|
|
Expected: []Point{{0, 1}},
|
2019-12-31 20:43:45 -08:00
|
|
|
},
|
|
|
|
|
{
|
2020-01-02 16:10:33 -08:00
|
|
|
Body: []Point{{5, 5}, {5, 5}},
|
2019-12-31 20:43:45 -08:00
|
|
|
Move: "",
|
2021-01-19 15:33:05 -08:00
|
|
|
Expected: []Point{{5, 6}, {5, 5}},
|
2019-12-31 20:43:45 -08:00
|
|
|
},
|
|
|
|
|
{
|
2020-01-02 16:10:33 -08:00
|
|
|
Body: []Point{{5, 5}, {5, 4}},
|
|
|
|
|
Expected: []Point{{5, 6}, {5, 5}},
|
2019-12-31 20:43:45 -08:00
|
|
|
},
|
|
|
|
|
{
|
2020-01-02 16:10:33 -08:00
|
|
|
Body: []Point{{5, 4}, {5, 5}},
|
|
|
|
|
Expected: []Point{{5, 3}, {5, 4}},
|
2019-12-31 20:43:45 -08:00
|
|
|
},
|
|
|
|
|
{
|
2020-01-02 16:10:33 -08:00
|
|
|
Body: []Point{{5, 4}, {5, 5}},
|
|
|
|
|
Expected: []Point{{5, 3}, {5, 4}},
|
2019-12-31 20:43:45 -08:00
|
|
|
},
|
|
|
|
|
{
|
2020-01-02 16:10:33 -08:00
|
|
|
Body: []Point{{4, 5}, {5, 5}},
|
|
|
|
|
Expected: []Point{{3, 5}, {4, 5}},
|
2019-12-31 20:43:45 -08:00
|
|
|
},
|
|
|
|
|
{
|
2020-01-02 16:10:33 -08:00
|
|
|
Body: []Point{{5, 5}, {4, 5}},
|
|
|
|
|
Expected: []Point{{6, 5}, {5, 5}},
|
2019-12-31 20:43:45 -08:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r := StandardRuleset{}
|
|
|
|
|
for _, test := range tests {
|
2020-01-01 17:23:23 -08:00
|
|
|
b := &BoardState{
|
2020-01-02 16:10:33 -08:00
|
|
|
Snakes: []Snake{
|
|
|
|
|
{ID: "one", Body: test.Body},
|
2019-12-31 20:43:45 -08:00
|
|
|
},
|
|
|
|
|
}
|
2020-01-02 16:10:33 -08:00
|
|
|
moves := []SnakeMove{{ID: "one", Move: test.Move}}
|
2019-12-31 20:43:45 -08:00
|
|
|
|
2022-04-19 15:52:57 -07:00
|
|
|
_, err := MoveSnakesStandard(b, r.Settings(), moves)
|
2019-12-31 20:43:45 -08:00
|
|
|
require.NoError(t, err)
|
2020-01-01 17:23:23 -08:00
|
|
|
require.Len(t, b.Snakes, 1)
|
|
|
|
|
require.Equal(t, len(test.Body), len(b.Snakes[0].Body))
|
|
|
|
|
require.Equal(t, len(test.Expected), len(b.Snakes[0].Body))
|
2019-12-31 20:43:45 -08:00
|
|
|
for i, e := range test.Expected {
|
2020-01-02 16:10:33 -08:00
|
|
|
require.Equal(t, e, b.Snakes[0].Body[i])
|
2019-12-31 20:43:45 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-11 22:44:37 +00:00
|
|
|
func TestGetDefaultMove(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
SnakeBody []Point
|
|
|
|
|
ExpectedMove string
|
|
|
|
|
}{
|
|
|
|
|
// Default is always up
|
|
|
|
|
{
|
|
|
|
|
SnakeBody: []Point{},
|
|
|
|
|
ExpectedMove: MoveUp,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
SnakeBody: []Point{{0, 0}},
|
|
|
|
|
ExpectedMove: MoveUp,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
SnakeBody: []Point{{-1, -1}},
|
|
|
|
|
ExpectedMove: MoveUp,
|
|
|
|
|
},
|
|
|
|
|
// Stacked (fallback to default)
|
|
|
|
|
{
|
|
|
|
|
SnakeBody: []Point{{2, 2}, {2, 2}},
|
|
|
|
|
ExpectedMove: MoveUp,
|
|
|
|
|
},
|
|
|
|
|
// Neck next to head
|
|
|
|
|
{
|
|
|
|
|
SnakeBody: []Point{{2, 2}, {2, 1}},
|
|
|
|
|
ExpectedMove: MoveUp,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
SnakeBody: []Point{{2, 2}, {2, 3}},
|
|
|
|
|
ExpectedMove: MoveDown,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
SnakeBody: []Point{{2, 2}, {1, 2}},
|
|
|
|
|
ExpectedMove: MoveRight,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
SnakeBody: []Point{{2, 2}, {3, 2}},
|
|
|
|
|
ExpectedMove: MoveLeft,
|
|
|
|
|
},
|
|
|
|
|
// Board wrap cases
|
|
|
|
|
{
|
|
|
|
|
SnakeBody: []Point{{0, 0}, {0, 2}},
|
|
|
|
|
ExpectedMove: MoveUp,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
SnakeBody: []Point{{0, 0}, {2, 0}},
|
|
|
|
|
ExpectedMove: MoveRight,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
SnakeBody: []Point{{0, 2}, {0, 0}},
|
|
|
|
|
ExpectedMove: MoveDown,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
SnakeBody: []Point{{2, 0}, {0, 0}},
|
|
|
|
|
ExpectedMove: MoveLeft,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, test := range tests {
|
2022-03-16 16:58:05 -07:00
|
|
|
actualMove := getDefaultMove(test.SnakeBody)
|
2022-01-11 22:44:37 +00:00
|
|
|
require.Equal(t, test.ExpectedMove, actualMove)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-31 20:43:45 -08:00
|
|
|
func TestReduceSnakeHealth(t *testing.T) {
|
2020-01-01 17:23:23 -08:00
|
|
|
b := &BoardState{
|
2020-01-02 16:10:33 -08:00
|
|
|
Snakes: []Snake{
|
|
|
|
|
{
|
|
|
|
|
Body: []Point{{0, 0}, {0, 1}},
|
2019-12-31 20:43:45 -08:00
|
|
|
Health: 99,
|
|
|
|
|
},
|
2020-01-02 16:10:33 -08:00
|
|
|
{
|
|
|
|
|
Body: []Point{{5, 8}, {6, 8}, {7, 8}},
|
2019-12-31 20:43:45 -08:00
|
|
|
Health: 2,
|
|
|
|
|
},
|
2020-01-03 12:56:33 -08:00
|
|
|
{
|
|
|
|
|
Body: []Point{{0, 0}, {0, 1}},
|
|
|
|
|
Health: 50,
|
|
|
|
|
EliminatedCause: EliminatedByCollision,
|
|
|
|
|
},
|
2019-12-31 20:43:45 -08:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-02 16:10:33 -08:00
|
|
|
r := StandardRuleset{}
|
2022-04-19 15:52:57 -07:00
|
|
|
_, err := ReduceSnakeHealthStandard(b, r.Settings(), mockSnakeMoves())
|
2019-12-31 20:43:45 -08:00
|
|
|
require.NoError(t, err)
|
2022-05-25 11:17:41 -07:00
|
|
|
require.Equal(t, b.Snakes[0].Health, 98)
|
|
|
|
|
require.Equal(t, b.Snakes[1].Health, 1)
|
|
|
|
|
require.Equal(t, b.Snakes[2].Health, 50)
|
2019-12-31 20:43:45 -08:00
|
|
|
|
2022-04-19 15:52:57 -07:00
|
|
|
_, err = ReduceSnakeHealthStandard(b, r.Settings(), mockSnakeMoves())
|
2019-12-31 20:43:45 -08:00
|
|
|
require.NoError(t, err)
|
2022-05-25 11:17:41 -07:00
|
|
|
require.Equal(t, b.Snakes[0].Health, 97)
|
|
|
|
|
require.Equal(t, b.Snakes[1].Health, 0)
|
|
|
|
|
require.Equal(t, b.Snakes[2].Health, 50)
|
2019-12-31 20:43:45 -08:00
|
|
|
|
2022-04-19 15:52:57 -07:00
|
|
|
_, err = ReduceSnakeHealthStandard(b, r.Settings(), mockSnakeMoves())
|
2019-12-31 20:43:45 -08:00
|
|
|
require.NoError(t, err)
|
2022-05-25 11:17:41 -07:00
|
|
|
require.Equal(t, b.Snakes[0].Health, 96)
|
|
|
|
|
require.Equal(t, b.Snakes[1].Health, -1)
|
|
|
|
|
require.Equal(t, b.Snakes[2].Health, 50)
|
2019-12-31 20:43:45 -08:00
|
|
|
|
2022-04-19 15:52:57 -07:00
|
|
|
_, err = ReduceSnakeHealthStandard(b, r.Settings(), mockSnakeMoves())
|
2019-12-31 20:43:45 -08:00
|
|
|
require.NoError(t, err)
|
2022-05-25 11:17:41 -07:00
|
|
|
require.Equal(t, b.Snakes[0].Health, 95)
|
|
|
|
|
require.Equal(t, b.Snakes[1].Health, -2)
|
|
|
|
|
require.Equal(t, b.Snakes[2].Health, 50)
|
2019-12-31 20:43:45 -08:00
|
|
|
}
|
|
|
|
|
|
2020-09-10 12:00:56 -07:00
|
|
|
func TestSnakeIsOutOfHealth(t *testing.T) {
|
2019-12-31 20:43:45 -08:00
|
|
|
tests := []struct {
|
2022-05-25 11:17:41 -07:00
|
|
|
Health int
|
2019-12-31 20:43:45 -08:00
|
|
|
Expected bool
|
|
|
|
|
}{
|
2022-05-25 11:17:41 -07:00
|
|
|
{Health: math.MinInt, Expected: true},
|
2019-12-31 20:43:45 -08:00
|
|
|
{Health: -10, Expected: true},
|
|
|
|
|
{Health: -2, Expected: true},
|
|
|
|
|
{Health: -1, Expected: true},
|
|
|
|
|
{Health: 0, Expected: true},
|
|
|
|
|
{Health: 1, Expected: false},
|
|
|
|
|
{Health: 2, Expected: false},
|
|
|
|
|
{Health: 10, Expected: false},
|
2022-05-25 11:17:41 -07:00
|
|
|
{Health: math.MaxInt, Expected: false},
|
2019-12-31 20:43:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, test := range tests {
|
|
|
|
|
s := &Snake{Health: test.Health}
|
2022-03-16 16:58:05 -07:00
|
|
|
require.Equal(t, test.Expected, snakeIsOutOfHealth(s), "Health: %+v", test.Health)
|
2019-12-31 20:43:45 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSnakeIsOutOfBounds(t *testing.T) {
|
2022-05-25 11:17:41 -07:00
|
|
|
boardWidth := 10
|
|
|
|
|
boardHeight := 100
|
2019-12-31 20:43:45 -08:00
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
|
Point Point
|
|
|
|
|
Expected bool
|
|
|
|
|
}{
|
2022-05-25 11:17:41 -07:00
|
|
|
{Point{X: math.MinInt, Y: math.MinInt}, true},
|
|
|
|
|
{Point{X: math.MinInt, Y: 0}, true},
|
|
|
|
|
{Point{X: 0, Y: math.MinInt}, true},
|
2019-12-31 20:43:45 -08:00
|
|
|
{Point{X: -1, Y: -1}, true},
|
|
|
|
|
{Point{X: -1, Y: 0}, true},
|
|
|
|
|
{Point{X: 0, Y: -1}, true},
|
|
|
|
|
{Point{X: 0, Y: 0}, false},
|
|
|
|
|
{Point{X: 1, Y: 0}, false},
|
|
|
|
|
{Point{X: 0, Y: 1}, false},
|
|
|
|
|
{Point{X: 1, Y: 1}, false},
|
|
|
|
|
{Point{X: 9, Y: 9}, false},
|
|
|
|
|
{Point{X: 9, Y: 10}, false},
|
|
|
|
|
{Point{X: 9, Y: 11}, false},
|
|
|
|
|
{Point{X: 10, Y: 9}, true},
|
|
|
|
|
{Point{X: 10, Y: 10}, true},
|
|
|
|
|
{Point{X: 10, Y: 11}, true},
|
|
|
|
|
{Point{X: 11, Y: 9}, true},
|
|
|
|
|
{Point{X: 11, Y: 10}, true},
|
|
|
|
|
{Point{X: 11, Y: 11}, true},
|
2022-05-25 11:17:41 -07:00
|
|
|
{Point{X: math.MaxInt, Y: 11}, true},
|
2019-12-31 20:43:45 -08:00
|
|
|
{Point{X: 9, Y: 99}, false},
|
|
|
|
|
{Point{X: 9, Y: 100}, true},
|
|
|
|
|
{Point{X: 9, Y: 101}, true},
|
2022-05-25 11:17:41 -07:00
|
|
|
{Point{X: 9, Y: math.MaxInt}, true},
|
|
|
|
|
{Point{X: math.MaxInt, Y: math.MaxInt}, true},
|
2019-12-31 20:43:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, test := range tests {
|
|
|
|
|
// Test with point as head
|
2020-01-02 16:10:33 -08:00
|
|
|
s := Snake{Body: []Point{test.Point}}
|
2022-03-16 16:58:05 -07:00
|
|
|
require.Equal(t, test.Expected, snakeIsOutOfBounds(&s, boardWidth, boardHeight), "Head%+v", test.Point)
|
2019-12-31 20:43:45 -08:00
|
|
|
// Test with point as body
|
2021-08-17 16:47:06 -07:00
|
|
|
s = Snake{Body: []Point{{0, 0}, {0, 0}, test.Point}}
|
2022-03-16 16:58:05 -07:00
|
|
|
require.Equal(t, test.Expected, snakeIsOutOfBounds(&s, boardWidth, boardHeight), "Body%+v", test.Point)
|
2019-12-31 20:43:45 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSnakeHasBodyCollidedSelf(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
2020-01-02 16:10:33 -08:00
|
|
|
Body []Point
|
2019-12-31 20:43:45 -08:00
|
|
|
Expected bool
|
|
|
|
|
}{
|
2020-01-02 16:10:33 -08:00
|
|
|
{[]Point{{1, 1}}, false},
|
2019-12-31 20:43:45 -08:00
|
|
|
// Self stacks should self collide
|
|
|
|
|
// (we rely on snakes moving before we check self-collision on turn one)
|
2020-01-02 16:10:33 -08:00
|
|
|
{[]Point{{2, 2}, {2, 2}}, true},
|
|
|
|
|
{[]Point{{3, 3}, {3, 3}, {3, 3}}, true},
|
|
|
|
|
{[]Point{{5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}}, true},
|
2019-12-31 20:43:45 -08:00
|
|
|
// Non-collision cases
|
2020-01-02 16:10:33 -08:00
|
|
|
{[]Point{{0, 0}, {1, 0}, {1, 0}}, false},
|
|
|
|
|
{[]Point{{0, 0}, {1, 0}, {2, 0}}, false},
|
|
|
|
|
{[]Point{{0, 0}, {1, 0}, {2, 0}, {2, 0}, {2, 0}}, false},
|
|
|
|
|
{[]Point{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}}, false},
|
|
|
|
|
{[]Point{{0, 0}, {0, 1}, {0, 2}}, false},
|
|
|
|
|
{[]Point{{0, 0}, {0, 1}, {0, 2}, {0, 2}, {0, 2}}, false},
|
|
|
|
|
{[]Point{{0, 0}, {0, 1}, {0, 2}, {0, 3}, {0, 4}}, false},
|
2019-12-31 20:43:45 -08:00
|
|
|
// Collision cases
|
2020-01-02 16:10:33 -08:00
|
|
|
{[]Point{{0, 0}, {1, 0}, {0, 0}}, true},
|
|
|
|
|
{[]Point{{0, 0}, {0, 0}, {1, 0}}, true},
|
|
|
|
|
{[]Point{{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}}, true},
|
|
|
|
|
{[]Point{{4, 4}, {3, 4}, {3, 3}, {4, 4}, {4, 4}}, true},
|
|
|
|
|
{[]Point{{3, 3}, {3, 4}, {3, 3}, {4, 4}, {4, 5}}, true},
|
2019-12-31 20:43:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, test := range tests {
|
2020-01-02 16:10:33 -08:00
|
|
|
s := Snake{Body: test.Body}
|
2022-03-16 16:58:05 -07:00
|
|
|
require.Equal(t, test.Expected, snakeHasBodyCollided(&s, &s), "Body%q", s.Body)
|
2019-12-31 20:43:45 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSnakeHasBodyCollidedOther(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
2020-01-02 16:10:33 -08:00
|
|
|
SnakeBody []Point
|
|
|
|
|
OtherBody []Point
|
2019-12-31 20:43:45 -08:00
|
|
|
Expected bool
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
// Just heads
|
2020-01-02 16:10:33 -08:00
|
|
|
[]Point{{0, 0}},
|
|
|
|
|
[]Point{{1, 1}},
|
2019-12-31 20:43:45 -08:00
|
|
|
false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
// Head-to-heads are not considered in body collisions
|
2020-01-02 16:10:33 -08:00
|
|
|
[]Point{{0, 0}},
|
|
|
|
|
[]Point{{0, 0}},
|
2019-12-31 20:43:45 -08:00
|
|
|
false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
// Stacked bodies
|
2020-01-02 16:10:33 -08:00
|
|
|
[]Point{{0, 0}},
|
|
|
|
|
[]Point{{0, 0}, {0, 0}},
|
2019-12-31 20:43:45 -08:00
|
|
|
true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
// Separate stacked bodies
|
2020-01-02 16:10:33 -08:00
|
|
|
[]Point{{0, 0}, {0, 0}, {0, 0}},
|
|
|
|
|
[]Point{{1, 1}, {1, 1}, {1, 1}},
|
2019-12-31 20:43:45 -08:00
|
|
|
false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
// Stacked bodies, separated heads
|
2020-01-02 16:10:33 -08:00
|
|
|
[]Point{{0, 0}, {1, 0}, {1, 0}},
|
|
|
|
|
[]Point{{2, 0}, {1, 0}, {1, 0}},
|
2019-12-31 20:43:45 -08:00
|
|
|
false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
// Mid-snake collision
|
2020-01-02 16:10:33 -08:00
|
|
|
[]Point{{1, 1}},
|
|
|
|
|
[]Point{{0, 1}, {1, 1}, {2, 1}},
|
2019-12-31 20:43:45 -08:00
|
|
|
true,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, test := range tests {
|
2020-01-02 16:10:33 -08:00
|
|
|
s := &Snake{Body: test.SnakeBody}
|
|
|
|
|
o := &Snake{Body: test.OtherBody}
|
2022-03-16 16:58:05 -07:00
|
|
|
require.Equal(t, test.Expected, snakeHasBodyCollided(s, o), "Snake%q Other%q", s.Body, o.Body)
|
2019-12-31 20:43:45 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSnakeHasLostHeadToHead(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
2020-01-02 16:10:33 -08:00
|
|
|
SnakeBody []Point
|
|
|
|
|
OtherBody []Point
|
2019-12-31 20:43:45 -08:00
|
|
|
Expected bool
|
|
|
|
|
ExpectedOpposite bool
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
// Just heads
|
2020-01-02 16:10:33 -08:00
|
|
|
[]Point{{0, 0}},
|
|
|
|
|
[]Point{{1, 1}},
|
2019-12-31 20:43:45 -08:00
|
|
|
false, false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
// Just heads colliding
|
2020-01-02 16:10:33 -08:00
|
|
|
[]Point{{0, 0}},
|
|
|
|
|
[]Point{{0, 0}},
|
2019-12-31 20:43:45 -08:00
|
|
|
true, true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
// One snake larger
|
2020-01-02 16:10:33 -08:00
|
|
|
[]Point{{0, 0}, {1, 0}, {2, 0}},
|
|
|
|
|
[]Point{{0, 0}},
|
2019-12-31 20:43:45 -08:00
|
|
|
false, true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
// Other snake equal
|
2020-01-02 16:10:33 -08:00
|
|
|
[]Point{{0, 0}, {1, 0}, {2, 0}},
|
|
|
|
|
[]Point{{0, 0}, {0, 1}, {0, 2}},
|
2019-12-31 20:43:45 -08:00
|
|
|
true, true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
// Other snake longer
|
2020-01-02 16:10:33 -08:00
|
|
|
[]Point{{0, 0}, {1, 0}, {2, 0}},
|
|
|
|
|
[]Point{{0, 0}, {0, 1}, {0, 2}, {0, 3}},
|
2019-12-31 20:43:45 -08:00
|
|
|
true, false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
// Body collision
|
2020-01-02 16:10:33 -08:00
|
|
|
[]Point{{0, 1}, {1, 1}, {2, 1}},
|
|
|
|
|
[]Point{{0, 0}, {0, 1}, {0, 2}, {0, 3}},
|
2019-12-31 20:43:45 -08:00
|
|
|
false, false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
// Separate stacked bodies, head collision
|
2020-01-02 16:10:33 -08:00
|
|
|
[]Point{{3, 10}, {2, 10}, {2, 10}},
|
|
|
|
|
[]Point{{3, 10}, {4, 10}, {4, 10}},
|
2019-12-31 20:43:45 -08:00
|
|
|
true, true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
// Separate stacked bodies, head collision
|
2020-01-02 16:10:33 -08:00
|
|
|
[]Point{{10, 3}, {10, 2}, {10, 1}, {10, 0}},
|
|
|
|
|
[]Point{{10, 3}, {10, 4}, {10, 5}},
|
2019-12-31 20:43:45 -08:00
|
|
|
false, true,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, test := range tests {
|
2020-01-02 16:10:33 -08:00
|
|
|
s := Snake{Body: test.SnakeBody}
|
|
|
|
|
o := Snake{Body: test.OtherBody}
|
2022-03-16 16:58:05 -07:00
|
|
|
require.Equal(t, test.Expected, snakeHasLostHeadToHead(&s, &o), "Snake%q Other%q", s.Body, o.Body)
|
|
|
|
|
require.Equal(t, test.ExpectedOpposite, snakeHasLostHeadToHead(&o, &s), "Snake%q Other%q", s.Body, o.Body)
|
2019-12-31 20:43:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-20 10:24:44 -08:00
|
|
|
func TestMaybeEliminateSnakes(t *testing.T) {
|
2020-01-03 11:39:19 -08:00
|
|
|
tests := []struct {
|
2020-02-19 11:44:48 -08:00
|
|
|
Name string
|
2020-01-03 11:39:19 -08:00
|
|
|
Snakes []Snake
|
|
|
|
|
ExpectedEliminatedCauses []string
|
2020-02-19 11:44:48 -08:00
|
|
|
ExpectedEliminatedBy []string
|
2020-01-03 11:39:19 -08:00
|
|
|
Err error
|
|
|
|
|
}{
|
|
|
|
|
{
|
2020-02-19 11:44:48 -08:00
|
|
|
"Empty",
|
2020-01-03 11:39:19 -08:00
|
|
|
[]Snake{},
|
|
|
|
|
[]string{},
|
2020-02-19 11:44:48 -08:00
|
|
|
[]string{},
|
2020-01-03 11:39:19 -08:00
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
{
|
2020-02-19 11:44:48 -08:00
|
|
|
"Zero Snake",
|
2020-01-03 11:39:19 -08:00
|
|
|
[]Snake{
|
2021-08-17 16:47:06 -07:00
|
|
|
{},
|
2020-01-03 11:39:19 -08:00
|
|
|
},
|
|
|
|
|
[]string{NotEliminated},
|
2020-02-19 11:44:48 -08:00
|
|
|
[]string{""},
|
2020-12-11 12:50:52 -05:00
|
|
|
ErrorZeroLengthSnake,
|
2020-01-03 11:39:19 -08:00
|
|
|
},
|
|
|
|
|
{
|
2020-02-19 11:44:48 -08:00
|
|
|
"Single Starvation",
|
2020-01-03 11:39:19 -08:00
|
|
|
[]Snake{
|
2021-08-17 16:47:06 -07:00
|
|
|
{ID: "1", Body: []Point{{1, 1}}},
|
2020-01-03 11:39:19 -08:00
|
|
|
},
|
2020-09-10 12:00:56 -07:00
|
|
|
[]string{EliminatedByOutOfHealth},
|
2020-02-19 11:44:48 -08:00
|
|
|
[]string{""},
|
2020-01-03 11:39:19 -08:00
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
{
|
2020-02-19 11:44:48 -08:00
|
|
|
"Not Eliminated",
|
2020-01-03 11:39:19 -08:00
|
|
|
[]Snake{
|
2021-08-17 16:47:06 -07:00
|
|
|
{ID: "1", Health: 1, Body: []Point{{1, 1}}},
|
2020-01-03 11:39:19 -08:00
|
|
|
},
|
|
|
|
|
[]string{NotEliminated},
|
2020-02-19 11:44:48 -08:00
|
|
|
[]string{""},
|
2020-01-03 11:39:19 -08:00
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
{
|
2020-02-19 11:44:48 -08:00
|
|
|
"Out of Bounds",
|
2020-01-03 11:39:19 -08:00
|
|
|
[]Snake{
|
2021-08-17 16:47:06 -07:00
|
|
|
{ID: "1", Health: 1, Body: []Point{{-1, 1}}},
|
2020-01-03 11:39:19 -08:00
|
|
|
},
|
|
|
|
|
[]string{EliminatedByOutOfBounds},
|
2020-02-19 11:44:48 -08:00
|
|
|
[]string{""},
|
2020-01-03 11:39:19 -08:00
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
{
|
2020-02-19 11:44:48 -08:00
|
|
|
"Self Collision",
|
2020-01-03 11:39:19 -08:00
|
|
|
[]Snake{
|
2021-08-17 16:47:06 -07:00
|
|
|
{ID: "1", Health: 1, Body: []Point{{0, 0}, {0, 1}, {0, 0}}},
|
2020-01-03 11:39:19 -08:00
|
|
|
},
|
|
|
|
|
[]string{EliminatedBySelfCollision},
|
2020-02-19 11:44:48 -08:00
|
|
|
[]string{"1"},
|
2020-01-03 11:39:19 -08:00
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
{
|
2020-02-19 11:44:48 -08:00
|
|
|
"Multiple Separate Deaths",
|
2020-01-03 11:39:19 -08:00
|
|
|
[]Snake{
|
2021-08-17 16:47:06 -07:00
|
|
|
{ID: "1", Health: 1, Body: []Point{{0, 0}, {0, 1}, {0, 0}}},
|
|
|
|
|
{ID: "2", Health: 1, Body: []Point{{-1, 1}}},
|
2020-01-03 11:39:19 -08:00
|
|
|
},
|
|
|
|
|
[]string{
|
|
|
|
|
EliminatedBySelfCollision,
|
|
|
|
|
EliminatedByOutOfBounds},
|
2020-02-19 11:44:48 -08:00
|
|
|
[]string{"1", ""},
|
2020-01-03 11:39:19 -08:00
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
{
|
2020-02-19 11:44:48 -08:00
|
|
|
"Other Collision",
|
2020-01-03 11:39:19 -08:00
|
|
|
[]Snake{
|
2021-08-17 16:47:06 -07:00
|
|
|
{ID: "1", Health: 1, Body: []Point{{0, 2}, {0, 3}, {0, 4}}},
|
|
|
|
|
{ID: "2", Health: 1, Body: []Point{{0, 0}, {0, 1}, {0, 2}}},
|
2020-01-03 11:39:19 -08:00
|
|
|
},
|
|
|
|
|
[]string{
|
|
|
|
|
EliminatedByCollision,
|
|
|
|
|
NotEliminated},
|
2020-02-19 11:44:48 -08:00
|
|
|
[]string{"2", ""},
|
2020-01-03 11:39:19 -08:00
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
{
|
2020-02-19 11:44:48 -08:00
|
|
|
"All Eliminated Head 2 Head",
|
2020-01-03 11:39:19 -08:00
|
|
|
[]Snake{
|
2021-08-17 16:47:06 -07:00
|
|
|
{ID: "1", Health: 1, Body: []Point{{1, 1}}},
|
|
|
|
|
{ID: "2", Health: 1, Body: []Point{{1, 1}}},
|
|
|
|
|
{ID: "3", Health: 1, Body: []Point{{1, 1}}},
|
2020-01-03 11:39:19 -08:00
|
|
|
},
|
|
|
|
|
[]string{
|
|
|
|
|
EliminatedByHeadToHeadCollision,
|
|
|
|
|
EliminatedByHeadToHeadCollision,
|
|
|
|
|
EliminatedByHeadToHeadCollision,
|
|
|
|
|
},
|
2020-02-19 11:44:48 -08:00
|
|
|
[]string{"2", "1", "1"},
|
2020-01-03 11:39:19 -08:00
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
{
|
2020-02-19 11:44:48 -08:00
|
|
|
"One Snake wins Head 2 Head",
|
2020-01-03 11:39:19 -08:00
|
|
|
[]Snake{
|
2021-08-17 16:47:06 -07:00
|
|
|
{ID: "1", Health: 1, Body: []Point{{1, 1}, {0, 1}}},
|
|
|
|
|
{ID: "2", Health: 1, Body: []Point{{1, 1}, {1, 2}, {1, 3}}},
|
|
|
|
|
{ID: "3", Health: 1, Body: []Point{{1, 1}}},
|
2020-01-03 11:39:19 -08:00
|
|
|
},
|
|
|
|
|
[]string{
|
|
|
|
|
EliminatedByHeadToHeadCollision,
|
|
|
|
|
NotEliminated,
|
|
|
|
|
EliminatedByHeadToHeadCollision,
|
|
|
|
|
},
|
2020-02-19 11:44:48 -08:00
|
|
|
[]string{"2", "", "2"},
|
2020-01-03 11:39:19 -08:00
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
{
|
2020-02-19 11:44:48 -08:00
|
|
|
"All Snakes Body Eliminated",
|
2020-01-03 11:39:19 -08:00
|
|
|
[]Snake{
|
2021-08-17 16:47:06 -07:00
|
|
|
{ID: "1", Health: 1, Body: []Point{{4, 4}, {3, 3}}},
|
|
|
|
|
{ID: "2", Health: 1, Body: []Point{{3, 3}, {2, 2}}},
|
|
|
|
|
{ID: "3", Health: 1, Body: []Point{{2, 2}, {1, 1}}},
|
|
|
|
|
{ID: "4", Health: 1, Body: []Point{{1, 1}, {4, 4}}},
|
|
|
|
|
{ID: "5", Health: 1, Body: []Point{{4, 4}}}, // Body collision takes priority
|
2020-01-03 11:39:19 -08:00
|
|
|
},
|
|
|
|
|
[]string{
|
|
|
|
|
EliminatedByCollision,
|
|
|
|
|
EliminatedByCollision,
|
|
|
|
|
EliminatedByCollision,
|
|
|
|
|
EliminatedByCollision,
|
|
|
|
|
EliminatedByCollision,
|
|
|
|
|
},
|
2020-02-19 11:44:48 -08:00
|
|
|
[]string{"4", "1", "2", "3", "4"},
|
2020-01-03 11:39:19 -08:00
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
{
|
2020-02-19 11:44:48 -08:00
|
|
|
"All Snakes Eliminated Head 2 Head",
|
2020-01-03 11:39:19 -08:00
|
|
|
[]Snake{
|
2021-08-17 16:47:06 -07:00
|
|
|
{ID: "1", Health: 1, Body: []Point{{4, 4}, {4, 5}}},
|
|
|
|
|
{ID: "2", Health: 1, Body: []Point{{4, 4}, {4, 3}}},
|
|
|
|
|
{ID: "3", Health: 1, Body: []Point{{4, 4}, {5, 4}}},
|
|
|
|
|
{ID: "4", Health: 1, Body: []Point{{4, 4}, {3, 4}}},
|
2020-01-03 11:39:19 -08:00
|
|
|
},
|
|
|
|
|
[]string{
|
|
|
|
|
EliminatedByHeadToHeadCollision,
|
|
|
|
|
EliminatedByHeadToHeadCollision,
|
|
|
|
|
EliminatedByHeadToHeadCollision,
|
|
|
|
|
EliminatedByHeadToHeadCollision,
|
|
|
|
|
},
|
2020-02-19 11:44:48 -08:00
|
|
|
[]string{"2", "1", "1", "1"},
|
2020-01-03 11:39:19 -08:00
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
{
|
2020-02-19 11:44:48 -08:00
|
|
|
"4 Snakes Head 2 Head",
|
2020-01-03 11:39:19 -08:00
|
|
|
[]Snake{
|
2021-08-17 16:47:06 -07:00
|
|
|
{ID: "1", Health: 1, Body: []Point{{4, 4}, {4, 5}}},
|
|
|
|
|
{ID: "2", Health: 1, Body: []Point{{4, 4}, {4, 3}}},
|
|
|
|
|
{ID: "3", Health: 1, Body: []Point{{4, 4}, {5, 4}, {6, 4}}},
|
|
|
|
|
{ID: "4", Health: 1, Body: []Point{{4, 4}, {3, 4}}},
|
2020-01-03 11:39:19 -08:00
|
|
|
},
|
|
|
|
|
[]string{
|
|
|
|
|
EliminatedByHeadToHeadCollision,
|
|
|
|
|
EliminatedByHeadToHeadCollision,
|
|
|
|
|
NotEliminated,
|
|
|
|
|
EliminatedByHeadToHeadCollision,
|
|
|
|
|
},
|
2020-02-19 11:44:48 -08:00
|
|
|
[]string{"3", "3", "", "3"},
|
2020-01-03 11:39:19 -08:00
|
|
|
nil,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r := StandardRuleset{}
|
|
|
|
|
for _, test := range tests {
|
2020-02-19 11:44:48 -08:00
|
|
|
t.Run(test.Name, func(t *testing.T) {
|
|
|
|
|
b := &BoardState{
|
|
|
|
|
Width: 10,
|
|
|
|
|
Height: 10,
|
|
|
|
|
Snakes: test.Snakes,
|
|
|
|
|
}
|
2022-04-19 15:52:57 -07:00
|
|
|
_, err := EliminateSnakesStandard(b, r.Settings(), mockSnakeMoves())
|
2020-02-19 11:44:48 -08:00
|
|
|
require.Equal(t, test.Err, err)
|
|
|
|
|
for i, snake := range b.Snakes {
|
|
|
|
|
require.Equal(t, test.ExpectedEliminatedCauses[i], snake.EliminatedCause)
|
|
|
|
|
require.Equal(t, test.ExpectedEliminatedBy[i], snake.EliminatedBy)
|
|
|
|
|
}
|
|
|
|
|
})
|
2020-01-03 11:39:19 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-21 17:11:12 -07:00
|
|
|
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{
|
2020-09-10 12:00:56 -07:00
|
|
|
EliminatedByOutOfHealth,
|
2020-07-21 17:11:12 -07:00
|
|
|
EliminatedByOutOfBounds,
|
|
|
|
|
EliminatedBySelfCollision,
|
|
|
|
|
EliminatedByCollision,
|
|
|
|
|
EliminatedByHeadToHeadCollision,
|
|
|
|
|
NotEliminated,
|
|
|
|
|
},
|
2020-09-10 11:49:41 -07:00
|
|
|
[]string{"", "", "3", "3", "6", ""},
|
2020-07-21 17:11:12 -07:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r := StandardRuleset{}
|
|
|
|
|
for _, test := range tests {
|
|
|
|
|
b := &BoardState{Width: 10, Height: 10, Snakes: test.Snakes}
|
2022-04-19 15:52:57 -07:00
|
|
|
_, err := EliminateSnakesStandard(b, r.Settings(), mockSnakeMoves())
|
2020-07-21 17:11:12 -07:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
for i, snake := range b.Snakes {
|
2020-09-10 11:49:41 -07:00
|
|
|
require.Equal(t, test.ExpectedEliminatedCauses[i], snake.EliminatedCause, snake.ID)
|
|
|
|
|
require.Equal(t, test.ExpectedEliminatedBy[i], snake.EliminatedBy, snake.ID)
|
2020-07-21 17:11:12 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-17 16:47:06 -07:00
|
|
|
func TestMaybeDamageHazards(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
2022-07-21 14:26:56 -07:00
|
|
|
Snakes []Snake
|
|
|
|
|
Hazards []Point
|
|
|
|
|
Food []Point
|
|
|
|
|
ExpectedEliminatedCauses []string
|
|
|
|
|
ExpectedEliminatedByIDs []string
|
|
|
|
|
ExpectedEliminatedOnTurns []int
|
2021-08-17 16:47:06 -07:00
|
|
|
}{
|
|
|
|
|
{},
|
|
|
|
|
{
|
2022-07-21 14:26:56 -07:00
|
|
|
Snakes: []Snake{{Body: []Point{{0, 0}}}},
|
|
|
|
|
Hazards: []Point{},
|
|
|
|
|
ExpectedEliminatedCauses: []string{NotEliminated},
|
|
|
|
|
ExpectedEliminatedByIDs: []string{""},
|
|
|
|
|
ExpectedEliminatedOnTurns: []int{0},
|
2021-08-17 16:47:06 -07:00
|
|
|
},
|
|
|
|
|
{
|
2022-07-21 14:26:56 -07:00
|
|
|
Snakes: []Snake{{Body: []Point{{0, 0}}}},
|
|
|
|
|
Hazards: []Point{{0, 0}},
|
|
|
|
|
ExpectedEliminatedCauses: []string{EliminatedByOutOfHealth},
|
|
|
|
|
ExpectedEliminatedByIDs: []string{""},
|
|
|
|
|
ExpectedEliminatedOnTurns: []int{42},
|
2021-08-17 16:47:06 -07:00
|
|
|
},
|
|
|
|
|
{
|
2022-07-21 14:26:56 -07:00
|
|
|
Snakes: []Snake{{Body: []Point{{0, 0}}}},
|
|
|
|
|
Hazards: []Point{{0, 0}},
|
|
|
|
|
Food: []Point{{0, 0}},
|
|
|
|
|
ExpectedEliminatedCauses: []string{NotEliminated},
|
|
|
|
|
ExpectedEliminatedByIDs: []string{""},
|
|
|
|
|
ExpectedEliminatedOnTurns: []int{0},
|
2021-08-17 16:47:06 -07:00
|
|
|
},
|
|
|
|
|
{
|
2022-07-21 14:26:56 -07:00
|
|
|
Snakes: []Snake{{Body: []Point{{0, 0}, {1, 0}, {2, 0}}}},
|
|
|
|
|
Hazards: []Point{{1, 0}, {2, 0}},
|
|
|
|
|
ExpectedEliminatedCauses: []string{NotEliminated},
|
|
|
|
|
ExpectedEliminatedByIDs: []string{""},
|
|
|
|
|
ExpectedEliminatedOnTurns: []int{0},
|
2021-08-17 16:47:06 -07:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{Body: []Point{{0, 0}, {1, 0}, {2, 0}}},
|
|
|
|
|
{Body: []Point{{3, 3}, {3, 4}, {3, 5}, {3, 6}}},
|
|
|
|
|
},
|
2022-07-21 14:26:56 -07:00
|
|
|
Hazards: []Point{{1, 0}, {2, 0}, {3, 4}, {3, 5}, {3, 6}},
|
|
|
|
|
ExpectedEliminatedCauses: []string{NotEliminated, NotEliminated},
|
|
|
|
|
ExpectedEliminatedByIDs: []string{"", ""},
|
|
|
|
|
ExpectedEliminatedOnTurns: []int{0, 0},
|
2021-08-17 16:47:06 -07:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{Body: []Point{{0, 0}, {1, 0}, {2, 0}}},
|
|
|
|
|
{Body: []Point{{3, 3}, {3, 4}, {3, 5}, {3, 6}}},
|
|
|
|
|
},
|
2022-07-21 14:26:56 -07:00
|
|
|
Hazards: []Point{{3, 3}},
|
|
|
|
|
ExpectedEliminatedCauses: []string{NotEliminated, EliminatedByOutOfHealth},
|
|
|
|
|
ExpectedEliminatedByIDs: []string{"", ""},
|
|
|
|
|
ExpectedEliminatedOnTurns: []int{0, 42},
|
2021-08-17 16:47:06 -07:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, test := range tests {
|
2022-07-21 14:26:56 -07:00
|
|
|
b := &BoardState{Turn: 41, Snakes: test.Snakes, Hazards: test.Hazards, Food: test.Food}
|
2021-08-17 16:47:06 -07:00
|
|
|
r := StandardRuleset{HazardDamagePerTurn: 100}
|
2022-04-19 15:52:57 -07:00
|
|
|
_, err := DamageHazardsStandard(b, r.Settings(), mockSnakeMoves())
|
2021-08-17 16:47:06 -07:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
for i, snake := range b.Snakes {
|
|
|
|
|
require.Equal(t, test.ExpectedEliminatedCauses[i], snake.EliminatedCause)
|
2022-07-21 14:26:56 -07:00
|
|
|
require.Equal(t, test.ExpectedEliminatedByIDs[i], snake.EliminatedBy)
|
|
|
|
|
require.Equal(t, test.ExpectedEliminatedOnTurns[i], snake.EliminatedOnTurn)
|
2021-08-17 16:47:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestHazardDamagePerTurn(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
2022-05-25 11:17:41 -07:00
|
|
|
Health int
|
|
|
|
|
HazardDamagePerTurn int
|
2021-08-17 16:47:06 -07:00
|
|
|
Food bool
|
2022-05-25 11:17:41 -07:00
|
|
|
ExpectedHealth int
|
2021-08-17 16:47:06 -07:00
|
|
|
ExpectedEliminationCause string
|
|
|
|
|
Error error
|
|
|
|
|
}{
|
|
|
|
|
{100, 1, false, 99, NotEliminated, nil},
|
|
|
|
|
{100, 1, true, 100, NotEliminated, nil},
|
|
|
|
|
{100, 99, false, 1, NotEliminated, nil},
|
|
|
|
|
{100, 99, true, 100, NotEliminated, nil},
|
2022-06-30 12:10:30 -07:00
|
|
|
{100, -1, false, 100, NotEliminated, nil},
|
|
|
|
|
{99, -2, false, 100, NotEliminated, nil},
|
2021-08-17 16:47:06 -07:00
|
|
|
{100, 100, false, 0, EliminatedByOutOfHealth, nil},
|
|
|
|
|
{100, 101, false, 0, EliminatedByOutOfHealth, nil},
|
|
|
|
|
{100, 999, false, 0, EliminatedByOutOfHealth, nil},
|
|
|
|
|
{100, 100, true, 100, NotEliminated, nil},
|
|
|
|
|
{2, 1, false, 1, NotEliminated, nil},
|
|
|
|
|
{1, 1, false, 0, EliminatedByOutOfHealth, nil},
|
|
|
|
|
{1, 999, false, 0, EliminatedByOutOfHealth, nil},
|
|
|
|
|
{0, 1, false, 0, EliminatedByOutOfHealth, nil},
|
|
|
|
|
{0, 999, false, 0, EliminatedByOutOfHealth, nil},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, test := range tests {
|
|
|
|
|
b := &BoardState{Snakes: []Snake{{Health: test.Health, Body: []Point{{0, 0}}}}, Hazards: []Point{{0, 0}}}
|
|
|
|
|
if test.Food {
|
|
|
|
|
b.Food = []Point{{0, 0}}
|
|
|
|
|
}
|
|
|
|
|
r := StandardRuleset{HazardDamagePerTurn: test.HazardDamagePerTurn}
|
|
|
|
|
|
2022-04-19 15:52:57 -07:00
|
|
|
_, err := DamageHazardsStandard(b, r.Settings(), mockSnakeMoves())
|
2021-08-17 16:47:06 -07:00
|
|
|
require.Equal(t, test.Error, err)
|
|
|
|
|
require.Equal(t, test.ExpectedHealth, b.Snakes[0].Health)
|
|
|
|
|
require.Equal(t, test.ExpectedEliminationCause, b.Snakes[0].EliminatedCause)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-20 10:24:44 -08:00
|
|
|
func TestMaybeFeedSnakes(t *testing.T) {
|
2020-01-03 12:56:33 -08:00
|
|
|
tests := []struct {
|
|
|
|
|
Name string
|
|
|
|
|
Snakes []Snake
|
|
|
|
|
Food []Point
|
|
|
|
|
ExpectedSnakes []Snake
|
|
|
|
|
ExpectedFood []Point
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
Name: "snake not on food",
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{Health: 5, Body: []Point{{0, 0}, {0, 1}, {0, 2}}},
|
|
|
|
|
},
|
|
|
|
|
Food: []Point{{3, 3}},
|
|
|
|
|
ExpectedSnakes: []Snake{
|
|
|
|
|
{Health: 5, Body: []Point{{0, 0}, {0, 1}, {0, 2}}},
|
|
|
|
|
},
|
|
|
|
|
ExpectedFood: []Point{{3, 3}},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Name: "snake on food",
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{Health: SnakeMaxHealth - 1, Body: []Point{{2, 1}, {1, 1}, {1, 2}, {2, 2}}},
|
|
|
|
|
},
|
|
|
|
|
Food: []Point{{2, 1}},
|
|
|
|
|
ExpectedSnakes: []Snake{
|
|
|
|
|
{Health: SnakeMaxHealth, Body: []Point{{2, 1}, {1, 1}, {1, 2}, {2, 2}, {2, 2}}},
|
|
|
|
|
},
|
|
|
|
|
ExpectedFood: []Point{},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Name: "food under body",
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{Body: []Point{{0, 0}, {0, 1}, {0, 2}}},
|
|
|
|
|
},
|
|
|
|
|
Food: []Point{{0, 1}},
|
|
|
|
|
ExpectedSnakes: []Snake{
|
|
|
|
|
{Body: []Point{{0, 0}, {0, 1}, {0, 2}}},
|
|
|
|
|
},
|
|
|
|
|
ExpectedFood: []Point{{0, 1}},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Name: "snake on food but already eliminated",
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{Body: []Point{{0, 0}, {0, 1}, {0, 2}}, EliminatedCause: "EliminatedByOutOfBounds"},
|
|
|
|
|
},
|
|
|
|
|
Food: []Point{{0, 0}},
|
|
|
|
|
ExpectedSnakes: []Snake{
|
|
|
|
|
{Body: []Point{{0, 0}, {0, 1}, {0, 2}}},
|
|
|
|
|
},
|
|
|
|
|
ExpectedFood: []Point{{0, 0}},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Name: "multiple snakes on same food",
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{Health: SnakeMaxHealth, Body: []Point{{0, 0}, {0, 1}, {0, 2}}},
|
|
|
|
|
{Health: SnakeMaxHealth - 9, Body: []Point{{0, 0}, {1, 0}, {2, 0}}},
|
|
|
|
|
},
|
|
|
|
|
Food: []Point{{0, 0}, {4, 4}},
|
|
|
|
|
ExpectedSnakes: []Snake{
|
|
|
|
|
{Health: SnakeMaxHealth, Body: []Point{{0, 0}, {0, 1}, {0, 2}, {0, 2}}},
|
|
|
|
|
{Health: SnakeMaxHealth, Body: []Point{{0, 0}, {1, 0}, {2, 0}, {2, 0}}},
|
|
|
|
|
},
|
|
|
|
|
ExpectedFood: []Point{{4, 4}},
|
2019-12-31 20:43:45 -08:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-03 12:56:33 -08:00
|
|
|
r := StandardRuleset{}
|
|
|
|
|
for _, test := range tests {
|
|
|
|
|
b := &BoardState{
|
|
|
|
|
Snakes: test.Snakes,
|
|
|
|
|
Food: test.Food,
|
|
|
|
|
}
|
2022-04-19 15:52:57 -07:00
|
|
|
_, err := FeedSnakesStandard(b, r.Settings(), nil)
|
2020-01-03 12:56:33 -08:00
|
|
|
require.NoError(t, err, test.Name)
|
|
|
|
|
require.Equal(t, len(test.ExpectedSnakes), len(b.Snakes), test.Name)
|
|
|
|
|
for i := 0; i < len(b.Snakes); i++ {
|
|
|
|
|
require.Equal(t, test.ExpectedSnakes[i].Health, b.Snakes[i].Health, test.Name)
|
|
|
|
|
require.Equal(t, test.ExpectedSnakes[i].Body, b.Snakes[i].Body, test.Name)
|
|
|
|
|
}
|
|
|
|
|
require.Equal(t, test.ExpectedFood, b.Food, test.Name)
|
|
|
|
|
}
|
2020-01-01 17:23:23 -08:00
|
|
|
}
|
2019-12-31 20:43:45 -08:00
|
|
|
|
2020-11-20 12:00:58 -08:00
|
|
|
func TestMaybeSpawnFoodMinimum(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
2022-05-25 11:17:41 -07:00
|
|
|
MinimumFood int
|
2020-11-20 12:00:58 -08:00
|
|
|
Food []Point
|
|
|
|
|
ExpectedFood int
|
|
|
|
|
}{
|
|
|
|
|
// Use pre-tested seeds and results
|
|
|
|
|
{0, []Point{}, 0},
|
|
|
|
|
{1, []Point{}, 1},
|
|
|
|
|
{9, []Point{}, 9},
|
|
|
|
|
{7, []Point{{4, 5}, {4, 4}, {4, 1}}, 7},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, test := range tests {
|
|
|
|
|
r := StandardRuleset{MinimumFood: test.MinimumFood}
|
|
|
|
|
b := &BoardState{
|
|
|
|
|
Height: 11,
|
|
|
|
|
Width: 11,
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{Body: []Point{{1, 0}, {1, 1}}},
|
|
|
|
|
{Body: []Point{{0, 1}, {0, 2}, {0, 3}}},
|
|
|
|
|
},
|
|
|
|
|
Food: test.Food,
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-19 15:52:57 -07:00
|
|
|
_, err := SpawnFoodStandard(b, r.Settings(), mockSnakeMoves())
|
2020-11-20 12:00:58 -08:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Equal(t, test.ExpectedFood, len(b.Food))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestMaybeSpawnFoodZeroChance(t *testing.T) {
|
|
|
|
|
r := StandardRuleset{FoodSpawnChance: 0}
|
|
|
|
|
b := &BoardState{
|
|
|
|
|
Height: 11,
|
|
|
|
|
Width: 11,
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{Body: []Point{{1, 0}, {1, 1}}},
|
|
|
|
|
{Body: []Point{{0, 1}, {0, 2}, {0, 3}}},
|
|
|
|
|
},
|
|
|
|
|
Food: []Point{},
|
|
|
|
|
}
|
|
|
|
|
for i := 0; i < 1000; i++ {
|
2022-04-19 15:52:57 -07:00
|
|
|
_, err := SpawnFoodStandard(b, r.Settings(), nil)
|
2020-11-20 12:00:58 -08:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Equal(t, len(b.Food), 0)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestMaybeSpawnFoodHundredChance(t *testing.T) {
|
|
|
|
|
r := StandardRuleset{FoodSpawnChance: 100}
|
|
|
|
|
b := &BoardState{
|
|
|
|
|
Height: 11,
|
|
|
|
|
Width: 11,
|
|
|
|
|
Snakes: []Snake{
|
|
|
|
|
{Body: []Point{{1, 0}, {1, 1}}},
|
|
|
|
|
{Body: []Point{{0, 1}, {0, 2}, {0, 3}}},
|
|
|
|
|
},
|
|
|
|
|
Food: []Point{},
|
|
|
|
|
}
|
|
|
|
|
for i := 1; i <= 22; i++ {
|
2022-04-19 15:52:57 -07:00
|
|
|
_, err := SpawnFoodStandard(b, r.Settings(), mockSnakeMoves())
|
2020-11-20 12:00:58 -08:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Equal(t, i, len(b.Food))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestMaybeSpawnFoodHalfChance(t *testing.T) {
|
2020-01-01 17:23:23 -08:00
|
|
|
tests := []struct {
|
|
|
|
|
Seed int64
|
2020-02-01 10:47:15 -08:00
|
|
|
Food []Point
|
2022-05-25 11:17:41 -07:00
|
|
|
ExpectedFood int
|
2020-01-01 17:23:23 -08:00
|
|
|
}{
|
|
|
|
|
// Use pre-tested seeds and results
|
2020-11-20 12:00:58 -08:00
|
|
|
{123, []Point{}, 1},
|
|
|
|
|
{12345, []Point{}, 0},
|
|
|
|
|
{456, []Point{{4, 4}}, 1},
|
|
|
|
|
{789, []Point{{4, 4}}, 2},
|
|
|
|
|
{511, []Point{{4, 4}}, 1},
|
|
|
|
|
{165, []Point{{4, 4}}, 2},
|
2020-01-01 17:23:23 -08:00
|
|
|
}
|
|
|
|
|
|
2020-11-20 12:00:58 -08:00
|
|
|
r := StandardRuleset{FoodSpawnChance: 50}
|
2020-01-01 17:23:23 -08:00
|
|
|
for _, test := range tests {
|
|
|
|
|
b := &BoardState{
|
|
|
|
|
Height: 4,
|
|
|
|
|
Width: 5,
|
2020-01-02 16:10:33 -08:00
|
|
|
Snakes: []Snake{
|
|
|
|
|
{Body: []Point{{1, 0}, {1, 1}}},
|
|
|
|
|
{Body: []Point{{0, 1}, {0, 2}, {0, 3}}},
|
2020-01-01 17:23:23 -08:00
|
|
|
},
|
2020-02-01 10:47:15 -08:00
|
|
|
Food: test.Food,
|
2020-01-01 17:23:23 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rand.Seed(test.Seed)
|
2022-04-19 15:52:57 -07:00
|
|
|
_, err := SpawnFoodStandard(b, r.Settings(), mockSnakeMoves())
|
2020-01-01 17:23:23 -08:00
|
|
|
require.NoError(t, err)
|
2022-05-25 11:17:41 -07:00
|
|
|
require.Equal(t, test.ExpectedFood, len(b.Food), "Seed %d", test.Seed)
|
2020-01-01 17:23:23 -08:00
|
|
|
}
|
2019-12-31 20:43:45 -08:00
|
|
|
}
|
2020-05-17 14:22:09 -07:00
|
|
|
|
|
|
|
|
func TestIsGameOver(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
Snakes []Snake
|
|
|
|
|
Expected bool
|
|
|
|
|
}{
|
|
|
|
|
{[]Snake{}, true},
|
|
|
|
|
{[]Snake{{}}, true},
|
|
|
|
|
{[]Snake{{}, {}}, false},
|
|
|
|
|
{[]Snake{{}, {}, {}, {}, {}}, false},
|
|
|
|
|
{
|
|
|
|
|
[]Snake{
|
|
|
|
|
{EliminatedCause: EliminatedByCollision},
|
|
|
|
|
{EliminatedCause: NotEliminated},
|
|
|
|
|
},
|
|
|
|
|
true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
[]Snake{
|
|
|
|
|
{EliminatedCause: NotEliminated},
|
|
|
|
|
{EliminatedCause: EliminatedByCollision},
|
|
|
|
|
{EliminatedCause: NotEliminated},
|
|
|
|
|
{EliminatedCause: NotEliminated},
|
|
|
|
|
},
|
|
|
|
|
false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
[]Snake{
|
|
|
|
|
{EliminatedCause: EliminatedByOutOfBounds},
|
|
|
|
|
{EliminatedCause: EliminatedByOutOfBounds},
|
|
|
|
|
{EliminatedCause: EliminatedByOutOfBounds},
|
|
|
|
|
{EliminatedCause: EliminatedByOutOfBounds},
|
|
|
|
|
},
|
|
|
|
|
true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
[]Snake{
|
|
|
|
|
{EliminatedCause: EliminatedByOutOfBounds},
|
|
|
|
|
{EliminatedCause: EliminatedByOutOfBounds},
|
|
|
|
|
{EliminatedCause: EliminatedByOutOfBounds},
|
|
|
|
|
{EliminatedCause: NotEliminated},
|
|
|
|
|
},
|
|
|
|
|
true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
[]Snake{
|
|
|
|
|
{EliminatedCause: EliminatedByOutOfBounds},
|
|
|
|
|
{EliminatedCause: EliminatedByOutOfBounds},
|
|
|
|
|
{EliminatedCause: NotEliminated},
|
|
|
|
|
{EliminatedCause: NotEliminated},
|
|
|
|
|
},
|
|
|
|
|
false,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r := StandardRuleset{}
|
|
|
|
|
for _, test := range tests {
|
|
|
|
|
b := &BoardState{
|
|
|
|
|
Height: 11,
|
|
|
|
|
Width: 11,
|
|
|
|
|
Snakes: test.Snakes,
|
|
|
|
|
Food: []Point{},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
actual, err := r.IsGameOver(b)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Equal(t, test.Expected, actual)
|
|
|
|
|
}
|
|
|
|
|
}
|