Skip to content

Commit

Permalink
Never spawn food within one move of any snake.
Browse files Browse the repository at this point in the history
  • Loading branch information
bvanvugt committed Nov 10, 2020
1 parent f5aec61 commit c6d9ba1
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 16 deletions.
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
Expand Down
25 changes: 20 additions & 5 deletions standard.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ func (r *StandardRuleset) placeFoodFixed(b *BoardState) error {
// Finally, always place 1 food in center of board for dramatic purposes
isCenterOccupied := true
centerCoord := Point{(b.Width - 1) / 2, (b.Height - 1) / 2}
unoccupiedPoints := r.getUnoccupiedPoints(b)
unoccupiedPoints := r.getUnoccupiedPoints(b, true)
for _, point := range unoccupiedPoints {
if point == centerCoord {
isCenterOccupied = false
Expand Down Expand Up @@ -526,7 +526,7 @@ func (r *StandardRuleset) maybeSpawnFood(b *BoardState) error {

func (r *StandardRuleset) spawnFood(b *BoardState, n int) error {
for i := 0; i < n; i++ {
unoccupiedPoints := r.getUnoccupiedPoints(b)
unoccupiedPoints := r.getUnoccupiedPoints(b, false)
if len(unoccupiedPoints) > 0 {
newFood := unoccupiedPoints[rand.Intn(len(unoccupiedPoints))]
b.Food = append(b.Food, newFood)
Expand All @@ -535,7 +535,7 @@ func (r *StandardRuleset) spawnFood(b *BoardState, n int) error {
return nil
}

func (r *StandardRuleset) getUnoccupiedPoints(b *BoardState) []Point {
func (r *StandardRuleset) getUnoccupiedPoints(b *BoardState, includePossibleMoves bool) []Point {
pointIsOccupied := map[int32]map[int32]bool{}
for _, p := range b.Food {
if _, xExists := pointIsOccupied[p.X]; !xExists {
Expand All @@ -544,11 +544,26 @@ func (r *StandardRuleset) getUnoccupiedPoints(b *BoardState) []Point {
pointIsOccupied[p.X][p.Y] = true
}
for _, snake := range b.Snakes {
for _, p := range snake.Body {
for i, p := range snake.Body {
if _, xExists := pointIsOccupied[p.X]; !xExists {
pointIsOccupied[p.X] = map[int32]bool{}
}
pointIsOccupied[p.X][p.Y] = true

if i == 0 && !includePossibleMoves {
nextMovePoints := []Point{
{X: p.X - 1, Y: p.Y},
{X: p.X + 1, Y: p.Y},
{X: p.X, Y: p.Y - 1},
{X: p.X, Y: p.Y + 1},
}
for _, nextP := range nextMovePoints {
if _, xExists := pointIsOccupied[nextP.X]; !xExists {
pointIsOccupied[nextP.X] = map[int32]bool{}
}
pointIsOccupied[nextP.X][nextP.Y] = true
}
}
}
}

Expand All @@ -570,7 +585,7 @@ func (r *StandardRuleset) getUnoccupiedPoints(b *BoardState) []Point {

func (r *StandardRuleset) getEvenUnoccupiedPoints(b *BoardState) []Point {
// Start by getting unoccupied points
unoccupiedPoints := r.getUnoccupiedPoints(b)
unoccupiedPoints := r.getUnoccupiedPoints(b, true)

// Create a new array to hold points that are even
evenUnoccupiedPoints := []Point{}
Expand Down
38 changes: 27 additions & 11 deletions standard_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,18 @@ func TestCreateInitialBoardState(t *testing.T) {
Err error
}{
{1, 1, []string{"one"}, 0, nil},
{1, 2, []string{"one"}, 1, nil},
{1, 2, []string{"one"}, 0, nil},
{1, 4, []string{"one"}, 1, nil},
{2, 2, []string{"one"}, 1, nil},
{9, 8, []string{"one"}, 1, nil},
{2, 2, []string{"one", "two"}, 2, nil},
{2, 2, []string{"one", "two"}, 2, nil},
{2, 2, []string{"one", "two"}, 0, nil},
{1, 1, []string{"one", "two"}, 2, errors.New("not enough space to place snake")},
{1, 2, []string{"one", "two"}, 2, errors.New("not enough space to place snake")},
{BoardSizeSmall, BoardSizeSmall, []string{"one", "two"}, 3, nil},
}

r := StandardRuleset{}
for _, test := range tests {
for testNum, test := range tests {
state, err := r.CreateInitialBoardState(test.Width, test.Height, test.IDs)
require.Equal(t, test.Err, err)
if err != nil {
Expand All @@ -68,7 +69,7 @@ func TestCreateInitialBoardState(t *testing.T) {
for i, id := range test.IDs {
require.Equal(t, id, state.Snakes[i].ID)
}
require.Len(t, state.Food, test.ExpectedNumFood)
require.Len(t, state.Food, test.ExpectedNumFood, testNum)
}
}

Expand Down Expand Up @@ -212,7 +213,7 @@ func TestPlaceSnakes(t *testing.T) {

r := StandardRuleset{}
for _, test := range tests {
require.Equal(t, test.BoardState.Width*test.BoardState.Height, int32(len(r.getUnoccupiedPoints(test.BoardState))))
require.Equal(t, test.BoardState.Width*test.BoardState.Height, int32(len(r.getUnoccupiedPoints(test.BoardState, true))))
err := r.placeSnakes(test.BoardState)
require.Equal(t, test.Err, err, "Snakes: %d", len(test.BoardState.Snakes))
if err == nil {
Expand Down Expand Up @@ -1732,7 +1733,7 @@ func TestGetUnoccupiedPoints(t *testing.T) {

r := StandardRuleset{}
for _, test := range tests {
unoccupiedPoints := r.getUnoccupiedPoints(test.Board)
unoccupiedPoints := r.getUnoccupiedPoints(test.Board, true)
require.Equal(t, len(test.Expected), len(unoccupiedPoints))
for i, e := range test.Expected {
require.Equal(t, e, unoccupiedPoints[i])
Expand Down Expand Up @@ -1834,12 +1835,12 @@ func TestMaybeSpawnFood(t *testing.T) {
ExpectedFood []Point
}{
// Use pre-tested seeds and results
{123, []Point{}, []Point{{2, 2}}},
{123, []Point{}, []Point{{2, 3}}},
{456, []Point{{4, 4}}, []Point{{4, 4}}},
{789, []Point{{4, 4}}, []Point{{4, 4}}},
{1024, []Point{}, []Point{{4, 1}}},
{511, []Point{{4, 4}}, []Point{{4, 4}, {2, 0}}},
{165, []Point{{4, 4}}, []Point{{4, 4}, {3, 1}}},
{1024, []Point{}, []Point{{1, 2}}},
{511, []Point{{4, 4}}, []Point{{4, 4}, {4, 1}}},
{165, []Point{{4, 4}}, []Point{{4, 4}, {4, 2}}},
}

r := StandardRuleset{}
Expand All @@ -1864,6 +1865,21 @@ func TestMaybeSpawnFood(t *testing.T) {
}
}

func TestSpawnFood(t *testing.T) {
b := &BoardState{
Height: 1,
Width: 3,
Snakes: []Snake{
{Body: []Point{{1, 0}}},
},
}
// Food should never spawn, no room
r := StandardRuleset{}
err := r.spawnFood(b, 99)
require.NoError(t, err)
require.Equal(t, len(b.Food), 0)
}

func TestIsGameOver(t *testing.T) {
tests := []struct {
Snakes []Snake
Expand Down

0 comments on commit c6d9ba1

Please sign in to comment.