Byte-snake-engine/royale.go

98 lines
2.4 KiB
Go
Raw Normal View History

2020-07-25 17:37:41 -07:00
package rules
import (
"errors"
"math/rand"
2020-07-25 17:37:41 -07:00
)
type RoyaleRuleset struct {
StandardRuleset
2020-07-29 13:14:42 -07:00
Seed int64
2020-07-25 17:37:41 -07:00
ShrinkEveryNTurns int32
}
func (r *RoyaleRuleset) Name() string { return GameTypeRoyale }
2020-07-25 17:37:41 -07:00
func (r *RoyaleRuleset) CreateNextBoardState(prevState *BoardState, moves []SnakeMove) (*BoardState, error) {
if r.StandardRuleset.HazardDamagePerTurn < 1 {
return nil, errors.New("royale damage per turn must be greater than zero")
2020-07-25 17:37:41 -07:00
}
nextBoardState, err := r.StandardRuleset.CreateNextBoardState(prevState, moves)
if err != nil {
return nil, err
}
// Royale's only job is now to populate the hazards for next turn - StandardRuleset takes care of applying hazard damage.
err = r.populateHazards(nextBoardState)
2020-07-25 17:37:41 -07:00
if err != nil {
return nil, err
}
return nextBoardState, nil
}
func (r *RoyaleRuleset) populateHazards(b *BoardState) error {
_, err := r.callStageFunc(PopulateHazardsRoyale, b, []SnakeMove{})
return err
}
func PopulateHazardsRoyale(b *BoardState, settings Settings, moves []SnakeMove) (bool, error) {
b.Hazards = []Point{}
2020-07-25 17:37:41 -07:00
// Royale uses the current turn to generate hazards, not the previous turn that's in the board state
turn := b.Turn + 1
if settings.RoyaleSettings.ShrinkEveryNTurns < 1 {
return false, errors.New("royale game can't shrink more frequently than every turn")
2020-07-25 17:37:41 -07:00
}
if turn < settings.RoyaleSettings.ShrinkEveryNTurns {
return false, nil
2020-07-25 17:37:41 -07:00
}
randGenerator := rand.New(rand.NewSource(settings.RoyaleSettings.seed))
numShrinks := turn / settings.RoyaleSettings.ShrinkEveryNTurns
minX, maxX := int32(0), b.Width-1
minY, maxY := int32(0), b.Height-1
for i := int32(0); i < numShrinks; i++ {
switch randGenerator.Intn(4) {
case 0:
minX += 1
case 1:
maxX -= 1
case 2:
minY += 1
case 3:
maxY -= 1
}
}
2020-07-25 17:37:41 -07:00
for x := int32(0); x < b.Width; x++ {
for y := int32(0); y < b.Height; y++ {
if x < minX || x > maxX || y < minY || y > maxY {
b.Hazards = append(b.Hazards, Point{x, y})
2020-07-25 17:37:41 -07:00
}
}
}
return false, nil
}
func (r RoyaleRuleset) Settings() Settings {
s := r.StandardRuleset.Settings()
s.RoyaleSettings = RoyaleSettings{
seed: r.Seed,
ShrinkEveryNTurns: r.ShrinkEveryNTurns,
}
return s
}
// Adaptor for integrating stages into RoyaleRuleset
func (r *RoyaleRuleset) callStageFunc(stage StageFunc, boardState *BoardState, moves []SnakeMove) (bool, error) {
return stage(boardState, r.Settings(), moves)
2020-07-25 17:37:41 -07:00
}