-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* added the new hazard map with custom start locations * tweaked comments/logic * cleaning up functionality * unit test plus bug fixes * fixing unnecessary error
- Loading branch information
1 parent
7fa55be
commit 0061425
Showing
2 changed files
with
208 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
package maps | ||
|
||
import ( | ||
"github.com/BattlesnakeOfficial/rules" | ||
) | ||
|
||
func init() { | ||
globalRegistry.RegisterMap("hz_hazard_pits", HazardPitsMap{}) | ||
} | ||
|
||
type HazardPitsMap struct{} | ||
|
||
func (m HazardPitsMap) ID() string { | ||
return "hz_hazard_pits" | ||
} | ||
|
||
func (m HazardPitsMap) Meta() Metadata { | ||
return Metadata{ | ||
Name: "hz_hazard_pits", | ||
Description: "A map that that fills in grid-like pattern of squares with pits filled with hazard sauce. Every N turns the pits will fill with another layer of sauce up to a maximum of 4 layers which last a few cycles, then the pits drain and the pattern repeats", | ||
Author: "Battlesnake", | ||
Version: 1, | ||
MinPlayers: 1, | ||
MaxPlayers: 4, | ||
BoardSizes: FixedSizes(Dimensions{11, 11}), | ||
Tags: []string{TAG_FOOD_PLACEMENT, TAG_HAZARD_PLACEMENT, TAG_SNAKE_PLACEMENT}, | ||
} | ||
} | ||
|
||
func (m HazardPitsMap) AddHazardPits(board *rules.BoardState, settings rules.Settings, editor Editor) { | ||
for x := 0; x < board.Width; x++ { | ||
for y := 0; y < board.Height; y++ { | ||
if x%2 == 1 && y%2 == 1 { | ||
point := rules.Point{X: x, Y: y} | ||
isStartPosition := false | ||
for _, startPos := range hazardPitStartPositions { | ||
if startPos == point { | ||
isStartPosition = true | ||
} | ||
} | ||
if !isStartPosition { | ||
editor.AddHazard(point) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
func (m HazardPitsMap) SetupBoard(initialBoardState *rules.BoardState, settings rules.Settings, editor Editor) error { | ||
if !m.Meta().BoardSizes.IsAllowable(initialBoardState.Width, initialBoardState.Height) { | ||
return rules.RulesetError("This map can only be played on a 11x11 board") | ||
} | ||
|
||
if len(initialBoardState.Snakes) > len(hazardPitStartPositions) { | ||
return rules.ErrorTooManySnakes | ||
} | ||
|
||
rand := settings.GetRand(0) | ||
|
||
rand.Shuffle(len(hazardPitStartPositions), func(i int, j int) { | ||
hazardPitStartPositions[i], hazardPitStartPositions[j] = hazardPitStartPositions[j], hazardPitStartPositions[i] | ||
}) | ||
snakeIDs := make([]string, 0, len(initialBoardState.Snakes)) | ||
for _, snake := range initialBoardState.Snakes { | ||
snakeIDs = append(snakeIDs, snake.ID) | ||
} | ||
|
||
tempBoardState := rules.NewBoardState(initialBoardState.Width, initialBoardState.Height) | ||
tempBoardState.Snakes = make([]rules.Snake, len(snakeIDs)) | ||
|
||
for i := 0; i < len(snakeIDs); i++ { | ||
tempBoardState.Snakes[i] = rules.Snake{ | ||
ID: snakeIDs[i], | ||
Health: rules.SnakeMaxHealth, | ||
} | ||
} | ||
|
||
for index, snake := range initialBoardState.Snakes { | ||
head := hazardPitStartPositions[index] | ||
err := rules.PlaceSnake(tempBoardState, snake.ID, []rules.Point{head, head, head}) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
err := rules.PlaceFoodFixed(rand, tempBoardState) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Copy food from temp board state | ||
for _, f := range tempBoardState.Food { | ||
editor.AddFood(f) | ||
} | ||
|
||
// Copy snakes from temp board state | ||
for _, snake := range tempBoardState.Snakes { | ||
editor.PlaceSnake(snake.ID, snake.Body, snake.Health) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (m HazardPitsMap) UpdateBoard(lastBoardState *rules.BoardState, settings rules.Settings, editor Editor) error { | ||
err := StandardMap{}.UpdateBoard(lastBoardState, settings, editor) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Cycle 0 - no hazards | ||
// Cycle 1 - 1 layer | ||
// Cycle 2 - 2 layers | ||
// Cycle 3 - 3 layers | ||
// Cycle 4-6 - 4 layers of hazards | ||
|
||
if lastBoardState.Turn%settings.RoyaleSettings.ShrinkEveryNTurns == 0 { | ||
// Is it time to update the hazards | ||
layers := (lastBoardState.Turn / settings.RoyaleSettings.ShrinkEveryNTurns) % 7 | ||
if layers > 4 { | ||
layers = 4 | ||
} | ||
|
||
editor.ClearHazards() | ||
|
||
// Add 1-4 layers of hazard pits depending on the cycle | ||
for n := 0; n < layers; n++ { | ||
m.AddHazardPits(lastBoardState, settings, editor) | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
var hazardPitStartPositions = []rules.Point{ | ||
{X: 1, Y: 1}, | ||
{X: 9, Y: 1}, | ||
{X: 1, Y: 9}, | ||
{X: 9, Y: 9}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package maps_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/BattlesnakeOfficial/rules" | ||
"github.com/BattlesnakeOfficial/rules/maps" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestHazardPitsMap(t *testing.T) { | ||
// check error handling | ||
m := maps.HazardPitsMap{} | ||
settings := rules.Settings{} | ||
// check error for unsupported board sizes | ||
state := rules.NewBoardState(9, | ||
9) | ||
editor := maps.NewBoardStateEditor(state) | ||
err := m.SetupBoard(state, settings, editor) | ||
require.Error(t, err) | ||
|
||
// too big | ||
state = rules.NewBoardState(19, 19) | ||
editor = maps.NewBoardStateEditor(state) | ||
err = m.SetupBoard(state, settings, editor) | ||
require.Error(t, err) | ||
|
||
// Too many snakes | ||
state = rules.NewBoardState(19, 19) | ||
editor = maps.NewBoardStateEditor(state) | ||
state.Snakes = append(state.Snakes, rules.Snake{ID: "1", Body: []rules.Point{}}) | ||
state.Snakes = append(state.Snakes, rules.Snake{ID: "2", Body: []rules.Point{}}) | ||
state.Snakes = append(state.Snakes, rules.Snake{ID: "3", Body: []rules.Point{}}) | ||
state.Snakes = append(state.Snakes, rules.Snake{ID: "4", Body: []rules.Point{}}) | ||
state.Snakes = append(state.Snakes, rules.Snake{ID: "5", Body: []rules.Point{}}) | ||
err = m.SetupBoard(state, settings, editor) | ||
require.Error(t, err) | ||
|
||
state = rules.NewBoardState(int(11), int(11)) | ||
m = maps.HazardPitsMap{} | ||
settings.RoyaleSettings.ShrinkEveryNTurns = 1 | ||
editor = maps.NewBoardStateEditor(state) | ||
require.Empty(t, state.Hazards) | ||
err = m.SetupBoard(state, settings, editor) | ||
require.NoError(t, err) | ||
require.Empty(t, state.Hazards) | ||
// Verify the hazard progression through the turns | ||
for i := 0; i < 16; i++ { | ||
state.Turn = i | ||
err = m.UpdateBoard(state, settings, editor) | ||
require.NoError(t, err) | ||
if i == 1 { | ||
require.Len(t, state.Hazards, 21) | ||
} else if i == 2 { | ||
require.Len(t, state.Hazards, 42) | ||
} else if i == 3 { | ||
require.Len(t, state.Hazards, 63) | ||
} else if i == 4 { | ||
require.Len(t, state.Hazards, 84) | ||
} else if i == 5 { | ||
require.Len(t, state.Hazards, 84) | ||
} else if i == 6 { | ||
require.Len(t, state.Hazards, 84) | ||
} else if i == 7 { | ||
require.Len(t, state.Hazards, 0) | ||
} else if i == 8 { | ||
require.Len(t, state.Hazards, 21) | ||
} | ||
} | ||
} |