Never spawn food within one move of any snake.
This commit is contained in:
parent
f5aec61e04
commit
c6d9ba12ab
3 changed files with 48 additions and 16 deletions
1
go.sum
1
go.sum
|
|
@ -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/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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
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/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 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
|
|
||||||
25
standard.go
25
standard.go
|
|
@ -157,7 +157,7 @@ func (r *StandardRuleset) placeFoodFixed(b *BoardState) error {
|
||||||
// Finally, always place 1 food in center of board for dramatic purposes
|
// Finally, always place 1 food in center of board for dramatic purposes
|
||||||
isCenterOccupied := true
|
isCenterOccupied := true
|
||||||
centerCoord := Point{(b.Width - 1) / 2, (b.Height - 1) / 2}
|
centerCoord := Point{(b.Width - 1) / 2, (b.Height - 1) / 2}
|
||||||
unoccupiedPoints := r.getUnoccupiedPoints(b)
|
unoccupiedPoints := r.getUnoccupiedPoints(b, true)
|
||||||
for _, point := range unoccupiedPoints {
|
for _, point := range unoccupiedPoints {
|
||||||
if point == centerCoord {
|
if point == centerCoord {
|
||||||
isCenterOccupied = false
|
isCenterOccupied = false
|
||||||
|
|
@ -526,7 +526,7 @@ func (r *StandardRuleset) maybeSpawnFood(b *BoardState) error {
|
||||||
|
|
||||||
func (r *StandardRuleset) spawnFood(b *BoardState, n int) error {
|
func (r *StandardRuleset) spawnFood(b *BoardState, n int) error {
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
unoccupiedPoints := r.getUnoccupiedPoints(b)
|
unoccupiedPoints := r.getUnoccupiedPoints(b, false)
|
||||||
if len(unoccupiedPoints) > 0 {
|
if len(unoccupiedPoints) > 0 {
|
||||||
newFood := unoccupiedPoints[rand.Intn(len(unoccupiedPoints))]
|
newFood := unoccupiedPoints[rand.Intn(len(unoccupiedPoints))]
|
||||||
b.Food = append(b.Food, newFood)
|
b.Food = append(b.Food, newFood)
|
||||||
|
|
@ -535,7 +535,7 @@ func (r *StandardRuleset) spawnFood(b *BoardState, n int) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *StandardRuleset) getUnoccupiedPoints(b *BoardState) []Point {
|
func (r *StandardRuleset) getUnoccupiedPoints(b *BoardState, includePossibleMoves bool) []Point {
|
||||||
pointIsOccupied := map[int32]map[int32]bool{}
|
pointIsOccupied := map[int32]map[int32]bool{}
|
||||||
for _, p := range b.Food {
|
for _, p := range b.Food {
|
||||||
if _, xExists := pointIsOccupied[p.X]; !xExists {
|
if _, xExists := pointIsOccupied[p.X]; !xExists {
|
||||||
|
|
@ -544,11 +544,26 @@ func (r *StandardRuleset) getUnoccupiedPoints(b *BoardState) []Point {
|
||||||
pointIsOccupied[p.X][p.Y] = true
|
pointIsOccupied[p.X][p.Y] = true
|
||||||
}
|
}
|
||||||
for _, snake := range b.Snakes {
|
for _, snake := range b.Snakes {
|
||||||
for _, p := range snake.Body {
|
for i, p := range snake.Body {
|
||||||
if _, xExists := pointIsOccupied[p.X]; !xExists {
|
if _, xExists := pointIsOccupied[p.X]; !xExists {
|
||||||
pointIsOccupied[p.X] = map[int32]bool{}
|
pointIsOccupied[p.X] = map[int32]bool{}
|
||||||
}
|
}
|
||||||
pointIsOccupied[p.X][p.Y] = true
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -570,7 +585,7 @@ func (r *StandardRuleset) getUnoccupiedPoints(b *BoardState) []Point {
|
||||||
|
|
||||||
func (r *StandardRuleset) getEvenUnoccupiedPoints(b *BoardState) []Point {
|
func (r *StandardRuleset) getEvenUnoccupiedPoints(b *BoardState) []Point {
|
||||||
// Start by getting unoccupied points
|
// Start by getting unoccupied points
|
||||||
unoccupiedPoints := r.getUnoccupiedPoints(b)
|
unoccupiedPoints := r.getUnoccupiedPoints(b, true)
|
||||||
|
|
||||||
// Create a new array to hold points that are even
|
// Create a new array to hold points that are even
|
||||||
evenUnoccupiedPoints := []Point{}
|
evenUnoccupiedPoints := []Point{}
|
||||||
|
|
|
||||||
|
|
@ -44,17 +44,18 @@ func TestCreateInitialBoardState(t *testing.T) {
|
||||||
Err error
|
Err error
|
||||||
}{
|
}{
|
||||||
{1, 1, []string{"one"}, 0, nil},
|
{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},
|
{9, 8, []string{"one"}, 1, nil},
|
||||||
{2, 2, []string{"one", "two"}, 2, nil},
|
{2, 2, []string{"one", "two"}, 0, nil},
|
||||||
{2, 2, []string{"one", "two"}, 2, nil},
|
|
||||||
{1, 1, []string{"one", "two"}, 2, errors.New("not enough space to place snake")},
|
{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")},
|
{1, 2, []string{"one", "two"}, 2, errors.New("not enough space to place snake")},
|
||||||
{BoardSizeSmall, BoardSizeSmall, []string{"one", "two"}, 3, nil},
|
{BoardSizeSmall, BoardSizeSmall, []string{"one", "two"}, 3, nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
r := StandardRuleset{}
|
r := StandardRuleset{}
|
||||||
for _, test := range tests {
|
for testNum, test := range tests {
|
||||||
state, err := r.CreateInitialBoardState(test.Width, test.Height, test.IDs)
|
state, err := r.CreateInitialBoardState(test.Width, test.Height, test.IDs)
|
||||||
require.Equal(t, test.Err, err)
|
require.Equal(t, test.Err, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -68,7 +69,7 @@ func TestCreateInitialBoardState(t *testing.T) {
|
||||||
for i, id := range test.IDs {
|
for i, id := range test.IDs {
|
||||||
require.Equal(t, id, state.Snakes[i].ID)
|
require.Equal(t, id, state.Snakes[i].ID)
|
||||||
}
|
}
|
||||||
require.Len(t, state.Food, test.ExpectedNumFood)
|
require.Len(t, state.Food, test.ExpectedNumFood, testNum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,7 +213,7 @@ func TestPlaceSnakes(t *testing.T) {
|
||||||
|
|
||||||
r := StandardRuleset{}
|
r := StandardRuleset{}
|
||||||
for _, test := range tests {
|
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)
|
err := r.placeSnakes(test.BoardState)
|
||||||
require.Equal(t, test.Err, err, "Snakes: %d", len(test.BoardState.Snakes))
|
require.Equal(t, test.Err, err, "Snakes: %d", len(test.BoardState.Snakes))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
@ -1732,7 +1733,7 @@ func TestGetUnoccupiedPoints(t *testing.T) {
|
||||||
|
|
||||||
r := StandardRuleset{}
|
r := StandardRuleset{}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
unoccupiedPoints := r.getUnoccupiedPoints(test.Board)
|
unoccupiedPoints := r.getUnoccupiedPoints(test.Board, true)
|
||||||
require.Equal(t, len(test.Expected), len(unoccupiedPoints))
|
require.Equal(t, len(test.Expected), len(unoccupiedPoints))
|
||||||
for i, e := range test.Expected {
|
for i, e := range test.Expected {
|
||||||
require.Equal(t, e, unoccupiedPoints[i])
|
require.Equal(t, e, unoccupiedPoints[i])
|
||||||
|
|
@ -1834,12 +1835,12 @@ func TestMaybeSpawnFood(t *testing.T) {
|
||||||
ExpectedFood []Point
|
ExpectedFood []Point
|
||||||
}{
|
}{
|
||||||
// Use pre-tested seeds and results
|
// Use pre-tested seeds and results
|
||||||
{123, []Point{}, []Point{{2, 2}}},
|
{123, []Point{}, []Point{{2, 3}}},
|
||||||
{456, []Point{{4, 4}}, []Point{{4, 4}}},
|
{456, []Point{{4, 4}}, []Point{{4, 4}}},
|
||||||
{789, []Point{{4, 4}}, []Point{{4, 4}}},
|
{789, []Point{{4, 4}}, []Point{{4, 4}}},
|
||||||
{1024, []Point{}, []Point{{4, 1}}},
|
{1024, []Point{}, []Point{{1, 2}}},
|
||||||
{511, []Point{{4, 4}}, []Point{{4, 4}, {2, 0}}},
|
{511, []Point{{4, 4}}, []Point{{4, 4}, {4, 1}}},
|
||||||
{165, []Point{{4, 4}}, []Point{{4, 4}, {3, 1}}},
|
{165, []Point{{4, 4}}, []Point{{4, 4}, {4, 2}}},
|
||||||
}
|
}
|
||||||
|
|
||||||
r := StandardRuleset{}
|
r := StandardRuleset{}
|
||||||
|
|
@ -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) {
|
func TestIsGameOver(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
Snakes []Snake
|
Snakes []Snake
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue