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>
This commit is contained in:
parent
639362ef46
commit
82e1999126
50 changed files with 1349 additions and 1610 deletions
|
|
@ -63,7 +63,7 @@ func (m ArcadeMazeMap) SetupBoard(initialBoardState *rules.BoardState, settings
|
|||
editor.AddHazard(hazard)
|
||||
}
|
||||
|
||||
if settings.MinimumFood > 0 {
|
||||
if settings.Int(rules.ParamMinimumFood, 0) > 0 {
|
||||
// Add food in center
|
||||
editor.AddFood(rules.Point{X: 9, Y: 11})
|
||||
}
|
||||
|
|
@ -71,11 +71,16 @@ func (m ArcadeMazeMap) SetupBoard(initialBoardState *rules.BoardState, settings
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m ArcadeMazeMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
func (m ArcadeMazeMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m ArcadeMazeMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
rand := settings.GetRand(lastBoardState.Turn)
|
||||
|
||||
// Respect FoodSpawnChance setting
|
||||
if settings.FoodSpawnChance == 0 || rand.Intn(100) > settings.FoodSpawnChance {
|
||||
foodSpawnChance := settings.Int(rules.ParamFoodSpawnChance, 0)
|
||||
if foodSpawnChance == 0 || rand.Intn(100) > foodSpawnChance {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -136,7 +136,11 @@ func (m CastleWallMediumHazardsMap) SetupBoard(initialBoardState *rules.BoardSta
|
|||
return setupCastleWallBoard(m.Meta().MaxPlayers, startPositions, castleWallMediumHazards, initialBoardState, settings, editor)
|
||||
}
|
||||
|
||||
func (m CastleWallMediumHazardsMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
func (m CastleWallMediumHazardsMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m CastleWallMediumHazardsMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
maxFood := 2
|
||||
return updateCastleWallBoard(maxFood, castleWallMediumFood, lastBoardState, settings, editor)
|
||||
}
|
||||
|
|
@ -228,7 +232,11 @@ func (m CastleWallLargeHazardsMap) SetupBoard(initialBoardState *rules.BoardStat
|
|||
return setupCastleWallBoard(m.Meta().MaxPlayers, startPositions, castleWallLargeHazards, initialBoardState, settings, editor)
|
||||
}
|
||||
|
||||
func (m CastleWallLargeHazardsMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
func (m CastleWallLargeHazardsMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m CastleWallLargeHazardsMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
maxFood := 2
|
||||
return updateCastleWallBoard(maxFood, castleWallLargeFood, lastBoardState, settings, editor)
|
||||
}
|
||||
|
|
@ -420,7 +428,11 @@ func (m CastleWallExtraLargeHazardsMap) SetupBoard(initialBoardState *rules.Boar
|
|||
return setupCastleWallBoard(m.Meta().MaxPlayers, startPositions, castleWallExtraLargeHazards, initialBoardState, settings, editor)
|
||||
}
|
||||
|
||||
func (m CastleWallExtraLargeHazardsMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
func (m CastleWallExtraLargeHazardsMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m CastleWallExtraLargeHazardsMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
maxFood := 4
|
||||
return updateCastleWallBoard(maxFood, castleWallExtraLargeFood, lastBoardState, settings, editor)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,10 @@ func (m EmptyMap) SetupBoard(initialBoardState *rules.BoardState, settings rules
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m EmptyMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
func (m EmptyMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m EmptyMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,95 +28,53 @@ func TestEmptyMapSetupBoard(t *testing.T) {
|
|||
"empty 7x7",
|
||||
rules.NewBoardState(7, 7),
|
||||
rules.MinRand,
|
||||
&rules.BoardState{
|
||||
Width: 7,
|
||||
Height: 7,
|
||||
Snakes: []rules.Snake{},
|
||||
Food: []rules.Point{},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.NewBoardState(7, 7),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"not enough room for snakes 7x7",
|
||||
&rules.BoardState{
|
||||
Width: 7,
|
||||
Height: 7,
|
||||
Snakes: generateSnakes(17),
|
||||
Food: []rules.Point{},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.NewBoardState(7, 7).WithSnakes(generateSnakes(17)),
|
||||
rules.MinRand,
|
||||
nil,
|
||||
rules.ErrorTooManySnakes,
|
||||
},
|
||||
{
|
||||
"not enough room for snakes 5x5",
|
||||
&rules.BoardState{
|
||||
Width: 5,
|
||||
Height: 5,
|
||||
Snakes: generateSnakes(14),
|
||||
Food: []rules.Point{},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.NewBoardState(5, 5).WithSnakes(generateSnakes(14)),
|
||||
rules.MinRand,
|
||||
nil,
|
||||
rules.ErrorTooManySnakes,
|
||||
},
|
||||
{
|
||||
"full 11x11 min",
|
||||
&rules.BoardState{
|
||||
Width: 11,
|
||||
Height: 11,
|
||||
Snakes: generateSnakes(8),
|
||||
Food: []rules.Point{},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.NewBoardState(11, 11).WithSnakes(generateSnakes(8)),
|
||||
rules.MinRand,
|
||||
&rules.BoardState{
|
||||
Width: 11,
|
||||
Height: 11,
|
||||
Snakes: []rules.Snake{
|
||||
{ID: "1", Body: []rules.Point{{X: 1, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100},
|
||||
{ID: "2", Body: []rules.Point{{X: 1, Y: 9}, {X: 1, Y: 9}, {X: 1, Y: 9}}, Health: 100},
|
||||
{ID: "3", Body: []rules.Point{{X: 9, Y: 1}, {X: 9, Y: 1}, {X: 9, Y: 1}}, Health: 100},
|
||||
{ID: "4", Body: []rules.Point{{X: 9, Y: 9}, {X: 9, Y: 9}, {X: 9, Y: 9}}, Health: 100},
|
||||
{ID: "5", Body: []rules.Point{{X: 1, Y: 5}, {X: 1, Y: 5}, {X: 1, Y: 5}}, Health: 100},
|
||||
{ID: "6", Body: []rules.Point{{X: 5, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 1}}, Health: 100},
|
||||
{ID: "7", Body: []rules.Point{{X: 5, Y: 9}, {X: 5, Y: 9}, {X: 5, Y: 9}}, Health: 100},
|
||||
{ID: "8", Body: []rules.Point{{X: 9, Y: 5}, {X: 9, Y: 5}, {X: 9, Y: 5}}, Health: 100},
|
||||
},
|
||||
Food: []rules.Point{},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.NewBoardState(11, 11).WithSnakes([]rules.Snake{
|
||||
{ID: "1", Body: []rules.Point{{X: 1, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100},
|
||||
{ID: "2", Body: []rules.Point{{X: 1, Y: 9}, {X: 1, Y: 9}, {X: 1, Y: 9}}, Health: 100},
|
||||
{ID: "3", Body: []rules.Point{{X: 9, Y: 1}, {X: 9, Y: 1}, {X: 9, Y: 1}}, Health: 100},
|
||||
{ID: "4", Body: []rules.Point{{X: 9, Y: 9}, {X: 9, Y: 9}, {X: 9, Y: 9}}, Health: 100},
|
||||
{ID: "5", Body: []rules.Point{{X: 1, Y: 5}, {X: 1, Y: 5}, {X: 1, Y: 5}}, Health: 100},
|
||||
{ID: "6", Body: []rules.Point{{X: 5, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 1}}, Health: 100},
|
||||
{ID: "7", Body: []rules.Point{{X: 5, Y: 9}, {X: 5, Y: 9}, {X: 5, Y: 9}}, Health: 100},
|
||||
{ID: "8", Body: []rules.Point{{X: 9, Y: 5}, {X: 9, Y: 5}, {X: 9, Y: 5}}, Health: 100},
|
||||
}),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"full 11x11 max",
|
||||
&rules.BoardState{
|
||||
Width: 11,
|
||||
Height: 11,
|
||||
Snakes: generateSnakes(8),
|
||||
Food: []rules.Point{},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.NewBoardState(11, 11).WithSnakes(generateSnakes(8)),
|
||||
rules.MaxRand,
|
||||
&rules.BoardState{
|
||||
Width: 11,
|
||||
Height: 11,
|
||||
Snakes: []rules.Snake{
|
||||
{ID: "1", Body: []rules.Point{{X: 5, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 1}}, Health: 100},
|
||||
{ID: "2", Body: []rules.Point{{X: 5, Y: 9}, {X: 5, Y: 9}, {X: 5, Y: 9}}, Health: 100},
|
||||
{ID: "3", Body: []rules.Point{{X: 9, Y: 5}, {X: 9, Y: 5}, {X: 9, Y: 5}}, Health: 100},
|
||||
{ID: "4", Body: []rules.Point{{X: 1, Y: 5}, {X: 1, Y: 5}, {X: 1, Y: 5}}, Health: 100},
|
||||
{ID: "5", Body: []rules.Point{{X: 1, Y: 9}, {X: 1, Y: 9}, {X: 1, Y: 9}}, Health: 100},
|
||||
{ID: "6", Body: []rules.Point{{X: 9, Y: 1}, {X: 9, Y: 1}, {X: 9, Y: 1}}, Health: 100},
|
||||
{ID: "7", Body: []rules.Point{{X: 9, Y: 9}, {X: 9, Y: 9}, {X: 9, Y: 9}}, Health: 100},
|
||||
{ID: "8", Body: []rules.Point{{X: 1, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100},
|
||||
},
|
||||
Food: []rules.Point{},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.NewBoardState(11, 11).WithSnakes([]rules.Snake{
|
||||
{ID: "1", Body: []rules.Point{{X: 5, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 1}}, Health: 100},
|
||||
{ID: "2", Body: []rules.Point{{X: 5, Y: 9}, {X: 5, Y: 9}, {X: 5, Y: 9}}, Health: 100},
|
||||
{ID: "3", Body: []rules.Point{{X: 9, Y: 5}, {X: 9, Y: 5}, {X: 9, Y: 5}}, Health: 100},
|
||||
{ID: "4", Body: []rules.Point{{X: 1, Y: 5}, {X: 1, Y: 5}, {X: 1, Y: 5}}, Health: 100},
|
||||
{ID: "5", Body: []rules.Point{{X: 1, Y: 9}, {X: 1, Y: 9}, {X: 1, Y: 9}}, Health: 100},
|
||||
{ID: "6", Body: []rules.Point{{X: 9, Y: 1}, {X: 9, Y: 1}, {X: 9, Y: 1}}, Health: 100},
|
||||
{ID: "7", Body: []rules.Point{{X: 9, Y: 9}, {X: 9, Y: 9}, {X: 9, Y: 9}}, Health: 100},
|
||||
{ID: "8", Body: []rules.Point{{X: 1, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100},
|
||||
}),
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
|
@ -139,27 +97,13 @@ func TestEmptyMapSetupBoard(t *testing.T) {
|
|||
|
||||
func TestEmptyMapUpdateBoard(t *testing.T) {
|
||||
m := maps.EmptyMap{}
|
||||
initialBoardState := &rules.BoardState{
|
||||
Width: 2,
|
||||
Height: 2,
|
||||
Snakes: []rules.Snake{},
|
||||
Food: []rules.Point{{X: 0, Y: 0}},
|
||||
Hazards: []rules.Point{},
|
||||
}
|
||||
settings := rules.Settings{
|
||||
FoodSpawnChance: 50,
|
||||
MinimumFood: 2,
|
||||
}.WithRand(rules.MaxRand)
|
||||
initialBoardState := rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 0}})
|
||||
settings := rules.NewSettingsWithParams(rules.ParamFoodSpawnChance, "50", rules.ParamMinimumFood, "2").WithRand(rules.MaxRand)
|
||||
nextBoardState := initialBoardState.Clone()
|
||||
|
||||
err := m.UpdateBoard(initialBoardState.Clone(), settings, maps.NewBoardStateEditor(nextBoardState))
|
||||
err := m.PostUpdateBoard(initialBoardState.Clone(), settings, maps.NewBoardStateEditor(nextBoardState))
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, &rules.BoardState{
|
||||
Width: 2,
|
||||
Height: 2,
|
||||
Snakes: []rules.Snake{},
|
||||
Food: []rules.Point{{X: 0, Y: 0}},
|
||||
Hazards: []rules.Point{},
|
||||
}, nextBoardState)
|
||||
expectedBoardState := rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 0}})
|
||||
require.Equal(t, expectedBoardState, nextBoardState)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,8 +24,21 @@ type GameMap interface {
|
|||
// Called to generate a new board. The map is responsible for placing all snakes, food, and hazards.
|
||||
SetupBoard(initialBoardState *rules.BoardState, settings rules.Settings, editor Editor) error
|
||||
|
||||
// Called every turn to optionally update the board.
|
||||
UpdateBoard(previousBoardState *rules.BoardState, settings rules.Settings, editor Editor) error
|
||||
// Called every turn to optionally update the board before the board is sent to snakes to get their moves.
|
||||
// Changes made here will be seen by snakes before before making their moves, but users in the
|
||||
// browser will see the changes at the same time as the snakes' moves.
|
||||
//
|
||||
// State that is stored in the map by this method will be visible to the PostUpdateBoard method
|
||||
// later in the same turn, but will not nessecarily be available when processing later turns.
|
||||
//
|
||||
// Disclaimer: Unless you have a specific usecase like moving hazards or storing intermediate state,
|
||||
// PostUpdateBoard is probably the better function to use.
|
||||
PreUpdateBoard(previousBoardState *rules.BoardState, settings rules.Settings, editor Editor) error
|
||||
|
||||
// Called every turn to optionally update the board after all other rules have been applied.
|
||||
// Changes made here will be seen by both snakes and users in the browser, before before snakes
|
||||
// make their next moves.
|
||||
PostUpdateBoard(previousBoardState *rules.BoardState, settings rules.Settings, editor Editor) error
|
||||
}
|
||||
|
||||
type Metadata struct {
|
||||
|
|
@ -166,6 +179,12 @@ type Editor interface {
|
|||
// Note: the body values in the return value are a copy and modifying them won't affect the board.
|
||||
SnakeBodies() map[string][]rules.Point
|
||||
|
||||
// Get an editable reference to the BoardState's GameState field
|
||||
GameState() map[string]string
|
||||
|
||||
// Get an editable reference to the BoardState's PointState field
|
||||
PointState() map[rules.Point]int
|
||||
|
||||
// Given a list of Snakes and a list of head coordinates, randomly place
|
||||
// the snakes on those coordinates, or return an error if placement of all
|
||||
// Snakes is impossible.
|
||||
|
|
@ -270,6 +289,16 @@ func (editor *BoardStateEditor) SnakeBodies() map[string][]rules.Point {
|
|||
return result
|
||||
}
|
||||
|
||||
// Get an editable reference to the BoardState's GameState field
|
||||
func (editor *BoardStateEditor) GameState() map[string]string {
|
||||
return editor.boardState.GameState
|
||||
}
|
||||
|
||||
// Get an editable reference to the BoardState's PointState field
|
||||
func (editor *BoardStateEditor) PointState() map[rules.Point]int {
|
||||
return editor.boardState.PointState
|
||||
}
|
||||
|
||||
// Given a list of Snakes and a list of head coordinates, randomly place
|
||||
// the snakes on those coordinates, or return an error if placement of all
|
||||
// Snakes is impossible.
|
||||
|
|
|
|||
|
|
@ -135,18 +135,16 @@ func TestBoardStateEditor(t *testing.T) {
|
|||
editor.PlaceSnake("existing_snake", []rules.Point{{X: 5, Y: 2}, {X: 5, Y: 1}, {X: 5, Y: 0}}, 99)
|
||||
editor.PlaceSnake("new_snake", []rules.Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 1}}, 98)
|
||||
|
||||
require.Equal(t, &rules.BoardState{
|
||||
Width: 11,
|
||||
Height: 11,
|
||||
Food: []rules.Point{
|
||||
expected := rules.NewBoardState(11, 11).
|
||||
WithFood([]rules.Point{
|
||||
{X: 1, Y: 3},
|
||||
{X: 3, Y: 7},
|
||||
},
|
||||
Hazards: []rules.Point{
|
||||
}).
|
||||
WithHazards([]rules.Point{
|
||||
{X: 1, Y: 3},
|
||||
{X: 3, Y: 7},
|
||||
},
|
||||
Snakes: []rules.Snake{
|
||||
}).
|
||||
WithSnakes([]rules.Snake{
|
||||
{
|
||||
ID: "existing_snake",
|
||||
Health: 99,
|
||||
|
|
@ -157,8 +155,8 @@ func TestBoardStateEditor(t *testing.T) {
|
|||
Health: 98,
|
||||
Body: []rules.Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 1}},
|
||||
},
|
||||
},
|
||||
}, boardState)
|
||||
})
|
||||
require.Equal(t, expected, boardState)
|
||||
|
||||
require.Equal(t, []rules.Point{
|
||||
{X: 1, Y: 3},
|
||||
|
|
|
|||
|
|
@ -97,8 +97,12 @@ func (m HazardPitsMap) SetupBoard(initialBoardState *rules.BoardState, settings
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m HazardPitsMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
err := StandardMap{}.UpdateBoard(lastBoardState, settings, editor)
|
||||
func (m HazardPitsMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m HazardPitsMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
err := StandardMap{}.PostUpdateBoard(lastBoardState, settings, editor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -109,9 +113,10 @@ func (m HazardPitsMap) UpdateBoard(lastBoardState *rules.BoardState, settings ru
|
|||
// Cycle 3 - 3 layers
|
||||
// Cycle 4-6 - 4 layers of hazards
|
||||
|
||||
if lastBoardState.Turn%settings.RoyaleSettings.ShrinkEveryNTurns == 0 {
|
||||
shrinkEveryNTurns := settings.Int(rules.ParamShrinkEveryNTurns, 0)
|
||||
if lastBoardState.Turn%shrinkEveryNTurns == 0 {
|
||||
// Is it time to update the hazards
|
||||
layers := (lastBoardState.Turn / settings.RoyaleSettings.ShrinkEveryNTurns) % 7
|
||||
layers := (lastBoardState.Turn / shrinkEveryNTurns) % 7
|
||||
if layers > 4 {
|
||||
layers = 4
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ func TestHazardPitsMap(t *testing.T) {
|
|||
|
||||
state = rules.NewBoardState(int(11), int(11))
|
||||
m = maps.HazardPitsMap{}
|
||||
settings.RoyaleSettings.ShrinkEveryNTurns = 1
|
||||
settings = rules.NewSettingsWithParams(rules.ParamShrinkEveryNTurns, "1")
|
||||
editor = maps.NewBoardStateEditor(state)
|
||||
require.Empty(t, state.Hazards)
|
||||
err = m.SetupBoard(state, settings, editor)
|
||||
|
|
@ -47,7 +47,7 @@ func TestHazardPitsMap(t *testing.T) {
|
|||
// Verify the hazard progression through the turns
|
||||
for i := 0; i < 16; i++ {
|
||||
state.Turn = i
|
||||
err = m.UpdateBoard(state, settings, editor)
|
||||
err = m.PostUpdateBoard(state, settings, editor)
|
||||
require.NoError(t, err)
|
||||
if i == 1 {
|
||||
require.Len(t, state.Hazards, 21)
|
||||
|
|
|
|||
|
|
@ -54,8 +54,12 @@ func (m InnerBorderHazardsMap) SetupBoard(lastBoardState *rules.BoardState, sett
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m InnerBorderHazardsMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return StandardMap{}.UpdateBoard(lastBoardState, settings, editor)
|
||||
func (m InnerBorderHazardsMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m InnerBorderHazardsMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return StandardMap{}.PostUpdateBoard(lastBoardState, settings, editor)
|
||||
}
|
||||
|
||||
type ConcentricRingsHazardsMap struct{}
|
||||
|
|
@ -96,8 +100,12 @@ func (m ConcentricRingsHazardsMap) SetupBoard(lastBoardState *rules.BoardState,
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m ConcentricRingsHazardsMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return StandardMap{}.UpdateBoard(lastBoardState, settings, editor)
|
||||
func (m ConcentricRingsHazardsMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m ConcentricRingsHazardsMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return StandardMap{}.PostUpdateBoard(lastBoardState, settings, editor)
|
||||
}
|
||||
|
||||
type ColumnsHazardsMap struct{}
|
||||
|
|
@ -135,8 +143,12 @@ func (m ColumnsHazardsMap) SetupBoard(lastBoardState *rules.BoardState, settings
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m ColumnsHazardsMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return StandardMap{}.UpdateBoard(lastBoardState, settings, editor)
|
||||
func (m ColumnsHazardsMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m ColumnsHazardsMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return StandardMap{}.PostUpdateBoard(lastBoardState, settings, editor)
|
||||
}
|
||||
|
||||
type SpiralHazardsMap struct{}
|
||||
|
|
@ -163,8 +175,12 @@ func (m SpiralHazardsMap) SetupBoard(lastBoardState *rules.BoardState, settings
|
|||
return (StandardMap{}).SetupBoard(lastBoardState, settings, editor)
|
||||
}
|
||||
|
||||
func (m SpiralHazardsMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
err := StandardMap{}.UpdateBoard(lastBoardState, settings, editor)
|
||||
func (m SpiralHazardsMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m SpiralHazardsMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
err := StandardMap{}.PostUpdateBoard(lastBoardState, settings, editor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -256,8 +272,12 @@ func (m ScatterFillMap) SetupBoard(lastBoardState *rules.BoardState, settings ru
|
|||
return (StandardMap{}).SetupBoard(lastBoardState, settings, editor)
|
||||
}
|
||||
|
||||
func (m ScatterFillMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
err := StandardMap{}.UpdateBoard(lastBoardState, settings, editor)
|
||||
func (m ScatterFillMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m ScatterFillMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
err := StandardMap{}.PostUpdateBoard(lastBoardState, settings, editor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -308,8 +328,12 @@ func (m DirectionalExpandingBoxMap) SetupBoard(lastBoardState *rules.BoardState,
|
|||
return (StandardMap{}).SetupBoard(lastBoardState, settings, editor)
|
||||
}
|
||||
|
||||
func (m DirectionalExpandingBoxMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
err := StandardMap{}.UpdateBoard(lastBoardState, settings, editor)
|
||||
func (m DirectionalExpandingBoxMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m DirectionalExpandingBoxMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
err := StandardMap{}.PostUpdateBoard(lastBoardState, settings, editor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -423,8 +447,12 @@ func (m ExpandingBoxMap) SetupBoard(lastBoardState *rules.BoardState, settings r
|
|||
return (StandardMap{}).SetupBoard(lastBoardState, settings, editor)
|
||||
}
|
||||
|
||||
func (m ExpandingBoxMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
err := StandardMap{}.UpdateBoard(lastBoardState, settings, editor)
|
||||
func (m ExpandingBoxMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m ExpandingBoxMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
err := StandardMap{}.PostUpdateBoard(lastBoardState, settings, editor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -499,8 +527,12 @@ func (m ExpandingScatterMap) SetupBoard(lastBoardState *rules.BoardState, settin
|
|||
return (StandardMap{}).SetupBoard(lastBoardState, settings, editor)
|
||||
}
|
||||
|
||||
func (m ExpandingScatterMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
err := StandardMap{}.UpdateBoard(lastBoardState, settings, editor)
|
||||
func (m ExpandingScatterMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return (StandardMap{}).PreUpdateBoard(lastBoardState, settings, editor)
|
||||
}
|
||||
|
||||
func (m ExpandingScatterMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
err := StandardMap{}.PostUpdateBoard(lastBoardState, settings, editor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ func TestSpiralHazardsMap(t *testing.T) {
|
|||
|
||||
for i := 0; i < 1000; i++ {
|
||||
state.Turn = i
|
||||
err = m.UpdateBoard(state, settings, editor)
|
||||
err = m.PostUpdateBoard(state, settings, editor)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
require.NotEmpty(t, state.Hazards)
|
||||
|
|
@ -123,7 +123,7 @@ func TestScatterFillMap(t *testing.T) {
|
|||
totalTurns := 11 * 11 * 2
|
||||
for i := 0; i < totalTurns; i++ {
|
||||
state.Turn = i
|
||||
err = m.UpdateBoard(state, settings, editor)
|
||||
err = m.PostUpdateBoard(state, settings, editor)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
require.NotEmpty(t, state.Hazards)
|
||||
|
|
@ -144,7 +144,7 @@ func TestDirectionalExpandingBoxMap(t *testing.T) {
|
|||
totalTurns := 1000
|
||||
for i := 0; i < totalTurns; i++ {
|
||||
state.Turn = i
|
||||
err = m.UpdateBoard(state, settings, editor)
|
||||
err = m.PostUpdateBoard(state, settings, editor)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
require.NotEmpty(t, state.Hazards)
|
||||
|
|
@ -165,7 +165,7 @@ func TestExpandingBoxMap(t *testing.T) {
|
|||
totalTurns := 1000
|
||||
for i := 0; i < totalTurns; i++ {
|
||||
state.Turn = i
|
||||
err = m.UpdateBoard(state, settings, editor)
|
||||
err = m.PostUpdateBoard(state, settings, editor)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
require.NotEmpty(t, state.Hazards)
|
||||
|
|
@ -186,7 +186,7 @@ func TestExpandingScatterMap(t *testing.T) {
|
|||
totalTurns := 1000
|
||||
for i := 0; i < totalTurns; i++ {
|
||||
state.Turn = i
|
||||
err = m.UpdateBoard(state, settings, editor)
|
||||
err = m.PostUpdateBoard(state, settings, editor)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
require.NotEmpty(t, state.Hazards)
|
||||
|
|
|
|||
|
|
@ -50,12 +50,17 @@ func (m HealingPoolsMap) SetupBoard(initialBoardState *rules.BoardState, setting
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m HealingPoolsMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
if err := (StandardMap{}).UpdateBoard(lastBoardState, settings, editor); err != nil {
|
||||
func (m HealingPoolsMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m HealingPoolsMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
if err := (StandardMap{}).PostUpdateBoard(lastBoardState, settings, editor); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if lastBoardState.Turn > 0 && settings.RoyaleSettings.ShrinkEveryNTurns > 0 && len(lastBoardState.Hazards) > 0 && lastBoardState.Turn%settings.RoyaleSettings.ShrinkEveryNTurns == 0 {
|
||||
shrinkEveryNTurns := settings.Int(rules.ParamShrinkEveryNTurns, 0)
|
||||
if lastBoardState.Turn > 0 && shrinkEveryNTurns > 0 && len(lastBoardState.Hazards) > 0 && lastBoardState.Turn%shrinkEveryNTurns == 0 {
|
||||
// Attempt to remove a healing pool every ShrinkEveryNTurns until there are none remaining
|
||||
i := rand.Intn(len(lastBoardState.Hazards))
|
||||
editor.RemoveHazard(lastBoardState.Hazards[i])
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ func TestHealingPoolsMap(t *testing.T) {
|
|||
t.Run(fmt.Sprintf("%dx%d", tc.boardSize, tc.boardSize), func(t *testing.T) {
|
||||
m := maps.HealingPoolsMap{}
|
||||
state := rules.NewBoardState(tc.boardSize, tc.boardSize)
|
||||
settings := rules.Settings{}
|
||||
settings.RoyaleSettings.ShrinkEveryNTurns = 10
|
||||
shrinkEveryNTurns := 10
|
||||
settings := rules.NewSettingsWithParams(rules.ParamShrinkEveryNTurns, fmt.Sprint(shrinkEveryNTurns))
|
||||
|
||||
// ensure the hazards are added to the board at setup
|
||||
editor := maps.NewBoardStateEditor(state)
|
||||
|
|
@ -56,10 +56,10 @@ func TestHealingPoolsMap(t *testing.T) {
|
|||
}
|
||||
|
||||
// ensure the hazards are removed
|
||||
totalTurns := settings.RoyaleSettings.ShrinkEveryNTurns*tc.expectedHazards + 1
|
||||
totalTurns := shrinkEveryNTurns*tc.expectedHazards + 1
|
||||
for i := 0; i < totalTurns; i++ {
|
||||
state.Turn = i
|
||||
err = m.UpdateBoard(state, settings, editor)
|
||||
err = m.PostUpdateBoard(state, settings, editor)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,17 +25,24 @@ func SetupBoard(mapID string, settings rules.Settings, width, height int, snakeI
|
|||
return boardState, nil
|
||||
}
|
||||
|
||||
// UpdateBoard is a shortcut for looking up a map by ID and updating an existing board state with it.
|
||||
func UpdateBoard(mapID string, previousBoardState *rules.BoardState, settings rules.Settings) (*rules.BoardState, error) {
|
||||
gameMap, err := GetMap(mapID)
|
||||
// PreUpdateBoard updates a board state with a map.
|
||||
func PreUpdateBoard(gameMap GameMap, previousBoardState *rules.BoardState, settings rules.Settings) (*rules.BoardState, error) {
|
||||
nextBoardState := previousBoardState.Clone()
|
||||
editor := NewBoardStateEditor(nextBoardState)
|
||||
|
||||
err := gameMap.PreUpdateBoard(previousBoardState, settings, editor)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nextBoardState, nil
|
||||
}
|
||||
|
||||
func PostUpdateBoard(gameMap GameMap, previousBoardState *rules.BoardState, settings rules.Settings) (*rules.BoardState, error) {
|
||||
nextBoardState := previousBoardState.Clone()
|
||||
editor := NewBoardStateEditor(nextBoardState)
|
||||
|
||||
err = gameMap.UpdateBoard(previousBoardState, settings, editor)
|
||||
err := gameMap.PostUpdateBoard(previousBoardState, settings, editor)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -77,7 +84,11 @@ func (m StubMap) SetupBoard(initialBoardState *rules.BoardState, settings rules.
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m StubMap) UpdateBoard(previousBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
func (m StubMap) PreUpdateBoard(previousBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m StubMap) PostUpdateBoard(previousBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
if m.Error != nil {
|
||||
return m.Error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,11 +82,10 @@ func TestUpdateBoard(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
previousBoardState := &rules.BoardState{
|
||||
Turn: 0,
|
||||
Food: []rules.Point{{X: 0, Y: 1}},
|
||||
Hazards: []rules.Point{{X: 3, Y: 4}},
|
||||
Snakes: []rules.Snake{
|
||||
previousBoardState := rules.NewBoardState(5, 5).
|
||||
WithFood([]rules.Point{{X: 0, Y: 1}}).
|
||||
WithHazards([]rules.Point{{X: 3, Y: 4}}).
|
||||
WithSnakes([]rules.Snake{
|
||||
{
|
||||
ID: "1",
|
||||
Health: 100,
|
||||
|
|
@ -96,11 +95,9 @@ func TestUpdateBoard(t *testing.T) {
|
|||
{X: 6, Y: 2},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
})
|
||||
maps.TestMap(testMap.ID(), testMap, func() {
|
||||
boardState, err := maps.UpdateBoard(testMap.ID(), previousBoardState, rules.Settings{})
|
||||
boardState, err := maps.PostUpdateBoard(testMap, previousBoardState, rules.Settings{})
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,14 +10,12 @@ import (
|
|||
|
||||
const maxBoardWidth, maxBoardHeight = 25, 25
|
||||
|
||||
var testSettings rules.Settings = rules.Settings{
|
||||
FoodSpawnChance: 25,
|
||||
MinimumFood: 1,
|
||||
HazardDamagePerTurn: 14,
|
||||
RoyaleSettings: rules.RoyaleSettings{
|
||||
ShrinkEveryNTurns: 1,
|
||||
},
|
||||
}
|
||||
var testSettings rules.Settings = rules.NewSettings(map[string]string{
|
||||
rules.ParamFoodSpawnChance: "25",
|
||||
rules.ParamMinimumFood: "1",
|
||||
rules.ParamHazardDamagePerTurn: "14",
|
||||
rules.ParamShrinkEveryNTurns: "1",
|
||||
})
|
||||
|
||||
func TestRegisteredMaps(t *testing.T) {
|
||||
for mapName, gameMap := range globalRegistry {
|
||||
|
|
@ -96,7 +94,7 @@ func TestRegisteredMaps(t *testing.T) {
|
|||
|
||||
passedBoardState := previousBoardState.Clone()
|
||||
tempBoardState := previousBoardState.Clone()
|
||||
err := gameMap.UpdateBoard(passedBoardState, testSettings, NewBoardStateEditor(tempBoardState))
|
||||
err := gameMap.PostUpdateBoard(passedBoardState, testSettings, NewBoardStateEditor(tempBoardState))
|
||||
require.NoError(t, err, "GameMap.UpdateBoard returned an error")
|
||||
require.Equal(t, previousBoardState, passedBoardState, "BoardState should not be modified directly by GameMap.UpdateBoard")
|
||||
})
|
||||
|
|
|
|||
|
|
@ -71,7 +71,11 @@ func (m RiverAndBridgesMediumHazardsMap) SetupBoard(initialBoardState *rules.Boa
|
|||
return setupRiverAndBridgesBoard(riversAndBridgesMediumStartPositions, riversAndBridgesMediumHazards, initialBoardState, settings, editor)
|
||||
}
|
||||
|
||||
func (m RiverAndBridgesMediumHazardsMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
func (m RiverAndBridgesMediumHazardsMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m RiverAndBridgesMediumHazardsMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return placeRiverAndBridgesFood(lastBoardState, settings, editor)
|
||||
}
|
||||
|
||||
|
|
@ -142,7 +146,11 @@ func (m RiverAndBridgesLargeHazardsMap) SetupBoard(initialBoardState *rules.Boar
|
|||
return setupRiverAndBridgesBoard(riversAndBridgesLargeStartPositions, riversAndBridgesLargeHazards, initialBoardState, settings, editor)
|
||||
}
|
||||
|
||||
func (m RiverAndBridgesLargeHazardsMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
func (m RiverAndBridgesLargeHazardsMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m RiverAndBridgesLargeHazardsMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return placeRiverAndBridgesFood(lastBoardState, settings, editor)
|
||||
}
|
||||
|
||||
|
|
@ -241,7 +249,11 @@ func (m RiverAndBridgesExtraLargeHazardsMap) SetupBoard(initialBoardState *rules
|
|||
return setupRiverAndBridgesBoard(riversAndBridgesExtraLargeStartPositions, riversAndBridgesExtraLargeHazards, initialBoardState, settings, editor)
|
||||
}
|
||||
|
||||
func (m RiverAndBridgesExtraLargeHazardsMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
func (m RiverAndBridgesExtraLargeHazardsMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m RiverAndBridgesExtraLargeHazardsMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return placeRiverAndBridgesFood(lastBoardState, settings, editor)
|
||||
}
|
||||
|
||||
|
|
@ -355,7 +367,11 @@ func (m IslandsAndBridgesMediumHazardsMap) SetupBoard(initialBoardState *rules.B
|
|||
return setupRiverAndBridgesBoard(islandsAndBridgesMediumStartPositions, islandsAndBridgesMediumHazards, initialBoardState, settings, editor)
|
||||
}
|
||||
|
||||
func (m IslandsAndBridgesMediumHazardsMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
func (m IslandsAndBridgesMediumHazardsMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m IslandsAndBridgesMediumHazardsMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return placeRiverAndBridgesFood(lastBoardState, settings, editor)
|
||||
}
|
||||
|
||||
|
|
@ -441,7 +457,11 @@ func (m IslandsAndBridgesLargeHazardsMap) SetupBoard(initialBoardState *rules.Bo
|
|||
return setupRiverAndBridgesBoard(islandsAndBridgesLargeStartPositions, islandsAndBridgesLargeHazards, initialBoardState, settings, editor)
|
||||
}
|
||||
|
||||
func (m IslandsAndBridgesLargeHazardsMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
func (m IslandsAndBridgesLargeHazardsMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m IslandsAndBridgesLargeHazardsMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return placeRiverAndBridgesFood(lastBoardState, settings, editor)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,20 +33,25 @@ func (m RoyaleHazardsMap) SetupBoard(lastBoardState *rules.BoardState, settings
|
|||
return StandardMap{}.SetupBoard(lastBoardState, settings, editor)
|
||||
}
|
||||
|
||||
func (m RoyaleHazardsMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
func (m RoyaleHazardsMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m RoyaleHazardsMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
// Use StandardMap to populate food
|
||||
if err := (StandardMap{}).UpdateBoard(lastBoardState, settings, editor); err != nil {
|
||||
if err := (StandardMap{}).PostUpdateBoard(lastBoardState, settings, editor); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Royale uses the current turn to generate hazards, not the previous turn that's in the board state
|
||||
turn := lastBoardState.Turn + 1
|
||||
|
||||
if settings.RoyaleSettings.ShrinkEveryNTurns < 1 {
|
||||
shrinkEveryNTurns := settings.Int(rules.ParamShrinkEveryNTurns, 0)
|
||||
if shrinkEveryNTurns < 1 {
|
||||
return errors.New("royale game can't shrink more frequently than every turn")
|
||||
}
|
||||
|
||||
if turn < settings.RoyaleSettings.ShrinkEveryNTurns {
|
||||
if turn < shrinkEveryNTurns {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -56,7 +61,7 @@ func (m RoyaleHazardsMap) UpdateBoard(lastBoardState *rules.BoardState, settings
|
|||
// Get random generator for turn zero, because we're regenerating all hazards every time.
|
||||
randGenerator := settings.GetRand(0)
|
||||
|
||||
numShrinks := turn / settings.RoyaleSettings.ShrinkEveryNTurns
|
||||
numShrinks := turn / shrinkEveryNTurns
|
||||
minX, maxX := 0, lastBoardState.Width-1
|
||||
minY, maxY := 0, lastBoardState.Height-1
|
||||
for i := 0; i < numShrinks; i++ {
|
||||
|
|
|
|||
|
|
@ -33,8 +33,12 @@ func (m SinkholesMap) SetupBoard(initialBoardState *rules.BoardState, settings r
|
|||
return (StandardMap{}).SetupBoard(initialBoardState, settings, editor)
|
||||
}
|
||||
|
||||
func (m SinkholesMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
err := StandardMap{}.UpdateBoard(lastBoardState, settings, editor)
|
||||
func (m SinkholesMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m SinkholesMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
err := StandardMap{}.PostUpdateBoard(lastBoardState, settings, editor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -42,8 +46,9 @@ func (m SinkholesMap) UpdateBoard(lastBoardState *rules.BoardState, settings rul
|
|||
currentTurn := lastBoardState.Turn
|
||||
startTurn := 1
|
||||
spawnEveryNTurns := 10
|
||||
if settings.RoyaleSettings.ShrinkEveryNTurns > 0 {
|
||||
spawnEveryNTurns = settings.RoyaleSettings.ShrinkEveryNTurns
|
||||
shrinkEveryNTurns := settings.Int(rules.ParamShrinkEveryNTurns, 0)
|
||||
if shrinkEveryNTurns > 0 {
|
||||
spawnEveryNTurns = shrinkEveryNTurns
|
||||
}
|
||||
maxRings := 5
|
||||
if lastBoardState.Width == 7 {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ func TestSinkholesMap(t *testing.T) {
|
|||
totalTurns := 100
|
||||
for i := 0; i < totalTurns; i++ {
|
||||
state.Turn = i
|
||||
err = m.UpdateBoard(state, settings, editor)
|
||||
err = m.PostUpdateBoard(state, settings, editor)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
require.NotEmpty(t, state.Hazards)
|
||||
|
|
|
|||
|
|
@ -4,20 +4,22 @@ import (
|
|||
"github.com/BattlesnakeOfficial/rules"
|
||||
)
|
||||
|
||||
type SnailModeMap struct{}
|
||||
type SnailModeMap struct {
|
||||
lastTailPositions map[rules.Point]int // local state is preserved during the turn
|
||||
}
|
||||
|
||||
// init registers this map in the global registry.
|
||||
func init() {
|
||||
globalRegistry.RegisterMap("snail_mode", SnailModeMap{})
|
||||
globalRegistry.RegisterMap("snail_mode", &SnailModeMap{lastTailPositions: nil})
|
||||
}
|
||||
|
||||
// ID returns a unique identifier for this map.
|
||||
func (m SnailModeMap) ID() string {
|
||||
func (m *SnailModeMap) ID() string {
|
||||
return "snail_mode"
|
||||
}
|
||||
|
||||
// Meta returns the non-functional metadata about this map.
|
||||
func (m SnailModeMap) Meta() Metadata {
|
||||
func (m *SnailModeMap) Meta() Metadata {
|
||||
return Metadata{
|
||||
Name: "Snail Mode",
|
||||
Description: "Snakes leave behind a trail of hazards",
|
||||
|
|
@ -31,7 +33,7 @@ func (m SnailModeMap) Meta() Metadata {
|
|||
}
|
||||
|
||||
// SetupBoard here is pretty 'standard' and doesn't do any special setup for this game mode
|
||||
func (m SnailModeMap) SetupBoard(initialBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
func (m *SnailModeMap) SetupBoard(initialBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
rand := settings.GetRand(0)
|
||||
|
||||
if len(initialBoardState.Snakes) > int(m.Meta().MaxPlayers) {
|
||||
|
|
@ -57,23 +59,6 @@ func (m SnailModeMap) SetupBoard(initialBoardState *rules.BoardState, settings r
|
|||
return nil
|
||||
}
|
||||
|
||||
// storeTailLocation returns an offboard point that corresponds to the given point.
|
||||
// This is useful for storing state that can be accessed next turn.
|
||||
func storeTailLocation(point rules.Point, height int) rules.Point {
|
||||
return rules.Point{X: point.X, Y: point.Y + height}
|
||||
}
|
||||
|
||||
// getPrevTailLocation returns the onboard point that corresponds to an offboard point.
|
||||
// This is useful for restoring state that was stored last turn.
|
||||
func getPrevTailLocation(point rules.Point, height int) rules.Point {
|
||||
return rules.Point{X: point.X, Y: point.Y - height}
|
||||
}
|
||||
|
||||
// outOfBounds determines if the given point is out of bounds for the current board size
|
||||
func outOfBounds(p rules.Point, w, h int) bool {
|
||||
return p.X < 0 || p.Y < 0 || p.X >= w || p.Y >= h
|
||||
}
|
||||
|
||||
// doubleTail determine if the snake has a double stacked tail currently
|
||||
func doubleTail(snake *rules.Snake) bool {
|
||||
almostTail := snake.Body[len(snake.Body)-2]
|
||||
|
|
@ -86,12 +71,28 @@ func isEliminated(s *rules.Snake) bool {
|
|||
return s.EliminatedCause != rules.NotEliminated
|
||||
}
|
||||
|
||||
// UpdateBoard does the work of placing the hazards along the 'snail tail' of snakes
|
||||
// This is responsible for saving the current tail location off the board
|
||||
// and restoring the previous tail position. This also handles removing one hazards from
|
||||
// the current stacks so the hazards tails fade as the snake moves away.
|
||||
func (m SnailModeMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
err := StandardMap{}.UpdateBoard(lastBoardState, settings, editor)
|
||||
// PreUpdateBoard stores the tail position of each snake in memory, to be
|
||||
// able to place hazards there after the snakes move.
|
||||
func (m *SnailModeMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
m.lastTailPositions = make(map[rules.Point]int)
|
||||
for _, snake := range lastBoardState.Snakes {
|
||||
if isEliminated(&snake) {
|
||||
continue
|
||||
}
|
||||
// Double tail means that the tail will stay on the same square for more
|
||||
// than one turn, so we don't want to spawn hazards
|
||||
if doubleTail(&snake) {
|
||||
continue
|
||||
}
|
||||
m.lastTailPositions[snake.Body[len(snake.Body)-1]] = len(snake.Body)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PostUpdateBoard does the work of placing the hazards along the 'snail tail' of snakes
|
||||
// This also handles removing one hazards from the current stacks so the hazards tails fade as the snake moves away.
|
||||
func (m *SnailModeMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
err := StandardMap{}.PostUpdateBoard(lastBoardState, settings, editor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -100,79 +101,38 @@ func (m SnailModeMap) UpdateBoard(lastBoardState *rules.BoardState, settings rul
|
|||
// need to be cleared first.
|
||||
editor.ClearHazards()
|
||||
|
||||
// This is a list of all the hazards we want to add for the previous tails
|
||||
// These were stored off board in the previous turn as a way to save state
|
||||
// When we add the locations to this list we have already converted the off-board
|
||||
// points to on-board points
|
||||
tailLocations := make([]rules.Point, 0, len(lastBoardState.Snakes))
|
||||
|
||||
// Count the number of hazards for a given position
|
||||
// Add non-double tail locations to a slice
|
||||
hazardCounts := map[rules.Point]int{}
|
||||
for _, hazard := range lastBoardState.Hazards {
|
||||
|
||||
// discard out of bound
|
||||
if outOfBounds(hazard, lastBoardState.Width, lastBoardState.Height) {
|
||||
onBoardTail := getPrevTailLocation(hazard, lastBoardState.Height)
|
||||
tailLocations = append(tailLocations, onBoardTail)
|
||||
} else {
|
||||
hazardCounts[hazard]++
|
||||
}
|
||||
hazardCounts[hazard]++
|
||||
}
|
||||
|
||||
// Add back existing hazards, but with a stack of 1 less than before.
|
||||
// This has the effect of making the snail-trail disappear over time.
|
||||
for hazard, count := range hazardCounts {
|
||||
|
||||
for i := 0; i < count-1; i++ {
|
||||
editor.AddHazard(hazard)
|
||||
}
|
||||
}
|
||||
|
||||
// Store a stack of hazards for the tail of each snake. This is stored out
|
||||
// of bounds and then applied on the next turn. The stack count is equal
|
||||
// the lenght of the snake.
|
||||
for _, snake := range lastBoardState.Snakes {
|
||||
if isEliminated(&snake) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Double tail means that the tail will stay on the same square for more
|
||||
// than one turn, so we don't want to spawn hazards
|
||||
if doubleTail(&snake) {
|
||||
continue
|
||||
}
|
||||
|
||||
tail := snake.Body[len(snake.Body)-1]
|
||||
offBoardTail := storeTailLocation(tail, lastBoardState.Height)
|
||||
for i := 0; i < len(snake.Body); i++ {
|
||||
editor.AddHazard(offBoardTail)
|
||||
}
|
||||
}
|
||||
|
||||
// Read offboard tails and move them to the board. The offboard tails are
|
||||
// stacked based on the length of the snake
|
||||
for _, p := range tailLocations {
|
||||
|
||||
// Skip position if a snakes head occupies it.
|
||||
// Otherwise hazard shows up in the viewer on top of a snake head, but
|
||||
// does not damage the snake, which is visually confusing.
|
||||
isHead := false
|
||||
// Place a new stack of hazards where each snake's tail used to be
|
||||
NewHazardLoop:
|
||||
for location, count := range m.lastTailPositions {
|
||||
for _, snake := range lastBoardState.Snakes {
|
||||
if isEliminated(&snake) {
|
||||
continue
|
||||
}
|
||||
head := snake.Body[0]
|
||||
if p.X == head.X && p.Y == head.Y {
|
||||
isHead = true
|
||||
break
|
||||
if location.X == head.X && location.Y == head.Y {
|
||||
// Skip position if a snakes head occupies it.
|
||||
// Otherwise hazard shows up in the viewer on top of a snake head, but
|
||||
// does not damage the snake, which is visually confusing.
|
||||
continue NewHazardLoop
|
||||
}
|
||||
}
|
||||
if isHead {
|
||||
continue
|
||||
for i := 0; i < count; i++ {
|
||||
editor.AddHazard(location)
|
||||
}
|
||||
|
||||
editor.AddHazard(p)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -176,7 +176,11 @@ func (m SoloMazeMap) PlaceFood(boardState *rules.BoardState, settings rules.Sett
|
|||
}
|
||||
}
|
||||
|
||||
func (m SoloMazeMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
func (m SoloMazeMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m SoloMazeMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
currentLevel, e := m.ReadBitState(lastBoardState)
|
||||
if e != nil {
|
||||
return e
|
||||
|
|
|
|||
|
|
@ -57,7 +57,11 @@ func (m StandardMap) SetupBoard(initialBoardState *rules.BoardState, settings ru
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m StandardMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
func (m StandardMap) PreUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m StandardMap) PostUpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error {
|
||||
rand := settings.GetRand(lastBoardState.Turn)
|
||||
|
||||
foodNeeded := checkFoodNeedingPlacement(rand, settings, lastBoardState)
|
||||
|
|
@ -69,8 +73,8 @@ func (m StandardMap) UpdateBoard(lastBoardState *rules.BoardState, settings rule
|
|||
}
|
||||
|
||||
func checkFoodNeedingPlacement(rand rules.Rand, settings rules.Settings, state *rules.BoardState) int {
|
||||
minFood := int(settings.MinimumFood)
|
||||
foodSpawnChance := int(settings.FoodSpawnChance)
|
||||
minFood := settings.Int(rules.ParamMinimumFood, 0)
|
||||
foodSpawnChance := settings.Int(rules.ParamFoodSpawnChance, 0)
|
||||
numCurrentFood := len(state.Food)
|
||||
|
||||
if numCurrentFood < minFood {
|
||||
|
|
|
|||
|
|
@ -29,65 +29,29 @@ func TestStandardMapSetupBoard(t *testing.T) {
|
|||
"empty 7x7",
|
||||
rules.NewBoardState(7, 7),
|
||||
rules.MinRand,
|
||||
&rules.BoardState{
|
||||
Width: 7,
|
||||
Height: 7,
|
||||
Snakes: []rules.Snake{},
|
||||
Food: []rules.Point{{X: 3, Y: 3}},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.NewBoardState(7, 7).WithFood([]rules.Point{{X: 3, Y: 3}}),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"not enough room for snakes 7x7",
|
||||
&rules.BoardState{
|
||||
Width: 7,
|
||||
Height: 7,
|
||||
Snakes: generateSnakes(17),
|
||||
Food: []rules.Point{},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.NewBoardState(7, 7).WithSnakes(generateSnakes(17)),
|
||||
rules.MinRand,
|
||||
nil,
|
||||
rules.ErrorTooManySnakes,
|
||||
},
|
||||
{
|
||||
"not enough room for snakes 5x5",
|
||||
&rules.BoardState{
|
||||
Width: 5,
|
||||
Height: 5,
|
||||
Snakes: generateSnakes(14),
|
||||
Food: []rules.Point{},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.NewBoardState(5, 5).WithSnakes(generateSnakes(14)),
|
||||
rules.MinRand,
|
||||
nil,
|
||||
rules.ErrorTooManySnakes,
|
||||
},
|
||||
{
|
||||
"full 11x11 min",
|
||||
&rules.BoardState{
|
||||
Width: 11,
|
||||
Height: 11,
|
||||
Snakes: generateSnakes(8),
|
||||
Food: []rules.Point{},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.NewBoardState(11, 11).WithSnakes(generateSnakes(8)),
|
||||
rules.MinRand,
|
||||
&rules.BoardState{
|
||||
Width: 11,
|
||||
Height: 11,
|
||||
Snakes: []rules.Snake{
|
||||
{ID: "1", Body: []rules.Point{{X: 1, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100},
|
||||
{ID: "2", Body: []rules.Point{{X: 1, Y: 9}, {X: 1, Y: 9}, {X: 1, Y: 9}}, Health: 100},
|
||||
{ID: "3", Body: []rules.Point{{X: 9, Y: 1}, {X: 9, Y: 1}, {X: 9, Y: 1}}, Health: 100},
|
||||
{ID: "4", Body: []rules.Point{{X: 9, Y: 9}, {X: 9, Y: 9}, {X: 9, Y: 9}}, Health: 100},
|
||||
{ID: "5", Body: []rules.Point{{X: 1, Y: 5}, {X: 1, Y: 5}, {X: 1, Y: 5}}, Health: 100},
|
||||
{ID: "6", Body: []rules.Point{{X: 5, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 1}}, Health: 100},
|
||||
{ID: "7", Body: []rules.Point{{X: 5, Y: 9}, {X: 5, Y: 9}, {X: 5, Y: 9}}, Health: 100},
|
||||
{ID: "8", Body: []rules.Point{{X: 9, Y: 5}, {X: 9, Y: 5}, {X: 9, Y: 5}}, Health: 100},
|
||||
},
|
||||
Food: []rules.Point{
|
||||
rules.NewBoardState(11, 11).
|
||||
WithFood([]rules.Point{
|
||||
{X: 0, Y: 2},
|
||||
{X: 0, Y: 8},
|
||||
{X: 8, Y: 0},
|
||||
|
|
@ -97,35 +61,25 @@ func TestStandardMapSetupBoard(t *testing.T) {
|
|||
{X: 4, Y: 10},
|
||||
{X: 10, Y: 4},
|
||||
{X: 5, Y: 5},
|
||||
},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
}).
|
||||
WithSnakes([]rules.Snake{
|
||||
{ID: "1", Body: []rules.Point{{X: 1, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100},
|
||||
{ID: "2", Body: []rules.Point{{X: 1, Y: 9}, {X: 1, Y: 9}, {X: 1, Y: 9}}, Health: 100},
|
||||
{ID: "3", Body: []rules.Point{{X: 9, Y: 1}, {X: 9, Y: 1}, {X: 9, Y: 1}}, Health: 100},
|
||||
{ID: "4", Body: []rules.Point{{X: 9, Y: 9}, {X: 9, Y: 9}, {X: 9, Y: 9}}, Health: 100},
|
||||
{ID: "5", Body: []rules.Point{{X: 1, Y: 5}, {X: 1, Y: 5}, {X: 1, Y: 5}}, Health: 100},
|
||||
{ID: "6", Body: []rules.Point{{X: 5, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 1}}, Health: 100},
|
||||
{ID: "7", Body: []rules.Point{{X: 5, Y: 9}, {X: 5, Y: 9}, {X: 5, Y: 9}}, Health: 100},
|
||||
{ID: "8", Body: []rules.Point{{X: 9, Y: 5}, {X: 9, Y: 5}, {X: 9, Y: 5}}, Health: 100},
|
||||
}),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"full 11x11 max",
|
||||
&rules.BoardState{
|
||||
Width: 11,
|
||||
Height: 11,
|
||||
Snakes: generateSnakes(8),
|
||||
Food: []rules.Point{},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.NewBoardState(11, 11).WithSnakes(generateSnakes(8)),
|
||||
rules.MaxRand,
|
||||
&rules.BoardState{
|
||||
Width: 11,
|
||||
Height: 11,
|
||||
Snakes: []rules.Snake{
|
||||
{ID: "1", Body: []rules.Point{{X: 5, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 1}}, Health: 100},
|
||||
{ID: "2", Body: []rules.Point{{X: 5, Y: 9}, {X: 5, Y: 9}, {X: 5, Y: 9}}, Health: 100},
|
||||
{ID: "3", Body: []rules.Point{{X: 9, Y: 5}, {X: 9, Y: 5}, {X: 9, Y: 5}}, Health: 100},
|
||||
{ID: "4", Body: []rules.Point{{X: 1, Y: 5}, {X: 1, Y: 5}, {X: 1, Y: 5}}, Health: 100},
|
||||
{ID: "5", Body: []rules.Point{{X: 1, Y: 9}, {X: 1, Y: 9}, {X: 1, Y: 9}}, Health: 100},
|
||||
{ID: "6", Body: []rules.Point{{X: 9, Y: 1}, {X: 9, Y: 1}, {X: 9, Y: 1}}, Health: 100},
|
||||
{ID: "7", Body: []rules.Point{{X: 9, Y: 9}, {X: 9, Y: 9}, {X: 9, Y: 9}}, Health: 100},
|
||||
{ID: "8", Body: []rules.Point{{X: 1, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100},
|
||||
},
|
||||
Food: []rules.Point{
|
||||
rules.NewBoardState(11, 11).
|
||||
WithFood([]rules.Point{
|
||||
{X: 6, Y: 0},
|
||||
{X: 6, Y: 10},
|
||||
{X: 10, Y: 6},
|
||||
|
|
@ -135,9 +89,17 @@ func TestStandardMapSetupBoard(t *testing.T) {
|
|||
{X: 10, Y: 8},
|
||||
{X: 2, Y: 0},
|
||||
{X: 5, Y: 5},
|
||||
},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
}).
|
||||
WithSnakes([]rules.Snake{
|
||||
{ID: "1", Body: []rules.Point{{X: 5, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 1}}, Health: 100},
|
||||
{ID: "2", Body: []rules.Point{{X: 5, Y: 9}, {X: 5, Y: 9}, {X: 5, Y: 9}}, Health: 100},
|
||||
{ID: "3", Body: []rules.Point{{X: 9, Y: 5}, {X: 9, Y: 5}, {X: 9, Y: 5}}, Health: 100},
|
||||
{ID: "4", Body: []rules.Point{{X: 1, Y: 5}, {X: 1, Y: 5}, {X: 1, Y: 5}}, Health: 100},
|
||||
{ID: "5", Body: []rules.Point{{X: 1, Y: 9}, {X: 1, Y: 9}, {X: 1, Y: 9}}, Health: 100},
|
||||
{ID: "6", Body: []rules.Point{{X: 9, Y: 1}, {X: 9, Y: 1}, {X: 9, Y: 1}}, Health: 100},
|
||||
{ID: "7", Body: []rules.Point{{X: 9, Y: 9}, {X: 9, Y: 9}, {X: 9, Y: 9}}, Health: 100},
|
||||
{ID: "8", Body: []rules.Point{{X: 1, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100},
|
||||
}),
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
|
@ -172,132 +134,51 @@ func TestStandardMapUpdateBoard(t *testing.T) {
|
|||
{
|
||||
"empty no food",
|
||||
rules.NewBoardState(2, 2),
|
||||
rules.Settings{
|
||||
FoodSpawnChance: 0,
|
||||
MinimumFood: 0,
|
||||
},
|
||||
rules.NewSettingsWithParams(rules.ParamFoodSpawnChance, "0", rules.ParamMinimumFood, "0"),
|
||||
rules.MinRand,
|
||||
&rules.BoardState{
|
||||
Width: 2,
|
||||
Height: 2,
|
||||
Snakes: []rules.Snake{},
|
||||
Food: []rules.Point{},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.NewBoardState(2, 2),
|
||||
},
|
||||
{
|
||||
"empty MinimumFood",
|
||||
rules.NewBoardState(2, 2),
|
||||
rules.Settings{
|
||||
FoodSpawnChance: 0,
|
||||
MinimumFood: 2,
|
||||
},
|
||||
rules.NewSettingsWithParams(rules.ParamFoodSpawnChance, "0", rules.ParamMinimumFood, "2"),
|
||||
rules.MinRand,
|
||||
&rules.BoardState{
|
||||
Width: 2,
|
||||
Height: 2,
|
||||
Snakes: []rules.Snake{},
|
||||
Food: []rules.Point{{X: 0, Y: 0}, {X: 0, Y: 1}},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 0}, {X: 0, Y: 1}}),
|
||||
},
|
||||
{
|
||||
"not empty MinimumFood",
|
||||
&rules.BoardState{
|
||||
Width: 2,
|
||||
Height: 2,
|
||||
Snakes: []rules.Snake{},
|
||||
Food: []rules.Point{{X: 0, Y: 1}},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.Settings{
|
||||
FoodSpawnChance: 0,
|
||||
MinimumFood: 2,
|
||||
},
|
||||
rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 1}}),
|
||||
rules.NewSettingsWithParams(rules.ParamFoodSpawnChance, "0", rules.ParamMinimumFood, "2"),
|
||||
rules.MinRand,
|
||||
&rules.BoardState{
|
||||
Width: 2,
|
||||
Height: 2,
|
||||
Snakes: []rules.Snake{},
|
||||
Food: []rules.Point{{X: 0, Y: 1}, {X: 0, Y: 0}},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 1}, {X: 0, Y: 0}}),
|
||||
},
|
||||
{
|
||||
"empty FoodSpawnChance inactive",
|
||||
rules.NewBoardState(2, 2),
|
||||
rules.Settings{
|
||||
FoodSpawnChance: 50,
|
||||
MinimumFood: 0,
|
||||
},
|
||||
rules.NewSettingsWithParams(rules.ParamFoodSpawnChance, "50", rules.ParamMinimumFood, "0"),
|
||||
rules.MinRand,
|
||||
&rules.BoardState{
|
||||
Width: 2,
|
||||
Height: 2,
|
||||
Snakes: []rules.Snake{},
|
||||
Food: []rules.Point{},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.NewBoardState(2, 2),
|
||||
},
|
||||
{
|
||||
"empty FoodSpawnChance active",
|
||||
rules.NewBoardState(2, 2),
|
||||
rules.Settings{
|
||||
FoodSpawnChance: 50,
|
||||
MinimumFood: 0,
|
||||
},
|
||||
rules.NewSettingsWithParams(rules.ParamFoodSpawnChance, "50", rules.ParamMinimumFood, "0"),
|
||||
rules.MaxRand,
|
||||
&rules.BoardState{
|
||||
Width: 2,
|
||||
Height: 2,
|
||||
Snakes: []rules.Snake{},
|
||||
Food: []rules.Point{{X: 0, Y: 1}},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 1}}),
|
||||
},
|
||||
{
|
||||
"not empty FoodSpawnChance active",
|
||||
&rules.BoardState{
|
||||
Width: 2,
|
||||
Height: 2,
|
||||
Snakes: []rules.Snake{},
|
||||
Food: []rules.Point{{X: 0, Y: 0}},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.Settings{
|
||||
FoodSpawnChance: 50,
|
||||
MinimumFood: 0,
|
||||
},
|
||||
rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 0}}),
|
||||
rules.NewSettingsWithParams(rules.ParamFoodSpawnChance, "50", rules.ParamMinimumFood, "0"),
|
||||
rules.MaxRand,
|
||||
&rules.BoardState{
|
||||
Width: 2,
|
||||
Height: 2,
|
||||
Snakes: []rules.Snake{},
|
||||
Food: []rules.Point{{X: 0, Y: 0}, {X: 1, Y: 0}},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 0}, {X: 1, Y: 0}}),
|
||||
},
|
||||
{
|
||||
"not empty FoodSpawnChance no room",
|
||||
&rules.BoardState{
|
||||
Width: 2,
|
||||
Height: 2,
|
||||
Snakes: []rules.Snake{},
|
||||
Food: []rules.Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 0}, {X: 1, Y: 1}},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.Settings{
|
||||
FoodSpawnChance: 50,
|
||||
MinimumFood: 0,
|
||||
},
|
||||
rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 0}, {X: 1, Y: 1}}),
|
||||
rules.NewSettingsWithParams(rules.ParamFoodSpawnChance, "50", rules.ParamMinimumFood, "0"),
|
||||
rules.MaxRand,
|
||||
&rules.BoardState{
|
||||
Width: 2,
|
||||
Height: 2,
|
||||
Snakes: []rules.Snake{},
|
||||
Food: []rules.Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 0}, {X: 1, Y: 1}},
|
||||
Hazards: []rules.Point{},
|
||||
},
|
||||
rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 0}, {X: 1, Y: 1}}),
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
|
|
@ -306,7 +187,7 @@ func TestStandardMapUpdateBoard(t *testing.T) {
|
|||
settings := test.settings.WithRand(test.rand)
|
||||
editor := maps.NewBoardStateEditor(nextBoardState)
|
||||
|
||||
err := m.UpdateBoard(test.initialBoardState.Clone(), settings, editor)
|
||||
err := m.PostUpdateBoard(test.initialBoardState.Clone(), settings, editor)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, test.expected, nextBoardState)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue