Skip to content

Commit

Permalink
wrapped ruleset (#30)
Browse files Browse the repository at this point in the history
* wrapped ruleset

* resurrect like brad suggested

* introduce mode to binary

* go fmt

* address edge crossing collision and eating bugs

* Update board_state.go

* removed binary

* rename variable
  • Loading branch information
joram committed Aug 24, 2021
1 parent 015b681 commit 17556e1
Show file tree
Hide file tree
Showing 3 changed files with 318 additions and 0 deletions.
4 changes: 4 additions & 0 deletions cli/commands/play.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@ func getRuleset(seed int64, gameTurn int32, snakes []Battlesnake) rules.Ruleset
ruleset = &rules.SoloRuleset{
StandardRuleset: standard,
}
case "wrapped":
ruleset = &rules.WrappedRuleset{
StandardRuleset: standard,
}
case "constrictor":
ruleset = &rules.ConstrictorRuleset{
StandardRuleset: standard,
Expand Down
66 changes: 66 additions & 0 deletions wrapped.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package rules

type WrappedRuleset struct {
StandardRuleset
}

func replace(value, min, max int32) int32 {
if value < min {
return max
}
if value > max {
return min
}
return value
}

func (r *WrappedRuleset) CreateNextBoardState(prevState *BoardState, moves []SnakeMove) (*BoardState, error) {
nextState := prevState.Clone()

err := r.moveSnakes(nextState, moves)
if err != nil {
return nil, err
}

err = r.reduceSnakeHealth(nextState)
if err != nil {
return nil, err
}

err = r.maybeDamageHazards(nextState)
if err != nil {
return nil, err
}

err = r.maybeFeedSnakes(nextState)
if err != nil {
return nil, err
}

err = r.maybeSpawnFood(nextState)
if err != nil {
return nil, err
}

err = r.maybeEliminateSnakes(nextState)
if err != nil {
return nil, err
}

return nextState, nil
}

func (r *WrappedRuleset) moveSnakes(b *BoardState, moves []SnakeMove) error {
err := r.StandardRuleset.moveSnakes(b, moves)
if err != nil {
return err
}

for i := 0; i < len(b.Snakes); i++ {
snake := &b.Snakes[i]
snake.Body[0].X = replace(snake.Body[0].X, 0, b.Width-1)
snake.Body[0].Y = replace(snake.Body[0].Y, 0, b.Height-1)
}

return nil
}
248 changes: 248 additions & 0 deletions wrapped_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
package rules

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestLeft(t *testing.T) {
boardState := &BoardState{
Width: 11,
Height: 11,
Snakes: []Snake{
{ID: "bottomLeft", Health: 10, Body: []Point{{0, 0}}},
{ID: "bottomRight", Health: 10, Body: []Point{{10, 0}}},
{ID: "topLeft", Health: 10, Body: []Point{{0, 10}}},
{ID: "topRight", Health: 10, Body: []Point{{10, 10}}},
},
}

snakeMoves := []SnakeMove{
{ID: "bottomLeft", Move: "left"},
{ID: "bottomRight", Move: "left"},
{ID: "topLeft", Move: "left"},
{ID: "topRight", Move: "left"},
}

r := WrappedRuleset{}

nextBoardState, err := r.CreateNextBoardState(boardState, snakeMoves)
require.NoError(t, err)
require.Equal(t, len(boardState.Snakes), len(nextBoardState.Snakes))

expectedSnakes := []Snake{
{ID: "bottomLeft", Health: 10, Body: []Point{{10, 0}}},
{ID: "bottomRight", Health: 10, Body: []Point{{9, 0}}},
{ID: "topLeft", Health: 10, Body: []Point{{10, 10}}},
{ID: "topRight", Health: 10, Body: []Point{{9, 10}}},
}
for i, snake := range nextBoardState.Snakes {
require.Equal(t, expectedSnakes[i].ID, snake.ID, snake.ID)
require.Equal(t, expectedSnakes[i].EliminatedCause, snake.EliminatedCause, snake.ID)
require.Equal(t, expectedSnakes[i].EliminatedBy, snake.EliminatedBy, snake.ID)
require.Equal(t, expectedSnakes[i].Body, snake.Body, snake.ID)
}
}

func TestRight(t *testing.T) {
boardState := &BoardState{
Width: 11,
Height: 11,
Snakes: []Snake{
{ID: "bottomLeft", Health: 10, Body: []Point{{0, 0}}},
{ID: "bottomRight", Health: 10, Body: []Point{{10, 0}}},
{ID: "topLeft", Health: 10, Body: []Point{{0, 10}}},
{ID: "topRight", Health: 10, Body: []Point{{10, 10}}},
},
}

snakeMoves := []SnakeMove{
{ID: "bottomLeft", Move: "right"},
{ID: "bottomRight", Move: "right"},
{ID: "topLeft", Move: "right"},
{ID: "topRight", Move: "right"},
}

r := WrappedRuleset{}

nextBoardState, err := r.CreateNextBoardState(boardState, snakeMoves)
require.NoError(t, err)
require.Equal(t, len(boardState.Snakes), len(nextBoardState.Snakes))

expectedSnakes := []Snake{
{ID: "bottomLeft", Health: 10, Body: []Point{{1, 0}}},
{ID: "bottomRight", Health: 10, Body: []Point{{0, 0}}},
{ID: "topLeft", Health: 10, Body: []Point{{1, 10}}},
{ID: "topRight", Health: 10, Body: []Point{{0, 10}}},
}
for i, snake := range nextBoardState.Snakes {
require.Equal(t, expectedSnakes[i].ID, snake.ID, snake.ID)
require.Equal(t, expectedSnakes[i].EliminatedCause, snake.EliminatedCause, snake.ID)
require.Equal(t, expectedSnakes[i].EliminatedBy, snake.EliminatedBy, snake.ID)
require.Equal(t, expectedSnakes[i].Body, snake.Body, snake.ID)
}
}

func TestUp(t *testing.T) {
boardState := &BoardState{
Width: 11,
Height: 11,
Snakes: []Snake{
{ID: "bottomLeft", Health: 10, Body: []Point{{0, 0}}},
{ID: "bottomRight", Health: 10, Body: []Point{{10, 0}}},
{ID: "topLeft", Health: 10, Body: []Point{{0, 10}}},
{ID: "topRight", Health: 10, Body: []Point{{10, 10}}},
},
}

snakeMoves := []SnakeMove{
{ID: "bottomLeft", Move: "up"},
{ID: "bottomRight", Move: "up"},
{ID: "topLeft", Move: "up"},
{ID: "topRight", Move: "up"},
}

r := WrappedRuleset{}

nextBoardState, err := r.CreateNextBoardState(boardState, snakeMoves)
require.NoError(t, err)
require.Equal(t, len(boardState.Snakes), len(nextBoardState.Snakes))

expectedSnakes := []Snake{
{ID: "bottomLeft", Health: 10, Body: []Point{{0, 1}}},
{ID: "bottomRight", Health: 10, Body: []Point{{10, 1}}},
{ID: "topLeft", Health: 10, Body: []Point{{0, 0}}},
{ID: "topRight", Health: 10, Body: []Point{{10, 0}}},
}
for i, snake := range nextBoardState.Snakes {
require.Equal(t, expectedSnakes[i].ID, snake.ID, snake.ID)
require.Equal(t, expectedSnakes[i].Body, snake.Body, snake.ID)
require.Equal(t, expectedSnakes[i].EliminatedCause, snake.EliminatedCause, snake.ID)
require.Equal(t, expectedSnakes[i].EliminatedBy, snake.EliminatedBy, snake.ID)
}
}

func TestDown(t *testing.T) {
boardState := &BoardState{
Width: 11,
Height: 11,
Snakes: []Snake{
{ID: "bottomLeft", Health: 10, Body: []Point{{0, 0}}},
{ID: "bottomRight", Health: 10, Body: []Point{{10, 0}}},
{ID: "topLeft", Health: 10, Body: []Point{{0, 10}}},
{ID: "topRight", Health: 10, Body: []Point{{10, 10}}},
},
}

snakeMoves := []SnakeMove{
{ID: "bottomLeft", Move: "down"},
{ID: "bottomRight", Move: "down"},
{ID: "topLeft", Move: "down"},
{ID: "topRight", Move: "down"},
}

r := WrappedRuleset{}

nextBoardState, err := r.CreateNextBoardState(boardState, snakeMoves)
require.NoError(t, err)
require.Equal(t, len(boardState.Snakes), len(nextBoardState.Snakes))

expectedSnakes := []Snake{
{ID: "bottomLeft", Health: 10, Body: []Point{{0, 10}}},
{ID: "bottomRight", Health: 10, Body: []Point{{10, 10}}},
{ID: "topLeft", Health: 10, Body: []Point{{0, 9}}},
{ID: "topRight", Health: 10, Body: []Point{{10, 9}}},
}
for i, snake := range nextBoardState.Snakes {
require.Equal(t, expectedSnakes[i].ID, snake.ID, snake.ID)
require.Equal(t, expectedSnakes[i].Body, snake.Body, snake.ID)
require.Equal(t, expectedSnakes[i].EliminatedCause, snake.EliminatedCause, snake.ID)
require.Equal(t, expectedSnakes[i].EliminatedBy, snake.EliminatedBy, snake.ID)
}
}

func TestEdgeCrossingCollision(t *testing.T) {
boardState := &BoardState{
Width: 11,
Height: 11,
Snakes: []Snake{
{ID: "left", Health: 10, Body: []Point{{0, 5}}},
{ID: "rightEdge", Health: 10, Body: []Point{
{10, 1},
{10, 2},
{10, 3},
{10, 4},
{10, 5},
{10, 6},
}},
},
}

snakeMoves := []SnakeMove{
{ID: "left", Move: "left"},
{ID: "rightEdge", Move: "down"},
}

r := WrappedRuleset{}

nextBoardState, err := r.CreateNextBoardState(boardState, snakeMoves)
require.NoError(t, err)
require.Equal(t, len(boardState.Snakes), len(nextBoardState.Snakes))

expectedSnakes := []Snake{
{ID: "left", Health: 0, Body: []Point{{10, 5}}, EliminatedCause: EliminatedByCollision, EliminatedBy: "rightEdge"},
{ID: "rightEdge", Health: 10, Body: []Point{
{10, 0},
{10, 1},
{10, 2},
{10, 3},
{10, 4},
{10, 5},
}},
}
for i, snake := range nextBoardState.Snakes {
require.Equal(t, expectedSnakes[i].ID, snake.ID, snake.ID)
require.Equal(t, expectedSnakes[i].Body, snake.Body, snake.ID)
require.Equal(t, expectedSnakes[i].EliminatedCause, snake.EliminatedCause, snake.ID)
require.Equal(t, expectedSnakes[i].EliminatedBy, snake.EliminatedBy, snake.ID)
}
}

func TestEdgeCrossingEating(t *testing.T) {
boardState := &BoardState{
Width: 11,
Height: 11,
Snakes: []Snake{
{ID: "left", Health: 10, Body: []Point{{0, 5}, {1, 5}}},
{ID: "other", Health: 10, Body: []Point{{5, 5}}},
},
Food: []Point{
{10, 5},
},
}

snakeMoves := []SnakeMove{
{ID: "left", Move: "left"},
{ID: "other", Move: "left"},
}

r := WrappedRuleset{}

nextBoardState, err := r.CreateNextBoardState(boardState, snakeMoves)
require.NoError(t, err)
require.Equal(t, len(boardState.Snakes), len(nextBoardState.Snakes))

expectedSnakes := []Snake{
{ID: "left", Health: 100, Body: []Point{{10, 5}, {0, 5}, {0, 5}}},
{ID: "other", Health: 9, Body: []Point{{4, 5}}},
}
for i, snake := range nextBoardState.Snakes {
require.Equal(t, expectedSnakes[i].ID, snake.ID, snake.ID)
require.Equal(t, expectedSnakes[i].EliminatedCause, snake.EliminatedCause, snake.ID)
require.Equal(t, expectedSnakes[i].EliminatedBy, snake.EliminatedBy, snake.ID)
require.Equal(t, expectedSnakes[i].Body, snake.Body, snake.ID)
require.Equal(t, expectedSnakes[i].Health, snake.Health, snake.ID)

}
}

0 comments on commit 17556e1

Please sign in to comment.