Add parameters for food spawn chance and min food.

This commit is contained in:
bvanvugt 2020-11-20 12:00:58 -08:00
parent c6d9ba12ab
commit ca4b6c5dce
2 changed files with 88 additions and 20 deletions

View file

@ -6,15 +6,16 @@ import (
"sort" "sort"
) )
type StandardRuleset struct{} type StandardRuleset struct {
FoodSpawnChance int32 // [0, 100]
MinimumFood int32
}
const ( const (
BoardSizeSmall = 7 BoardSizeSmall = 7
BoardSizeMedium = 11 BoardSizeMedium = 11
BoardSizeLarge = 19 BoardSizeLarge = 19
FoodSpawnChance = 0.15
SnakeMaxHealth = 100 SnakeMaxHealth = 100
SnakeStartSize = 3 SnakeStartSize = 3
@ -173,7 +174,7 @@ func (r *StandardRuleset) placeFoodFixed(b *BoardState) error {
} }
func (r *StandardRuleset) placeFoodRandomly(b *BoardState) error { func (r *StandardRuleset) placeFoodRandomly(b *BoardState) error {
return r.spawnFood(b, len(b.Snakes)) return r.spawnFood(b, int32(len(b.Snakes)))
} }
func (r *StandardRuleset) isKnownBoardSize(b *BoardState) bool { func (r *StandardRuleset) isKnownBoardSize(b *BoardState) bool {
@ -518,14 +519,17 @@ func (r *StandardRuleset) growSnake(snake *Snake) {
} }
func (r *StandardRuleset) maybeSpawnFood(b *BoardState) error { func (r *StandardRuleset) maybeSpawnFood(b *BoardState) error {
if len(b.Food) == 0 || rand.Float32() <= FoodSpawnChance { numCurrentFood := int32(len(b.Food))
if numCurrentFood < r.MinimumFood {
return r.spawnFood(b, r.MinimumFood-numCurrentFood)
} else if r.FoodSpawnChance > 0 && int32(rand.Intn(100)) < r.FoodSpawnChance {
return r.spawnFood(b, 1) return r.spawnFood(b, 1)
} }
return nil return nil
} }
func (r *StandardRuleset) spawnFood(b *BoardState, n int) error { func (r *StandardRuleset) spawnFood(b *BoardState, n int32) error {
for i := 0; i < n; i++ { for i := int32(0); i < n; i++ {
unoccupiedPoints := r.getUnoccupiedPoints(b, false) 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))]

View file

@ -1828,22 +1828,89 @@ func TestGetEvenUnoccupiedPoints(t *testing.T) {
} }
} }
func TestMaybeSpawnFood(t *testing.T) { func TestMaybeSpawnFoodMinimum(t *testing.T) {
tests := []struct {
MinimumFood int32
Food []Point
ExpectedFood int
}{
// Use pre-tested seeds and results
{0, []Point{}, 0},
{1, []Point{}, 1},
{9, []Point{}, 9},
{7, []Point{{4, 5}, {4, 4}, {4, 1}}, 7},
}
for _, test := range tests {
r := StandardRuleset{MinimumFood: test.MinimumFood}
b := &BoardState{
Height: 11,
Width: 11,
Snakes: []Snake{
{Body: []Point{{1, 0}, {1, 1}}},
{Body: []Point{{0, 1}, {0, 2}, {0, 3}}},
},
Food: test.Food,
}
err := r.maybeSpawnFood(b)
require.NoError(t, err)
require.Equal(t, test.ExpectedFood, len(b.Food))
}
}
func TestMaybeSpawnFoodZeroChance(t *testing.T) {
r := StandardRuleset{FoodSpawnChance: 0}
b := &BoardState{
Height: 11,
Width: 11,
Snakes: []Snake{
{Body: []Point{{1, 0}, {1, 1}}},
{Body: []Point{{0, 1}, {0, 2}, {0, 3}}},
},
Food: []Point{},
}
for i := 0; i < 1000; i++ {
err := r.maybeSpawnFood(b)
require.NoError(t, err)
require.Equal(t, len(b.Food), 0)
}
}
func TestMaybeSpawnFoodHundredChance(t *testing.T) {
r := StandardRuleset{FoodSpawnChance: 100}
b := &BoardState{
Height: 11,
Width: 11,
Snakes: []Snake{
{Body: []Point{{1, 0}, {1, 1}}},
{Body: []Point{{0, 1}, {0, 2}, {0, 3}}},
},
Food: []Point{},
}
for i := 1; i <= 22; i++ {
err := r.maybeSpawnFood(b)
require.NoError(t, err)
require.Equal(t, i, len(b.Food))
}
}
func TestMaybeSpawnFoodHalfChance(t *testing.T) {
tests := []struct { tests := []struct {
Seed int64 Seed int64
Food []Point Food []Point
ExpectedFood []Point ExpectedFood int32
}{ }{
// Use pre-tested seeds and results // Use pre-tested seeds and results
{123, []Point{}, []Point{{2, 3}}}, {123, []Point{}, 1},
{456, []Point{{4, 4}}, []Point{{4, 4}}}, {12345, []Point{}, 0},
{789, []Point{{4, 4}}, []Point{{4, 4}}}, {456, []Point{{4, 4}}, 1},
{1024, []Point{}, []Point{{1, 2}}}, {789, []Point{{4, 4}}, 2},
{511, []Point{{4, 4}}, []Point{{4, 4}, {4, 1}}}, {511, []Point{{4, 4}}, 1},
{165, []Point{{4, 4}}, []Point{{4, 4}, {4, 2}}}, {165, []Point{{4, 4}}, 2},
} }
r := StandardRuleset{} r := StandardRuleset{FoodSpawnChance: 50}
for _, test := range tests { for _, test := range tests {
b := &BoardState{ b := &BoardState{
Height: 4, Height: 4,
@ -1858,10 +1925,7 @@ func TestMaybeSpawnFood(t *testing.T) {
rand.Seed(test.Seed) rand.Seed(test.Seed)
err := r.maybeSpawnFood(b) err := r.maybeSpawnFood(b)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, len(test.ExpectedFood), len(b.Food), "Seed %d", test.Seed) require.Equal(t, test.ExpectedFood, int32(len(b.Food)), "Seed %d", test.Seed)
for i, e := range test.ExpectedFood {
require.Equal(t, e, b.Food[i], "Seed %d", test.Seed)
}
} }
} }