DEV-765 pipeline refactor (#64)
Refactor rulesets into smaller composable operations In order to mix up the functionality from different rulesets like Solo, Royale, etc. the code in these classes needs to be broken up into small functions that can be composed in a pipeline to make a custom game mode.
This commit is contained in:
parent
5e629e9e93
commit
397d925110
25 changed files with 1475 additions and 222 deletions
77
squad.go
77
squad.go
|
|
@ -16,9 +16,7 @@ type SquadRuleset struct {
|
|||
SharedLength bool
|
||||
}
|
||||
|
||||
const EliminatedBySquad = "squad-eliminated"
|
||||
|
||||
func (r *SquadRuleset) Name() string { return "squad" }
|
||||
func (r *SquadRuleset) Name() string { return GameTypeSquad }
|
||||
|
||||
func (r *SquadRuleset) CreateNextBoardState(prevState *BoardState, moves []SnakeMove) (*BoardState, error) {
|
||||
nextBoardState, err := r.StandardRuleset.CreateNextBoardState(prevState, moves)
|
||||
|
|
@ -26,13 +24,11 @@ func (r *SquadRuleset) CreateNextBoardState(prevState *BoardState, moves []Snake
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: LOG?
|
||||
err = r.resurrectSquadBodyCollisions(nextBoardState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: LOG?
|
||||
err = r.shareSquadAttributes(nextBoardState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -41,38 +37,50 @@ func (r *SquadRuleset) CreateNextBoardState(prevState *BoardState, moves []Snake
|
|||
return nextBoardState, nil
|
||||
}
|
||||
|
||||
func (r *SquadRuleset) areSnakesOnSameSquad(snake *Snake, other *Snake) bool {
|
||||
return r.areSnakeIDsOnSameSquad(snake.ID, other.ID)
|
||||
func areSnakesOnSameSquad(squadMap map[string]string, snake *Snake, other *Snake) bool {
|
||||
return areSnakeIDsOnSameSquad(squadMap, snake.ID, other.ID)
|
||||
}
|
||||
|
||||
func (r *SquadRuleset) areSnakeIDsOnSameSquad(snakeID string, otherID string) bool {
|
||||
return r.SquadMap[snakeID] == r.SquadMap[otherID]
|
||||
func areSnakeIDsOnSameSquad(squadMap map[string]string, snakeID string, otherID string) bool {
|
||||
return squadMap[snakeID] == squadMap[otherID]
|
||||
}
|
||||
|
||||
func (r *SquadRuleset) resurrectSquadBodyCollisions(b *BoardState) error {
|
||||
if !r.AllowBodyCollisions {
|
||||
return nil
|
||||
_, err := r.callStageFunc(ResurrectSnakesSquad, b, []SnakeMove{})
|
||||
return err
|
||||
}
|
||||
|
||||
func ResurrectSnakesSquad(b *BoardState, settings Settings, moves []SnakeMove) (bool, error) {
|
||||
if !settings.SquadSettings.AllowBodyCollisions {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
for i := 0; i < len(b.Snakes); i++ {
|
||||
snake := &b.Snakes[i]
|
||||
if snake.EliminatedCause == EliminatedByCollision {
|
||||
if snake.EliminatedBy == "" {
|
||||
return errors.New("snake eliminated by collision and eliminatedby is not set")
|
||||
return false, errors.New("snake eliminated by collision and eliminatedby is not set")
|
||||
}
|
||||
if snake.ID != snake.EliminatedBy && r.areSnakeIDsOnSameSquad(snake.ID, snake.EliminatedBy) {
|
||||
if snake.ID != snake.EliminatedBy && areSnakeIDsOnSameSquad(settings.SquadSettings.squadMap, snake.ID, snake.EliminatedBy) {
|
||||
snake.EliminatedCause = NotEliminated
|
||||
snake.EliminatedBy = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (r *SquadRuleset) shareSquadAttributes(b *BoardState) error {
|
||||
if !(r.SharedElimination || r.SharedLength || r.SharedHealth) {
|
||||
return nil
|
||||
_, err := r.callStageFunc(ShareAttributesSquad, b, []SnakeMove{})
|
||||
return err
|
||||
}
|
||||
|
||||
func ShareAttributesSquad(b *BoardState, settings Settings, moves []SnakeMove) (bool, error) {
|
||||
squadSettings := settings.SquadSettings
|
||||
|
||||
if !(squadSettings.SharedElimination || squadSettings.SharedLength || squadSettings.SharedHealth) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
for i := 0; i < len(b.Snakes); i++ {
|
||||
|
|
@ -83,21 +91,21 @@ func (r *SquadRuleset) shareSquadAttributes(b *BoardState) error {
|
|||
|
||||
for j := 0; j < len(b.Snakes); j++ {
|
||||
other := &b.Snakes[j]
|
||||
if r.areSnakesOnSameSquad(snake, other) {
|
||||
if r.SharedHealth {
|
||||
if areSnakesOnSameSquad(squadSettings.squadMap, snake, other) {
|
||||
if squadSettings.SharedHealth {
|
||||
if snake.Health < other.Health {
|
||||
snake.Health = other.Health
|
||||
}
|
||||
}
|
||||
if r.SharedLength {
|
||||
if squadSettings.SharedLength {
|
||||
if len(snake.Body) == 0 || len(other.Body) == 0 {
|
||||
return errors.New("found snake of zero length")
|
||||
return false, errors.New("found snake of zero length")
|
||||
}
|
||||
for len(snake.Body) < len(other.Body) {
|
||||
r.growSnake(snake)
|
||||
growSnake(snake)
|
||||
}
|
||||
}
|
||||
if r.SharedElimination {
|
||||
if squadSettings.SharedElimination {
|
||||
if snake.EliminatedCause == NotEliminated && other.EliminatedCause != NotEliminated {
|
||||
snake.EliminatedCause = EliminatedBySquad
|
||||
// We intentionally do not set snake.EliminatedBy because there might be multiple culprits.
|
||||
|
|
@ -108,10 +116,14 @@ func (r *SquadRuleset) shareSquadAttributes(b *BoardState) error {
|
|||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (r *SquadRuleset) IsGameOver(b *BoardState) (bool, error) {
|
||||
return r.callStageFunc(GameOverSquad, b, []SnakeMove{})
|
||||
}
|
||||
|
||||
func GameOverSquad(b *BoardState, settings Settings, moves []SnakeMove) (bool, error) {
|
||||
snakesRemaining := []*Snake{}
|
||||
for i := 0; i < len(b.Snakes); i++ {
|
||||
if b.Snakes[i].EliminatedCause == NotEliminated {
|
||||
|
|
@ -120,7 +132,7 @@ func (r *SquadRuleset) IsGameOver(b *BoardState) (bool, error) {
|
|||
}
|
||||
|
||||
for i := 0; i < len(snakesRemaining); i++ {
|
||||
if !r.areSnakesOnSameSquad(snakesRemaining[i], snakesRemaining[0]) {
|
||||
if !areSnakesOnSameSquad(settings.SquadSettings.squadMap, snakesRemaining[i], snakesRemaining[0]) {
|
||||
// There are multiple squads remaining
|
||||
return false, nil
|
||||
}
|
||||
|
|
@ -128,3 +140,20 @@ func (r *SquadRuleset) IsGameOver(b *BoardState) (bool, error) {
|
|||
// no snakes or single squad remaining
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (r SquadRuleset) Settings() Settings {
|
||||
s := r.StandardRuleset.Settings()
|
||||
s.SquadSettings = SquadSettings{
|
||||
squadMap: r.SquadMap,
|
||||
AllowBodyCollisions: r.AllowBodyCollisions,
|
||||
SharedElimination: r.SharedElimination,
|
||||
SharedHealth: r.SharedHealth,
|
||||
SharedLength: r.SharedLength,
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Adaptor for integrating stages into SquadRuleset
|
||||
func (r *SquadRuleset) callStageFunc(stage StageFunc, boardState *BoardState, moves []SnakeMove) (bool, error) {
|
||||
return stage(boardState, r.Settings(), moves)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue