Add new constants for standard ruleset errors, resolves #5 (#24)

* Convert errors to constant error interfaces.
This commit is contained in:
md-hexdrive 2020-12-11 12:50:52 -05:00 committed by GitHub
parent f0f2ff5961
commit 2cbf8884bf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 26 deletions

View file

@ -37,3 +37,7 @@ type Ruleset interface {
CreateNextBoardState(prevState *BoardState, moves []SnakeMove) (*BoardState, error) CreateNextBoardState(prevState *BoardState, moves []SnakeMove) (*BoardState, error)
IsGameOver(state *BoardState) (bool, error) IsGameOver(state *BoardState) (bool, error)
} }
type RulesetError string
func (err RulesetError) Error() string { return string(err) }

View file

@ -1,7 +1,7 @@
package rules package rules
import ( import (
"errors" //"errors"
"math/rand" "math/rand"
"sort" "sort"
) )
@ -28,6 +28,14 @@ const (
EliminatedByOutOfBounds = "wall-collision" EliminatedByOutOfBounds = "wall-collision"
// TODO - Error consts // TODO - Error consts
ErrorTooManySnakes = RulesetError("too many snakes for fixed start positions")
ErrorNoRoomForSnake = RulesetError("not enough space to place snake")
ErrorNoRoomForFood = RulesetError("not enough space to place food")
ErrorNoMoveFound = RulesetError("move not provided for snake")
// TODO: These two error codes seem equivalent, Do we only need one ?
ErrorSizeZeroBody = RulesetError("found snake with zero size body")
ErrorZeroLengthSnake = RulesetError("snake is length zero")
) )
func (r *StandardRuleset) CreateInitialBoardState(width int32, height int32, snakeIDs []string) (*BoardState, error) { func (r *StandardRuleset) CreateInitialBoardState(width int32, height int32, snakeIDs []string) (*BoardState, error) {
@ -80,7 +88,7 @@ func (r *StandardRuleset) placeSnakesFixed(b *BoardState) error {
// Sanity check // Sanity check
if len(b.Snakes) > len(startPoints) { if len(b.Snakes) > len(startPoints) {
return errors.New("too many snakes for fixed start positions") return ErrorTooManySnakes
} }
// Randomly order them // Randomly order them
@ -103,7 +111,7 @@ func (r *StandardRuleset) placeSnakesRandomly(b *BoardState) error {
for i := 0; i < len(b.Snakes); i++ { for i := 0; i < len(b.Snakes); i++ {
unoccupiedPoints := r.getEvenUnoccupiedPoints(b) unoccupiedPoints := r.getEvenUnoccupiedPoints(b)
if len(unoccupiedPoints) <= 0 { if len(unoccupiedPoints) <= 0 {
return errors.New("not enough space to place snake") return ErrorNoRoomForSnake
} }
p := unoccupiedPoints[rand.Intn(len(unoccupiedPoints))] p := unoccupiedPoints[rand.Intn(len(unoccupiedPoints))]
for j := 0; j < SnakeStartSize; j++ { for j := 0; j < SnakeStartSize; j++ {
@ -147,7 +155,7 @@ func (r *StandardRuleset) placeFoodFixed(b *BoardState) error {
} }
if len(availableFoodLocations) <= 0 { if len(availableFoodLocations) <= 0 {
return errors.New("not enough space to place food") return ErrorNoRoomForFood
} }
// Select randomly from available locations // Select randomly from available locations
@ -166,7 +174,7 @@ func (r *StandardRuleset) placeFoodFixed(b *BoardState) error {
} }
} }
if isCenterOccupied { if isCenterOccupied {
return errors.New("not enough space to place food") return ErrorNoRoomForFood
} }
b.Food = append(b.Food, centerCoord) b.Food = append(b.Food, centerCoord)
@ -255,7 +263,7 @@ func (r *StandardRuleset) moveSnakes(b *BoardState, moves []SnakeMove) error {
} }
if len(snake.Body) == 0 { if len(snake.Body) == 0 {
return errors.New("found snake with zero size body") return ErrorSizeZeroBody
} }
moveFound := false moveFound := false
for _, move := range moves { for _, move := range moves {
@ -265,7 +273,7 @@ func (r *StandardRuleset) moveSnakes(b *BoardState, moves []SnakeMove) error {
} }
} }
if !moveFound { if !moveFound {
return errors.New("move not provided for snake") return ErrorNoMoveFound
} }
} }
@ -346,7 +354,7 @@ func (r *StandardRuleset) maybeEliminateSnakes(b *BoardState) error {
continue continue
} }
if len(snake.Body) <= 0 { if len(snake.Body) <= 0 {
return errors.New("snake is length zero") return ErrorZeroLengthSnake
} }
if r.snakeIsOutOfHealth(snake) { if r.snakeIsOutOfHealth(snake) {
@ -374,7 +382,7 @@ func (r *StandardRuleset) maybeEliminateSnakes(b *BoardState) error {
continue continue
} }
if len(snake.Body) <= 0 { if len(snake.Body) <= 0 {
return errors.New("snake is length zero") return ErrorZeroLengthSnake
} }
// Check for self-collisions first // Check for self-collisions first

View file

@ -1,7 +1,7 @@
package rules package rules
import ( import (
"errors" //"errors"
"math" "math"
"math/rand" "math/rand"
"testing" "testing"
@ -49,8 +49,8 @@ func TestCreateInitialBoardState(t *testing.T) {
{2, 2, []string{"one"}, 1, nil}, {2, 2, []string{"one"}, 1, nil},
{9, 8, []string{"one"}, 1, nil}, {9, 8, []string{"one"}, 1, nil},
{2, 2, []string{"one", "two"}, 0, nil}, {2, 2, []string{"one", "two"}, 0, nil},
{1, 1, []string{"one", "two"}, 2, errors.New("not enough space to place snake")}, {1, 1, []string{"one", "two"}, 2, ErrorNoRoomForSnake},
{1, 2, []string{"one", "two"}, 2, errors.New("not enough space to place snake")}, {1, 2, []string{"one", "two"}, 2, ErrorNoRoomForSnake},
{BoardSizeSmall, BoardSizeSmall, []string{"one", "two"}, 3, nil}, {BoardSizeSmall, BoardSizeSmall, []string{"one", "two"}, 3, nil},
} }
@ -95,7 +95,7 @@ func TestPlaceSnakes(t *testing.T) {
Height: 1, Height: 1,
Snakes: make([]Snake, 2), Snakes: make([]Snake, 2),
}, },
errors.New("not enough space to place snake"), ErrorNoRoomForSnake,
}, },
{ {
&BoardState{ &BoardState{
@ -103,7 +103,7 @@ func TestPlaceSnakes(t *testing.T) {
Height: 1, Height: 1,
Snakes: make([]Snake, 2), Snakes: make([]Snake, 2),
}, },
errors.New("not enough space to place snake"), ErrorNoRoomForSnake,
}, },
{ {
&BoardState{ &BoardState{
@ -111,7 +111,7 @@ func TestPlaceSnakes(t *testing.T) {
Height: 2, Height: 2,
Snakes: make([]Snake, 2), Snakes: make([]Snake, 2),
}, },
errors.New("not enough space to place snake"), ErrorNoRoomForSnake,
}, },
{ {
&BoardState{ &BoardState{
@ -135,7 +135,7 @@ func TestPlaceSnakes(t *testing.T) {
Height: 5, Height: 5,
Snakes: make([]Snake, 49), Snakes: make([]Snake, 49),
}, },
errors.New("not enough space to place snake"), ErrorNoRoomForSnake,
}, },
{ {
&BoardState{ &BoardState{
@ -143,7 +143,7 @@ func TestPlaceSnakes(t *testing.T) {
Height: 10, Height: 10,
Snakes: make([]Snake, 50), Snakes: make([]Snake, 50),
}, },
errors.New("not enough space to place snake"), ErrorNoRoomForSnake,
}, },
{ {
&BoardState{ &BoardState{
@ -151,7 +151,7 @@ func TestPlaceSnakes(t *testing.T) {
Height: 2, Height: 2,
Snakes: make([]Snake, 51), Snakes: make([]Snake, 51),
}, },
errors.New("not enough space to place snake"), ErrorNoRoomForSnake,
}, },
{ {
&BoardState{ &BoardState{
@ -175,7 +175,7 @@ func TestPlaceSnakes(t *testing.T) {
Height: BoardSizeSmall, Height: BoardSizeSmall,
Snakes: make([]Snake, 9), Snakes: make([]Snake, 9),
}, },
errors.New("too many snakes for fixed start positions"), ErrorTooManySnakes,
}, },
{ {
&BoardState{ &BoardState{
@ -191,7 +191,7 @@ func TestPlaceSnakes(t *testing.T) {
Height: BoardSizeMedium, Height: BoardSizeMedium,
Snakes: make([]Snake, 9), Snakes: make([]Snake, 9),
}, },
errors.New("too many snakes for fixed start positions"), ErrorTooManySnakes,
}, },
{ {
&BoardState{ &BoardState{
@ -207,7 +207,7 @@ func TestPlaceSnakes(t *testing.T) {
Height: BoardSizeLarge, Height: BoardSizeLarge,
Snakes: make([]Snake, 9), Snakes: make([]Snake, 9),
}, },
errors.New("too many snakes for fixed start positions"), ErrorTooManySnakes,
}, },
} }
@ -488,7 +488,7 @@ func TestCreateNextBoardState(t *testing.T) {
Food: []Point{{0, 0}, {1, 0}}, Food: []Point{{0, 0}, {1, 0}},
}, },
[]SnakeMove{}, []SnakeMove{},
errors.New("move not provided for snake"), ErrorNoMoveFound,
nil, nil,
}, },
{ {
@ -513,7 +513,7 @@ func TestCreateNextBoardState(t *testing.T) {
{ID: "one", Move: MoveUp}, {ID: "one", Move: MoveUp},
{ID: "two", Move: MoveDown}, {ID: "two", Move: MoveDown},
}, },
errors.New("found snake with zero size body"), ErrorSizeZeroBody,
nil, nil,
}, },
{ {
@ -940,7 +940,7 @@ func TestMoveSnakesWrongID(t *testing.T) {
r := StandardRuleset{} r := StandardRuleset{}
err := r.moveSnakes(b, moves) err := r.moveSnakes(b, moves)
require.Equal(t, errors.New("move not provided for snake"), err) require.Equal(t, ErrorNoMoveFound, err) // TODO: @bvanvugt is this a place where an "==" comparision should be used ?
} }
func TestMoveSnakesNotEnoughMoves(t *testing.T) { func TestMoveSnakesNotEnoughMoves(t *testing.T) {
@ -965,7 +965,7 @@ func TestMoveSnakesNotEnoughMoves(t *testing.T) {
r := StandardRuleset{} r := StandardRuleset{}
err := r.moveSnakes(b, moves) err := r.moveSnakes(b, moves)
require.Equal(t, errors.New("move not provided for snake"), err) require.Equal(t, ErrorNoMoveFound, err)
} }
func TestMoveSnakesExtraMovesIgnored(t *testing.T) { func TestMoveSnakesExtraMovesIgnored(t *testing.T) {
@ -1366,7 +1366,7 @@ func TestMaybeEliminateSnakes(t *testing.T) {
}, },
[]string{NotEliminated}, []string{NotEliminated},
[]string{""}, []string{""},
errors.New("snake is length zero"), ErrorZeroLengthSnake,
}, },
{ {
"Single Starvation", "Single Starvation",