From 20c42a7a72550e16d89e953085a25607af98052f Mon Sep 17 00:00:00 2001 From: bvanvugt <1531419+bvanvugt@users.noreply.github.com> Date: Thu, 9 Jan 2020 13:58:49 -0800 Subject: [PATCH 1/5] Constant whitespace. --- standard.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/standard.go b/standard.go index 7ff8e50..7701ee7 100644 --- a/standard.go +++ b/standard.go @@ -11,9 +11,11 @@ const ( BoardSizeSmall = 7 BoardSizeMedium = 11 BoardSizeLarge = 19 + FoodSpawnChance = 0.1 - SnakeMaxHealth = 100 - SnakeStartSize = 3 + + SnakeMaxHealth = 100 + SnakeStartSize = 3 // bvanvugt - TODO: Just return formatted strings instead of codes? NotEliminated = "" From 37a4f3585b77f3dacfffab5dc0dc7d9f58975a43 Mon Sep 17 00:00:00 2001 From: bvanvugt <1531419+bvanvugt@users.noreply.github.com> Date: Tue, 14 Jan 2020 16:39:26 -0800 Subject: [PATCH 2/5] Remove dead code from unit tests. --- standard_test.go | 334 ----------------------------------------------- 1 file changed, 334 deletions(-) diff --git a/standard_test.go b/standard_test.go index 788b1ea..31454be 100644 --- a/standard_test.go +++ b/standard_test.go @@ -1122,337 +1122,3 @@ func TestMaybeSpawnFood(t *testing.T) { } } } - -// func TestCheckForSnakesEating(t *testing.T) { -// snake := &pb.Snake{ -// Body: []*pb.Point{ -// {X: 2, Y: 1}, -// {X: 1, Y: 1}, -// {X: 1, Y: 2}, -// {X: 2, Y: 2}, -// }, -// } -// checkForSnakesEating(&pb.GameFrame{ -// Food: []*pb.Point{ -// {X: 2, Y: 1}, -// }, -// Snakes: []*pb.Snake{snake}, -// }) -// require.Len(t, snake.Body, 4) -// require.Equal(t, snake.Body[2], snake.Body[3]) -// } - -// func TestCheckForSnakesNotEating(t *testing.T) { -// snake := &pb.Snake{ -// Body: []*pb.Point{ -// {X: 2, Y: 1}, -// {X: 1, Y: 1}, -// {X: 1, Y: 2}, -// {X: 2, Y: 2}, -// }, -// } -// checkForSnakesEating(&pb.GameFrame{ -// Food: []*pb.Point{}, -// Snakes: []*pb.Snake{snake}, -// }) -// require.Len(t, snake.Body, 3) -// require.NotEqual(t, snake.Body[2], snake.Body[1]) -// } -// func TestGameFrameSnakeEats(t *testing.T) { -// snake := &pb.Snake{ -// Health: 67, -// Body: []*pb.Point{ -// {X: 1, Y: 1}, -// {X: 1, Y: 2}, -// {X: 1, Y: 3}, -// }, -// } - -// lastFrame.Snakes = []*pb.Snake{snake} - -// gt, err := GameTick(commonGame, lastFrame) -// require.NoError(t, err) -// require.Len(t, gt.Snakes, 1) -// snake = gt.Snakes[0] -// require.Equal(t, int32(100), snake.Health) -// require.Len(t, snake.Body, 4) -// } - -// func TestUpdateFood(t *testing.T) { -// updated, err := updateFood(&pb.Game{Width: 20, Height: 20}, &pb.GameFrame{ -// Food: []*pb.Point{ -// {X: 1, Y: 1}, -// {X: 1, Y: 2}, -// }, -// Snakes: []*pb.Snake{ -// { -// Body: []*pb.Point{ -// {X: 1, Y: 2}, -// {X: 2, Y: 2}, -// {X: 3, Y: 2}, -// }, -// }, -// }, -// }, []*pb.Point{ -// {X: 1, Y: 2}, -// }) -// require.NoError(t, err) -// require.Len(t, updated, 2) -// require.True(t, updated[0].Equal(&pb.Point{X: 1, Y: 1})) -// require.False(t, updated[1].Equal(&pb.Point{X: 1, Y: 2})) -// require.False(t, updated[1].Equal(&pb.Point{X: 2, Y: 2})) -// require.False(t, updated[1].Equal(&pb.Point{X: 3, Y: 2})) -// require.False(t, updated[1].Equal(&pb.Point{X: 1, Y: 1})) -// } - -// func TestUpdateFoodWithFullBoard(t *testing.T) { -// updated, err := updateFood(&pb.Game{Width: 2, Height: 2}, &pb.GameFrame{ -// Food: []*pb.Point{ -// {X: 0, Y: 0}, -// }, -// Snakes: []*pb.Snake{ -// { -// Body: []*pb.Point{ -// {X: 0, Y: 0}, -// {X: 0, Y: 1}, -// {X: 1, Y: 1}, -// {X: 1, Y: 0}, -// }, -// }, -// }, -// }, []*pb.Point{ -// {X: 0, Y: 0}, -// }) -// require.NoError(t, err) -// require.Len(t, updated, 0) -// } - -// func TestGetUnoccupiedPointEven(t *testing.T) { - -// unoccupiedPoint := getUnoccupiedPointEven(2, 2, -// []*pb.Point{}, -// []*pb.Snake{}) -// require.True(t, (unoccupiedPoint.X+unoccupiedPoint.Y)%2 == 0, "Point coordinates should sum to an even number %o ", unoccupiedPoint) -// } - -// func TestGetUnoccupiedPointOdd(t *testing.T) { -// unoccupiedPoint := getUnoccupiedPointOdd(2, 2, -// []*pb.Point{{X: 0, Y: 1}}, -// []*pb.Snake{}) -// require.True(t, (unoccupiedPoint.X+unoccupiedPoint.Y)%2 == 1, "Point coordinates should sum to an odd number %o ", unoccupiedPoint) -// } - -// func TestGetUnoccupiedPointWithFullBoard(t *testing.T) { -// unoccupiedPoint := getUnoccupiedPoint(2, 2, -// []*pb.Point{{X: 0, Y: 0}}, -// []*pb.Snake{ -// { -// Body: []*pb.Point{ -// {X: 0, Y: 1}, -// {X: 1, Y: 1}, -// {X: 1, Y: 0}, -// }, -// }, -// }) -// require.True(t, unoccupiedPoint.Equal(nil)) -// } - -// func TestGetUnoccupiedPointsWithEmptySpots(t *testing.T) { -// unoccupiedPoints := getUnoccupiedPoints(2, 2, -// []*pb.Point{{X: 0, Y: 0}}, -// []*pb.Snake{ -// { -// Body: []*pb.Point{ -// {X: 0, Y: 1}, -// }, -// }, -// }) - -// require.Len(t, unoccupiedPoints, 2) -// require.True(t, unoccupiedPoints[0].Equal(&pb.Point{X: 1, Y: 0})) -// require.True(t, unoccupiedPoints[1].Equal(&pb.Point{X: 1, Y: 1})) -// } - -// func TestGetUniqOccupiedPoints(t *testing.T) { -// unoccupiedPoints := getUniqOccupiedPoints( -// []*pb.Point{ -// {X: 0, Y: 0}, -// }, -// []*pb.Snake{ -// { -// Body: []*pb.Point{ -// {X: 0, Y: 1}, -// {X: 1, Y: 1}, -// {X: 1, Y: 1}, -// {X: 1, Y: 0}, -// }, -// }, -// }) - -// require.Len(t, unoccupiedPoints, 4) -// } - -// func TestGameTickUpdatesTurnCounter(t *testing.T) { -// gt, err := GameTick(commonGame, &pb.GameFrame{Turn: 5}) -// require.NoError(t, err) -// require.Equal(t, int32(6), gt.Turn) -// } - -// func TestGameTickUpdatesSnake(t *testing.T) { -// snake := &pb.Snake{ -// Health: 67, -// Body: []*pb.Point{ -// {X: 1, Y: 1}, -// {X: 1, Y: 2}, -// {X: 1, Y: 3}, -// }, -// } -// game := &pb.Game{ -// Width: 20, -// Height: 20, -// } -// gt, err := GameTick(game, &pb.GameFrame{ -// Turn: 5, -// Snakes: []*pb.Snake{ -// snake, -// }, -// }) -// require.NoError(t, err) -// require.Len(t, gt.Snakes, 1) -// snake = gt.Snakes[0] -// require.Equal(t, int32(66), snake.Health) -// require.Len(t, snake.Body, 3) -// require.Equal(t, &pb.Point{X: 1, Y: 0}, snake.Body[0]) -// require.Equal(t, &pb.Point{X: 1, Y: 1}, snake.Body[1]) -// require.Equal(t, &pb.Point{X: 1, Y: 2}, snake.Body[2]) -// } - -// var commonGame = &pb.Game{ -// Width: 20, -// Height: 20, -// } -// var lastFrame = &pb.GameFrame{ -// Turn: 5, -// Snakes: []*pb.Snake{}, -// Food: []*pb.Point{ -// {X: 1, Y: 0}, -// }, -// } - -// func TestGameTickDeadSnakeDoNotUpdate(t *testing.T) { -// snake := &pb.Snake{ -// Health: 87, -// Body: []*pb.Point{ -// {X: 1, Y: 1}, -// {X: 1, Y: 2}, -// {X: 1, Y: 3}, -// }, -// Death: &pb.Death{ -// Turn: 4, -// Cause: DeathCauseSnakeCollision, -// }, -// } - -// lastFrame.Snakes = []*pb.Snake{snake} - -// gt, err := GameTick(commonGame, lastFrame) -// require.NoError(t, err) -// require.Len(t, gt.Snakes, 1) -// snake = gt.Snakes[0] -// require.Equal(t, int32(87), snake.Health) -// require.Len(t, snake.Body, 3) -// require.Equal(t, &pb.Point{X: 1, Y: 1}, snake.Body[0]) -// require.Equal(t, &pb.Point{X: 1, Y: 2}, snake.Body[1]) -// require.Equal(t, &pb.Point{X: 1, Y: 3}, snake.Body[2]) -// } - -// func TestGameTickUpdatesDeath(t *testing.T) { -// snake := &pb.Snake{ -// Health: 0, -// Body: []*pb.Point{ -// {X: 3, Y: 1}, -// {X: 3, Y: 2}, -// {X: 3, Y: 3}, -// }, -// } - -// lastFrame.Snakes = []*pb.Snake{snake} - -// gt, err := GameTick(commonGame, lastFrame) -// require.NoError(t, err) -// require.NotNil(t, gt.Snakes[0].Death) -// } - -// func TestUpdateSnakes(t *testing.T) { -// snake := &pb.Snake{ -// Body: []*pb.Point{ -// {X: 1, Y: 1}, -// }, -// } -// moves := []*SnakeUpdate{ -// { -// Snake: snake, -// Err: errors.New("some error"), -// }, -// } -// updateSnakes(&pb.Game{}, &pb.GameFrame{ -// Snakes: []*pb.Snake{snake}, -// }, moves) -// require.Equal(t, &pb.Point{X: 1, Y: 0}, snake.Head(), "snake did not move up") - -// moves = []*SnakeUpdate{ -// { -// Snake: snake, -// Move: "left", -// }, -// } -// updateSnakes(&pb.Game{}, &pb.GameFrame{ -// Snakes: []*pb.Snake{snake}, -// }, moves) -// require.Equal(t, &pb.Point{X: 0, Y: 0}, snake.Head(), "snake did not move left") -// } - -// func TestCanFollowTail(t *testing.T) { -// url := setupSnakeServer(t, MoveResponse{ -// Move: "down", -// }, StartResponse{}) -// snake := &pb.Snake{ -// Body: []*pb.Point{ -// {X: 2, Y: 1}, -// {X: 1, Y: 1}, -// {X: 1, Y: 2}, -// {X: 2, Y: 2}, -// }, -// URL: url, -// Health: 100, -// } -// next, err := GameTick(&pb.Game{ -// Width: 20, -// Height: 20, -// }, &pb.GameFrame{ -// Snakes: []*pb.Snake{snake}, -// }) -// require.NoError(t, err) -// require.NotNil(t, next) -// require.Nil(t, next.Snakes[0].Death) -// } - -// func TestNextFoodSpawn(t *testing.T) { -// rand.Seed(1) // random order is 65, 85, 29 -// snakes := []*pb.Snake{ -// {URL: setupSnakeServer(t, MoveResponse{}, StartResponse{})}, -// {URL: setupSnakeServer(t, MoveResponse{}, StartResponse{})}, -// {URL: setupSnakeServer(t, MoveResponse{}, StartResponse{})}, -// {URL: setupSnakeServer(t, MoveResponse{}, StartResponse{})}, -// } -// next, err := GameTick(&pb.Game{ -// Width: 20, -// Height: 20, -// TurnsSinceLastFoodSpawn: 5, -// MaxTurnsToNextFoodSpawn: 5, -// }, &pb.GameFrame{ -// Snakes: snakes, -// }) -// require.NoError(t, err) -// require.Len(t, next.Food, 2) -// } From d7b4663ef434a84c0ada27da14a8797c8adde7e8 Mon Sep 17 00:00:00 2001 From: bvanvugt <1531419+bvanvugt@users.noreply.github.com> Date: Tue, 14 Jan 2020 16:39:41 -0800 Subject: [PATCH 3/5] Bump food spawn rate to better match previous algorithm. --- standard.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard.go b/standard.go index d412f28..ec6632f 100644 --- a/standard.go +++ b/standard.go @@ -12,7 +12,7 @@ const ( BoardSizeMedium = 11 BoardSizeLarge = 19 - FoodSpawnChance = 0.1 + FoodSpawnChance = 0.25 SnakeMaxHealth = 100 SnakeStartSize = 3 From 6edb4ce5d4e745614fc76b42e6431191e20cb5ca Mon Sep 17 00:00:00 2001 From: bvanvugt <1531419+bvanvugt@users.noreply.github.com> Date: Wed, 15 Jan 2020 16:42:43 -0800 Subject: [PATCH 4/5] Reduce standard food spawn to a 15% chance. --- standard.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard.go b/standard.go index ec6632f..f3d608d 100644 --- a/standard.go +++ b/standard.go @@ -12,7 +12,7 @@ const ( BoardSizeMedium = 11 BoardSizeLarge = 19 - FoodSpawnChance = 0.25 + FoodSpawnChance = 0.15 SnakeMaxHealth = 100 SnakeStartSize = 3 From ccd7a4e47ddabd02d2e332877156e9c43ab5d487 Mon Sep 17 00:00:00 2001 From: bvanvugt <1531419+bvanvugt@users.noreply.github.com> Date: Sat, 1 Feb 2020 10:47:15 -0800 Subject: [PATCH 5/5] Maintain at least 1 food on board at all times. --- standard.go | 8 ++++---- standard_test.go | 16 +++++++++------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/standard.go b/standard.go index f3d608d..915d6da 100644 --- a/standard.go +++ b/standard.go @@ -174,7 +174,7 @@ func (r *StandardRuleset) ResolveMoves(prevState *BoardState, moves []SnakeMove) } // TODO: LOG? - err = r.maybeSpawnFood(nextState, 1) + err = r.maybeSpawnFood(nextState) if err != nil { return nil, err } @@ -361,9 +361,9 @@ func (r *StandardRuleset) feedSnakes(b *BoardState) error { return nil } -func (r *StandardRuleset) maybeSpawnFood(b *BoardState, n int) error { - if rand.Float32() <= FoodSpawnChance { - return r.spawnFood(b, n) +func (r *StandardRuleset) maybeSpawnFood(b *BoardState) error { + if len(b.Food) == 0 || rand.Float32() <= FoodSpawnChance { + return r.spawnFood(b, 1) } return nil } diff --git a/standard_test.go b/standard_test.go index 31454be..e25fe29 100644 --- a/standard_test.go +++ b/standard_test.go @@ -1091,15 +1091,16 @@ func TestGetUnoccupiedPoints(t *testing.T) { func TestMaybeSpawnFood(t *testing.T) { tests := []struct { Seed int64 + Food []Point ExpectedFood []Point }{ // Use pre-tested seeds and results - {123, []Point{}}, - {456, []Point{}}, - {789, []Point{}}, - {1024, []Point{{2, 1}}}, - {511, []Point{{2, 0}}}, - {165, []Point{{3, 1}}}, + {123, []Point{}, []Point{{2, 2}}}, + {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}}}, } r := StandardRuleset{} @@ -1111,10 +1112,11 @@ func TestMaybeSpawnFood(t *testing.T) { {Body: []Point{{1, 0}, {1, 1}}}, {Body: []Point{{0, 1}, {0, 2}, {0, 3}}}, }, + Food: test.Food, } rand.Seed(test.Seed) - err := r.maybeSpawnFood(b, 1) + err := r.maybeSpawnFood(b) require.NoError(t, err) require.Equal(t, len(test.ExpectedFood), len(b.Food), "Seed %d", test.Seed) for i, e := range test.ExpectedFood {