Byte-snake-engine/ruleset_test.go
Rob O'Dwyer 82e1999126
DEV-1761: New rules API (#118)
* DEV-1761: Clean up Ruleset interface (#115)

* remove legacy ruleset types and simplify ruleset interface

* remove unnecessary settings argument from Ruleset interface

* decouple rules.Settings from client API and store settings as strings

* DEV 1761: Add new BoardState and Point fields (#117)

* add Point.TTL, Point.Value, GameState and PointState to BoardState

* allow maps to access BoardState.GameState,PointState

* add PreUpdateBoard and refactor snail_mode with it

* fix bug where an extra turn was printed to the console

* fix formatting

* fix lint errors

Co-authored-by: JonathanArns <jonathan.arns@googlemail.com>
2022-10-28 16:49:49 -07:00

163 lines
4.2 KiB
Go

package rules_test
import (
"fmt"
"testing"
"github.com/BattlesnakeOfficial/rules"
"github.com/stretchr/testify/require"
)
func TestRulesetBuilder(t *testing.T) {
// Test that a fresh instance can produce a Ruleset
require.NotNil(t, rules.NewRulesetBuilder().NamedRuleset(""))
require.Equal(t, rules.GameTypeStandard, rules.NewRulesetBuilder().NamedRuleset("").Name(), "should default to standard game")
// make sure it works okay for lots of game types
expectedResults := []struct {
GameType string
}{
{GameType: rules.GameTypeStandard},
{GameType: rules.GameTypeWrapped},
{GameType: rules.GameTypeRoyale},
{GameType: rules.GameTypeSolo},
{GameType: rules.GameTypeConstrictor},
{GameType: rules.GameTypeWrappedConstrictor},
}
for _, expected := range expectedResults {
t.Run(expected.GameType, func(t *testing.T) {
rsb := rules.NewRulesetBuilder()
rsb.WithParams(map[string]string{
// apply the standard rule params
rules.ParamFoodSpawnChance: "10",
rules.ParamMinimumFood: "5",
rules.ParamHazardDamagePerTurn: "12",
})
require.NotNil(t, rsb.NamedRuleset(expected.GameType))
require.Equal(t, expected.GameType, rsb.NamedRuleset(expected.GameType).Name())
// All the standard settings should always be copied over
require.Equal(t, 10, rsb.NamedRuleset(expected.GameType).Settings().Int(rules.ParamFoodSpawnChance, 0))
require.Equal(t, 12, rsb.NamedRuleset(expected.GameType).Settings().Int(rules.ParamHazardDamagePerTurn, 0))
require.Equal(t, 5, rsb.NamedRuleset(expected.GameType).Settings().Int(rules.ParamMinimumFood, 0))
})
}
}
func TestRulesetBuilderGameOver(t *testing.T) {
settings := rules.NewSettingsWithParams(rules.ParamShrinkEveryNTurns, "12")
moves := []rules.SnakeMove{
{ID: "1", Move: "up"},
}
boardState := rules.NewBoardState(7, 7)
boardState.Snakes = append(boardState.Snakes, rules.Snake{
ID: "1",
Body: []rules.Point{
{X: 3, Y: 3},
{X: 3, Y: 3},
{X: 3, Y: 3},
},
Health: 100,
})
tests := []struct {
gameType string
solo bool
gameOver bool
}{
{
gameType: rules.GameTypeStandard,
solo: false,
gameOver: true,
},
{
gameType: rules.GameTypeConstrictor,
solo: false,
gameOver: true,
},
{
gameType: rules.GameTypeRoyale,
solo: false,
gameOver: true,
},
{
gameType: rules.GameTypeWrapped,
solo: false,
gameOver: true,
},
{
gameType: rules.GameTypeSolo,
solo: false,
gameOver: false,
},
{
gameType: rules.GameTypeStandard,
solo: true,
gameOver: false,
},
{
gameType: rules.GameTypeConstrictor,
solo: true,
gameOver: false,
},
{
gameType: rules.GameTypeRoyale,
solo: true,
gameOver: false,
},
{
gameType: rules.GameTypeWrapped,
solo: true,
gameOver: false,
},
}
for _, test := range tests {
t.Run(fmt.Sprintf("%v_%v", test.gameType, test.solo), func(t *testing.T) {
rsb := rules.NewRulesetBuilder().WithSettings(settings).WithSolo(test.solo)
ruleset := rsb.NamedRuleset(test.gameType)
gameOver, _, err := ruleset.Execute(boardState, moves)
require.NoError(t, err)
require.Equal(t, test.gameOver, gameOver)
})
}
}
func TestStageFuncContract(t *testing.T) {
//nolint:gosimple
var stage rules.StageFunc
stage = func(bs *rules.BoardState, s rules.Settings, sm []rules.SnakeMove) (bool, error) {
return true, nil
}
ended, err := stage(nil, rules.NewRulesetBuilder().NamedRuleset("").Settings(), nil)
require.NoError(t, err)
require.True(t, ended)
}
func TestRulesetBuilderGetRand(t *testing.T) {
var seed int64 = 12345
var turn int = 5
ruleset := rules.NewRulesetBuilder().WithSeed(seed).PipelineRuleset("example", rules.NewPipeline(rules.StageGameOverStandard))
rand1 := ruleset.Settings().GetRand(turn)
// Should produce a predictable series of numbers based on a seed
require.Equal(t, 83, rand1.Intn(100))
require.Equal(t, 15, rand1.Intn(100))
// Should produce the same number if re-initialized
require.Equal(
t,
ruleset.Settings().GetRand(turn).Intn(100),
ruleset.Settings().GetRand(turn).Intn(100),
)
// Should produce a different series of numbers for another turn
require.Equal(t, 69, rand1.Intn(100))
require.Equal(t, 86, rand1.Intn(100))
}