diff --git a/board.go b/board.go index d9ab796..cb8f1e1 100644 --- a/board.go +++ b/board.go @@ -2,6 +2,9 @@ package rules import "fmt" +// BoardState represents the internal state of a game board. +// NOTE: use NewBoardState to construct these to ensure fields are initialized +// correctly and that tests are resilient to changes to this type. type BoardState struct { Turn int Height int @@ -9,15 +12,26 @@ type BoardState struct { Food []Point Snakes []Snake Hazards []Point + + // Generic game-level state for maps and rules stages to persist data between turns. + GameState map[string]string + + // Numeric state keyed to specific points, also persisted between turns. + PointState map[Point]int } type Point struct { - X int - Y int + X int `json:"X"` + Y int `json:"Y"` + TTL int `json:"TTL,omitempty"` + Value int `json:"Value,omitempty"` } // Makes it easier to copy sample points out of Go logs and test failures. func (p Point) GoString() string { + if p.TTL != 0 || p.Value != 0 { + return fmt.Sprintf("{X:%d, Y:%d, TTL:%d, Value:%d}", p.X, p.Y, p.TTL, p.Value) + } return fmt.Sprintf("{X:%d, Y:%d}", p.X, p.Y) } @@ -33,24 +47,34 @@ type Snake struct { // NewBoardState returns an empty but fully initialized BoardState func NewBoardState(width, height int) *BoardState { return &BoardState{ - Turn: 0, - Height: height, - Width: width, - Food: []Point{}, - Snakes: []Snake{}, - Hazards: []Point{}, + Turn: 0, + Height: height, + Width: width, + Food: []Point{}, + Snakes: []Snake{}, + Hazards: []Point{}, + GameState: map[string]string{}, + PointState: map[Point]int{}, } } // Clone returns a deep copy of prevState that can be safely modified without affecting the original func (prevState *BoardState) Clone() *BoardState { nextState := &BoardState{ - Turn: prevState.Turn, - Height: prevState.Height, - Width: prevState.Width, - Food: append([]Point{}, prevState.Food...), - Snakes: make([]Snake, len(prevState.Snakes)), - Hazards: append([]Point{}, prevState.Hazards...), + Turn: prevState.Turn, + Height: prevState.Height, + Width: prevState.Width, + Food: append([]Point{}, prevState.Food...), + Snakes: make([]Snake, len(prevState.Snakes)), + Hazards: append([]Point{}, prevState.Hazards...), + GameState: make(map[string]string, len(prevState.GameState)), + PointState: make(map[Point]int, len(prevState.PointState)), + } + for key, value := range prevState.GameState { + nextState.GameState[key] = value + } + for key, value := range prevState.PointState { + nextState.PointState[key] = value } for i := 0; i < len(prevState.Snakes); i++ { nextState.Snakes[i].ID = prevState.Snakes[i].ID @@ -63,6 +87,42 @@ func (prevState *BoardState) Clone() *BoardState { return nextState } +// Builder method to set Turn and return the modified BoardState. +func (state *BoardState) WithTurn(turn int) *BoardState { + state.Turn = turn + return state +} + +// Builder method to set Food and return the modified BoardState. +func (state *BoardState) WithFood(food []Point) *BoardState { + state.Food = food + return state +} + +// Builder method to set Hazards and return the modified BoardState. +func (state *BoardState) WithHazards(hazards []Point) *BoardState { + state.Hazards = hazards + return state +} + +// Builder method to set Snakes and return the modified BoardState. +func (state *BoardState) WithSnakes(snakes []Snake) *BoardState { + state.Snakes = snakes + return state +} + +// Builder method to set State and return the modified BoardState. +func (state *BoardState) WithGameState(gameState map[string]string) *BoardState { + state.GameState = gameState + return state +} + +// Builder method to set PointState and return the modified BoardState. +func (state *BoardState) WithPointState(pointState map[Point]int) *BoardState { + state.PointState = pointState + return state +} + // CreateDefaultBoardState is a convenience function for fully initializing a // "default" board state with snakes and food. // In a real game, the engine may generate the board without calling this @@ -120,16 +180,16 @@ func PlaceSnakesFixed(rand Rand, b *BoardState, snakeIDs []string) error { // Create start 8 points mn, md, mx := 1, (b.Width-1)/2, b.Width-2 cornerPoints := []Point{ - {mn, mn}, - {mn, mx}, - {mx, mn}, - {mx, mx}, + {X: mn, Y: mn}, + {X: mn, Y: mx}, + {X: mx, Y: mn}, + {X: mx, Y: mx}, } cardinalPoints := []Point{ - {mn, md}, - {md, mn}, - {md, mx}, - {mx, md}, + {X: mn, Y: md}, + {X: md, Y: mn}, + {X: md, Y: mx}, + {X: mx, Y: md}, } // Sanity check @@ -325,7 +385,7 @@ func PlaceFoodAutomatically(rand Rand, b *BoardState) error { // Deprecated: will be replaced by maps.PlaceFoodFixed func PlaceFoodFixed(rand Rand, b *BoardState) error { - centerCoord := Point{(b.Width - 1) / 2, (b.Height - 1) / 2} + centerCoord := Point{X: (b.Width - 1) / 2, Y: (b.Height - 1) / 2} isSmallBoard := b.Width*b.Height < BoardSizeMedium*BoardSizeMedium // Up to 4 snakes can be placed such that food is nearby on small boards. @@ -335,10 +395,10 @@ func PlaceFoodFixed(rand Rand, b *BoardState) error { for i := 0; i < len(b.Snakes); i++ { snakeHead := b.Snakes[i].Body[0] possibleFoodLocations := []Point{ - {snakeHead.X - 1, snakeHead.Y - 1}, - {snakeHead.X - 1, snakeHead.Y + 1}, - {snakeHead.X + 1, snakeHead.Y - 1}, - {snakeHead.X + 1, snakeHead.Y + 1}, + {X: snakeHead.X - 1, Y: snakeHead.Y - 1}, + {X: snakeHead.X - 1, Y: snakeHead.Y + 1}, + {X: snakeHead.X + 1, Y: snakeHead.Y - 1}, + {X: snakeHead.X + 1, Y: snakeHead.Y + 1}, } // Remove any invalid/unwanted positions @@ -448,7 +508,7 @@ func GetEvenUnoccupiedPoints(b *BoardState) []Point { // removeCenterCoord filters out the board's center point from a list of points. func removeCenterCoord(b *BoardState, points []Point) []Point { - centerCoord := Point{(b.Width - 1) / 2, (b.Height - 1) / 2} + centerCoord := Point{X: (b.Width - 1) / 2, Y: (b.Height - 1) / 2} var noCenterPoints []Point for _, p := range points { if p != centerCoord { diff --git a/board_test.go b/board_test.go index 730d831..827bb4f 100644 --- a/board_test.go +++ b/board_test.go @@ -8,6 +8,30 @@ import ( "github.com/stretchr/testify/require" ) +func TestBoardStateClone(t *testing.T) { + empty := &BoardState{} + require.Equal(t, NewBoardState(0, 0), empty.Clone()) + + full := NewBoardState(11, 11). + WithTurn(99). + WithFood([]Point{{X: 1, Y: 2, TTL: 10, Value: 100}}). + WithHazards([]Point{{X: 3, Y: 4, TTL: 5, Value: 50}}). + WithSnakes([]Snake{ + { + ID: "1", + Body: []Point{{X: 1, Y: 2}}, + Health: 99, + EliminatedCause: EliminatedByCollision, + EliminatedOnTurn: 45, + EliminatedBy: "2", + }, + }). + WithGameState(map[string]string{"example": "game data"}). + WithPointState(map[Point]int{{X: 1, Y: 1}: 42}) + + require.Equal(t, full, full.Clone()) +} + func TestDev1235(t *testing.T) { // Small boards should no longer error and only get 1 food when num snakes > 4 state, err := CreateDefaultBoardState(MaxRand, BoardSizeSmall, BoardSizeSmall, []string{ @@ -346,23 +370,23 @@ func TestPlaceSnake(t *testing.T) { boardState := NewBoardState(BoardSizeSmall, BoardSizeSmall) require.Empty(t, boardState.Snakes) - _ = PlaceSnake(boardState, "a", []Point{{0, 0}, {1, 0}, {1, 1}}) + _ = PlaceSnake(boardState, "a", []Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 1}}) require.Len(t, boardState.Snakes, 1) require.Equal(t, Snake{ ID: "a", - Body: []Point{{0, 0}, {1, 0}, {1, 1}}, + Body: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 1}}, Health: SnakeMaxHealth, EliminatedCause: NotEliminated, EliminatedBy: "", }, boardState.Snakes[0]) - _ = PlaceSnake(boardState, "b", []Point{{0, 2}, {1, 2}, {3, 2}}) + _ = PlaceSnake(boardState, "b", []Point{{X: 0, Y: 2}, {X: 1, Y: 2}, {X: 3, Y: 2}}) require.Len(t, boardState.Snakes, 2) require.Equal(t, Snake{ ID: "b", - Body: []Point{{0, 2}, {1, 2}, {3, 2}}, + Body: []Point{{X: 0, Y: 2}, {X: 1, Y: 2}, {X: 3, Y: 2}}, Health: SnakeMaxHealth, EliminatedCause: NotEliminated, EliminatedBy: "", @@ -411,9 +435,9 @@ func TestPlaceFood(t *testing.T) { Width: BoardSizeSmall, Height: BoardSizeSmall, Snakes: []Snake{ - {Body: []Point{{5, 1}}}, - {Body: []Point{{5, 3}}}, - {Body: []Point{{5, 5}}}, + {Body: []Point{{X: 5, Y: 1}}}, + {Body: []Point{{X: 5, Y: 3}}}, + {Body: []Point{{X: 5, Y: 5}}}, }, }, 4, // +1 because of fixed spawn locations @@ -423,14 +447,14 @@ func TestPlaceFood(t *testing.T) { Width: BoardSizeMedium, Height: BoardSizeMedium, Snakes: []Snake{ - {Body: []Point{{1, 1}}}, - {Body: []Point{{1, 5}}}, - {Body: []Point{{1, 9}}}, - {Body: []Point{{5, 1}}}, - {Body: []Point{{5, 9}}}, - {Body: []Point{{9, 1}}}, - {Body: []Point{{9, 5}}}, - {Body: []Point{{9, 9}}}, + {Body: []Point{{X: 1, Y: 1}}}, + {Body: []Point{{X: 1, Y: 5}}}, + {Body: []Point{{X: 1, Y: 9}}}, + {Body: []Point{{X: 5, Y: 1}}}, + {Body: []Point{{X: 5, Y: 9}}}, + {Body: []Point{{X: 9, Y: 1}}}, + {Body: []Point{{X: 9, Y: 5}}}, + {Body: []Point{{X: 9, Y: 9}}}, }, }, 9, // +1 because of fixed spawn locations @@ -440,12 +464,12 @@ func TestPlaceFood(t *testing.T) { Width: BoardSizeLarge, Height: BoardSizeLarge, Snakes: []Snake{ - {Body: []Point{{1, 1}}}, - {Body: []Point{{1, 9}}}, - {Body: []Point{{1, 17}}}, - {Body: []Point{{17, 1}}}, - {Body: []Point{{17, 9}}}, - {Body: []Point{{17, 17}}}, + {Body: []Point{{X: 1, Y: 1}}}, + {Body: []Point{{X: 1, Y: 9}}}, + {Body: []Point{{X: 1, Y: 17}}}, + {Body: []Point{{X: 17, Y: 1}}}, + {Body: []Point{{X: 17, Y: 9}}}, + {Body: []Point{{X: 17, Y: 17}}}, }, }, 7, // +1 because of fixed spawn locations @@ -478,7 +502,7 @@ func TestPlaceFoodFixed(t *testing.T) { Width: BoardSizeSmall, Height: BoardSizeSmall, Snakes: []Snake{ - {Body: []Point{{1, 3}}}, + {Body: []Point{{X: 1, Y: 3}}}, }, }, }, @@ -487,10 +511,10 @@ func TestPlaceFoodFixed(t *testing.T) { Width: BoardSizeMedium, Height: BoardSizeMedium, Snakes: []Snake{ - {Body: []Point{{1, 1}}}, - {Body: []Point{{1, 5}}}, - {Body: []Point{{9, 5}}}, - {Body: []Point{{9, 9}}}, + {Body: []Point{{X: 1, Y: 1}}}, + {Body: []Point{{X: 1, Y: 5}}}, + {Body: []Point{{X: 9, Y: 5}}}, + {Body: []Point{{X: 9, Y: 9}}}, }, }, }, @@ -499,14 +523,14 @@ func TestPlaceFoodFixed(t *testing.T) { Width: BoardSizeLarge, Height: BoardSizeLarge, Snakes: []Snake{ - {Body: []Point{{1, 1}}}, - {Body: []Point{{1, 9}}}, - {Body: []Point{{1, 17}}}, - {Body: []Point{{9, 1}}}, - {Body: []Point{{9, 17}}}, - {Body: []Point{{17, 1}}}, - {Body: []Point{{17, 9}}}, - {Body: []Point{{17, 17}}}, + {Body: []Point{{X: 1, Y: 1}}}, + {Body: []Point{{X: 1, Y: 9}}}, + {Body: []Point{{X: 1, Y: 17}}}, + {Body: []Point{{X: 9, Y: 1}}}, + {Body: []Point{{X: 9, Y: 17}}}, + {Body: []Point{{X: 17, Y: 1}}}, + {Body: []Point{{X: 17, Y: 9}}}, + {Body: []Point{{X: 17, Y: 17}}}, }, }, }, @@ -519,16 +543,16 @@ func TestPlaceFoodFixed(t *testing.T) { require.NoError(t, err) require.Equal(t, len(test.BoardState.Snakes)+1, len(test.BoardState.Food)) - midPoint := Point{(test.BoardState.Width - 1) / 2, (test.BoardState.Height - 1) / 2} + midPoint := Point{X: (test.BoardState.Width - 1) / 2, Y: (test.BoardState.Height - 1) / 2} // Make sure every snake has food within 2 moves of it for _, snake := range test.BoardState.Snakes { head := snake.Body[0] - bottomLeft := Point{head.X - 1, head.Y - 1} - topLeft := Point{head.X - 1, head.Y + 1} - bottomRight := Point{head.X + 1, head.Y - 1} - topRight := Point{head.X + 1, head.Y + 1} + bottomLeft := Point{X: head.X - 1, Y: head.Y - 1} + topLeft := Point{X: head.X - 1, Y: head.Y + 1} + bottomRight := Point{X: head.X + 1, Y: head.Y - 1} + topRight := Point{X: head.X + 1, Y: head.Y + 1} foundFoodInTwoMoves := false for _, food := range test.BoardState.Food { @@ -559,7 +583,7 @@ func TestPlaceFoodFixedNoRoom(t *testing.T) { Width: 3, Height: 3, Snakes: []Snake{ - {Body: []Point{{1, 1}}}, + {Body: []Point{{X: 1, Y: 1}}}, }, Food: []Point{}, } @@ -572,10 +596,10 @@ func TestPlaceFoodFixedNoRoom_Corners(t *testing.T) { Width: 7, Height: 7, Snakes: []Snake{ - {Body: []Point{{1, 1}}}, - {Body: []Point{{1, 5}}}, - {Body: []Point{{5, 1}}}, - {Body: []Point{{5, 5}}}, + {Body: []Point{{X: 1, Y: 1}}}, + {Body: []Point{{X: 1, Y: 5}}}, + {Body: []Point{{X: 5, Y: 1}}}, + {Body: []Point{{X: 5, Y: 5}}}, }, Food: []Point{}, } @@ -597,10 +621,10 @@ func TestPlaceFoodFixedNoRoom_Corners(t *testing.T) { require.Error(t, err) expectedFood := []Point{ - {0, 2}, {2, 0}, // Snake @ {1, 1} - {0, 4}, {2, 6}, // Snake @ {1, 5} - {4, 0}, {6, 2}, // Snake @ {5, 1} - {4, 6}, {6, 4}, // Snake @ {5, 5} + {X: 0, Y: 2}, {X: 2, Y: 0}, // Snake @ {X: 1, Y: 1} + {X: 0, Y: 4}, {X: 2, Y: 6}, // Snake @ {X: 1, Y: 5} + {X: 4, Y: 0}, {X: 6, Y: 2}, // Snake @ {X: 5, Y: 1} + {X: 4, Y: 6}, {X: 6, Y: 4}, // Snake @ {X: 5, Y: 5} } sortPoints(expectedFood) sortPoints(boardState.Food) @@ -612,10 +636,10 @@ func TestPlaceFoodFixedNoRoom_Cardinal(t *testing.T) { Width: 11, Height: 11, Snakes: []Snake{ - {Body: []Point{{1, 5}}}, - {Body: []Point{{5, 1}}}, - {Body: []Point{{5, 9}}}, - {Body: []Point{{9, 5}}}, + {Body: []Point{{X: 1, Y: 5}}}, + {Body: []Point{{X: 5, Y: 1}}}, + {Body: []Point{{X: 5, Y: 9}}}, + {Body: []Point{{X: 9, Y: 5}}}, }, Food: []Point{}, } @@ -637,10 +661,10 @@ func TestPlaceFoodFixedNoRoom_Cardinal(t *testing.T) { require.Error(t, err) expectedFood := []Point{ - {0, 4}, {0, 6}, // Snake @ {1, 5} - {4, 0}, {6, 0}, // Snake @ {5, 1} - {4, 10}, {6, 10}, // Snake @ {5, 9} - {10, 4}, {10, 6}, // Snake @ {9, 5} + {X: 0, Y: 4}, {X: 0, Y: 6}, // Snake @ {X: 1, Y: 5} + {X: 4, Y: 0}, {X: 6, Y: 0}, // Snake @ {X: 5, Y: 1} + {X: 4, Y: 10}, {X: 6, Y: 10}, // Snake @ {X: 5, Y: 9} + {X: 10, Y: 4}, {X: 10, Y: 6}, // Snake @ {X: 9, Y: 5} } sortPoints(expectedFood) sortPoints(boardState.Food) @@ -653,15 +677,15 @@ func TestGetDistanceBetweenPoints(t *testing.T) { B Point Expected int }{ - {Point{0, 0}, Point{0, 0}, 0}, - {Point{0, 0}, Point{1, 0}, 1}, - {Point{0, 0}, Point{0, 1}, 1}, - {Point{0, 0}, Point{1, 1}, 2}, - {Point{0, 0}, Point{4, 4}, 8}, - {Point{0, 0}, Point{4, 6}, 10}, - {Point{8, 0}, Point{8, 0}, 0}, - {Point{8, 0}, Point{8, 8}, 8}, - {Point{8, 0}, Point{0, 8}, 16}, + {Point{X: 0, Y: 0}, Point{X: 0, Y: 0}, 0}, + {Point{X: 0, Y: 0}, Point{X: 1, Y: 0}, 1}, + {Point{X: 0, Y: 0}, Point{X: 0, Y: 1}, 1}, + {Point{X: 0, Y: 0}, Point{X: 1, Y: 1}, 2}, + {Point{X: 0, Y: 0}, Point{X: 4, Y: 4}, 8}, + {Point{X: 0, Y: 0}, Point{X: 4, Y: 6}, 10}, + {Point{X: 8, Y: 0}, Point{X: 8, Y: 0}, 0}, + {Point{X: 8, Y: 0}, Point{X: 8, Y: 8}, 8}, + {Point{X: 8, Y: 0}, Point{X: 0, Y: 8}, 16}, } for _, test := range tests { @@ -704,20 +728,20 @@ func TestGetUnoccupiedPoints(t *testing.T) { Height: 1, Width: 1, }, - []Point{{0, 0}}, + []Point{{X: 0, Y: 0}}, }, { &BoardState{ Height: 1, Width: 2, }, - []Point{{0, 0}, {1, 0}}, + []Point{{X: 0, Y: 0}, {X: 1, Y: 0}}, }, { &BoardState{ Height: 1, Width: 1, - Food: []Point{{0, 0}, {101, 202}, {-4, -5}}, + Food: []Point{{X: 0, Y: 0}, {X: 101, Y: 202}, {X: -4, Y: -5}}, }, []Point{}, }, @@ -725,15 +749,15 @@ func TestGetUnoccupiedPoints(t *testing.T) { &BoardState{ Height: 2, Width: 2, - Food: []Point{{0, 0}, {1, 0}}, + Food: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}}, }, - []Point{{0, 1}, {1, 1}}, + []Point{{X: 0, Y: 1}, {X: 1, Y: 1}}, }, { &BoardState{ Height: 2, Width: 2, - Food: []Point{{0, 0}, {0, 1}, {1, 0}, {1, 1}}, + Food: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 0}, {X: 1, Y: 1}}, }, []Point{}, }, @@ -742,38 +766,38 @@ func TestGetUnoccupiedPoints(t *testing.T) { Height: 4, Width: 1, Snakes: []Snake{ - {Body: []Point{{0, 0}}}, + {Body: []Point{{X: 0, Y: 0}}}, }, }, - []Point{{0, 1}, {0, 2}, {0, 3}}, + []Point{{X: 0, Y: 1}, {X: 0, Y: 2}, {X: 0, Y: 3}}, }, { &BoardState{ Height: 2, Width: 3, Snakes: []Snake{ - {Body: []Point{{0, 0}, {1, 0}, {1, 1}}}, + {Body: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 1}}}, }, }, - []Point{{0, 1}, {2, 0}, {2, 1}}, + []Point{{X: 0, Y: 1}, {X: 2, Y: 0}, {X: 2, Y: 1}}, }, { &BoardState{ Height: 2, Width: 3, - Food: []Point{{0, 0}, {1, 0}, {1, 1}, {2, 0}}, + Food: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 1}, {X: 2, Y: 0}}, Snakes: []Snake{ - {Body: []Point{{0, 0}, {1, 0}, {1, 1}}}, - {Body: []Point{{0, 1}}}, + {Body: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 1}}}, + {Body: []Point{{X: 0, Y: 1}}}, }, }, - []Point{{2, 1}}, + []Point{{X: 2, Y: 1}}, }, { &BoardState{ Height: 1, Width: 1, - Hazards: []Point{{0, 0}}, + Hazards: []Point{{X: 0, Y: 0}}, }, []Point{}, }, @@ -781,22 +805,22 @@ func TestGetUnoccupiedPoints(t *testing.T) { &BoardState{ Height: 2, Width: 2, - Hazards: []Point{{1, 1}}, + Hazards: []Point{{X: 1, Y: 1}}, }, - []Point{{0, 0}, {0, 1}, {1, 0}}, + []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 0}}, }, { &BoardState{ Height: 2, Width: 3, - Food: []Point{{1, 1}, {2, 0}}, + Food: []Point{{X: 1, Y: 1}, {X: 2, Y: 0}}, Snakes: []Snake{ - {Body: []Point{{0, 0}, {1, 0}, {1, 1}}}, - {Body: []Point{{0, 1}}}, + {Body: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 1}}}, + {Body: []Point{{X: 0, Y: 1}}}, }, - Hazards: []Point{{0, 0}, {1, 0}}, + Hazards: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}}, }, - []Point{{2, 1}}, + []Point{{X: 2, Y: 1}}, }, } @@ -819,20 +843,20 @@ func TestGetEvenUnoccupiedPoints(t *testing.T) { Height: 1, Width: 1, }, - []Point{{0, 0}}, + []Point{{X: 0, Y: 0}}, }, { &BoardState{ Height: 2, Width: 2, }, - []Point{{0, 0}, {1, 1}}, + []Point{{X: 0, Y: 0}, {X: 1, Y: 1}}, }, { &BoardState{ Height: 1, Width: 1, - Food: []Point{{0, 0}, {101, 202}, {-4, -5}}, + Food: []Point{{X: 0, Y: 0}, {X: 101, Y: 202}, {X: -4, Y: -5}}, }, []Point{}, }, @@ -840,15 +864,15 @@ func TestGetEvenUnoccupiedPoints(t *testing.T) { &BoardState{ Height: 2, Width: 2, - Food: []Point{{0, 0}, {1, 0}}, + Food: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}}, }, - []Point{{1, 1}}, + []Point{{X: 1, Y: 1}}, }, { &BoardState{ Height: 4, Width: 4, - Food: []Point{{0, 0}, {0, 2}, {1, 1}, {1, 3}, {2, 0}, {2, 2}, {3, 1}, {3, 3}}, + Food: []Point{{X: 0, Y: 0}, {X: 0, Y: 2}, {X: 1, Y: 1}, {X: 1, Y: 3}, {X: 2, Y: 0}, {X: 2, Y: 2}, {X: 3, Y: 1}, {X: 3, Y: 3}}, }, []Point{}, }, @@ -857,32 +881,32 @@ func TestGetEvenUnoccupiedPoints(t *testing.T) { Height: 4, Width: 1, Snakes: []Snake{ - {Body: []Point{{0, 0}}}, + {Body: []Point{{X: 0, Y: 0}}}, }, }, - []Point{{0, 2}}, + []Point{{X: 0, Y: 2}}, }, { &BoardState{ Height: 2, Width: 3, Snakes: []Snake{ - {Body: []Point{{0, 0}, {1, 0}, {1, 1}}}, + {Body: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 1}}}, }, }, - []Point{{2, 0}}, + []Point{{X: 2, Y: 0}}, }, { &BoardState{ Height: 2, Width: 3, - Food: []Point{{0, 0}, {1, 0}, {1, 1}, {2, 1}}, + Food: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 1}, {X: 2, Y: 1}}, Snakes: []Snake{ - {Body: []Point{{0, 0}, {1, 0}, {1, 1}}}, - {Body: []Point{{0, 1}}}, + {Body: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 1}}}, + {Body: []Point{{X: 0, Y: 1}}}, }, }, - []Point{{2, 0}}, + []Point{{X: 2, Y: 0}}, }, } @@ -902,7 +926,7 @@ func TestPlaceFoodRandomly(t *testing.T) { Height: 1, Width: 3, Snakes: []Snake{ - {Body: []Point{{1, 0}}}, + {Body: []Point{{X: 1, Y: 0}}}, }, } // Food should never spawn, no room diff --git a/cli/commands/play_test.go b/cli/commands/play_test.go index 88624bc..44d0b35 100644 --- a/cli/commands/play_test.go +++ b/cli/commands/play_test.go @@ -45,11 +45,10 @@ func buildDefaultGameState() *GameState { func TestGetIndividualBoardStateForSnake(t *testing.T) { s1 := rules.Snake{ID: "one", Body: []rules.Point{{X: 3, Y: 3}}} s2 := rules.Snake{ID: "two", Body: []rules.Point{{X: 4, Y: 3}}} - state := &rules.BoardState{ - Height: 11, - Width: 11, - Snakes: []rules.Snake{s1, s2}, - } + state := rules.NewBoardState(11, 11). + WithSnakes( + []rules.Snake{s1, s2}, + ) s1State := SnakeState{ ID: "one", Name: "ONE", @@ -85,11 +84,8 @@ func TestGetIndividualBoardStateForSnake(t *testing.T) { func TestSettingsRequestSerialization(t *testing.T) { s1 := rules.Snake{ID: "one", Body: []rules.Point{{X: 3, Y: 3}}} s2 := rules.Snake{ID: "two", Body: []rules.Point{{X: 4, Y: 3}}} - state := &rules.BoardState{ - Height: 11, - Width: 11, - Snakes: []rules.Snake{s1, s2}, - } + state := rules.NewBoardState(11, 11). + WithSnakes([]rules.Snake{s1, s2}) s1State := SnakeState{ ID: "one", Name: "ONE", @@ -255,12 +251,11 @@ func TestBuildFrameEvent(t *testing.T) { }, { name: "snake fields", - boardState: &rules.BoardState{ - Turn: 99, - Height: 19, - Width: 25, - Food: []rules.Point{{X: 9, Y: 4}}, - Snakes: []rules.Snake{ + boardState: rules.NewBoardState(19, 25). + WithTurn(99). + WithFood([]rules.Point{{X: 9, Y: 4}}). + WithHazards([]rules.Point{{X: 8, Y: 6}}). + WithSnakes([]rules.Snake{ { ID: "1", Body: []rules.Point{ @@ -273,9 +268,7 @@ func TestBuildFrameEvent(t *testing.T) { EliminatedOnTurn: 45, EliminatedBy: "1", }, - }, - Hazards: []rules.Point{{X: 8, Y: 6}}, - }, + }), snakeStates: map[string]SnakeState{ "1": { URL: "http://example.com", @@ -326,18 +319,15 @@ func TestBuildFrameEvent(t *testing.T) { }, { name: "snake errors", - boardState: &rules.BoardState{ - Height: 19, - Width: 25, - Snakes: []rules.Snake{ + boardState: rules.NewBoardState(19, 25). + WithSnakes([]rules.Snake{ { ID: "bad_status", }, { ID: "connection_error", }, - }, - }, + }), snakeStates: map[string]SnakeState{ "bad_status": { StatusCode: 504, @@ -366,6 +356,8 @@ func TestBuildFrameEvent(t *testing.T) { Error: "0:Error communicating with server", }, }, + Food: []rules.Point{}, + Hazards: []rules.Point{}, }, }, }, @@ -384,11 +376,7 @@ func TestBuildFrameEvent(t *testing.T) { func TestGetMoveForSnake(t *testing.T) { s1 := rules.Snake{ID: "one", Body: []rules.Point{{X: 3, Y: 3}}} s2 := rules.Snake{ID: "two", Body: []rules.Point{{X: 4, Y: 3}}} - boardState := &rules.BoardState{ - Height: 11, - Width: 11, - Snakes: []rules.Snake{s1, s2}, - } + boardState := rules.NewBoardState(11, 11).WithSnakes([]rules.Snake{s1, s2}) tests := []struct { name string @@ -530,11 +518,7 @@ func TestGetMoveForSnake(t *testing.T) { func TestCreateNextBoardState(t *testing.T) { s1 := rules.Snake{ID: "one", Body: []rules.Point{{X: 3, Y: 3}}} - boardState := &rules.BoardState{ - Height: 11, - Width: 11, - Snakes: []rules.Snake{s1}, - } + boardState := rules.NewBoardState(11, 11).WithSnakes([]rules.Snake{s1}) snakeState := SnakeState{ ID: s1.ID, URL: "http://example.com", diff --git a/constrictor_test.go b/constrictor_test.go index 9dffacb..722a408 100644 --- a/constrictor_test.go +++ b/constrictor_test.go @@ -17,16 +17,16 @@ var constrictorMoveAndCollideMAD = gameTestCase{ Snakes: []Snake{ { ID: "one", - Body: []Point{{1, 1}, {2, 1}}, + Body: []Point{{X: 1, Y: 1}, {X: 2, Y: 1}}, Health: 99, }, { ID: "two", - Body: []Point{{1, 2}, {2, 2}}, + Body: []Point{{X: 1, Y: 2}, {X: 2, Y: 2}}, Health: 99, }, }, - Food: []Point{{10, 10}, {9, 9}, {8, 8}}, + Food: []Point{{X: 10, Y: 10}, {X: 9, Y: 9}, {X: 8, Y: 8}}, Hazards: []Point{}, }, []SnakeMove{ @@ -40,7 +40,7 @@ var constrictorMoveAndCollideMAD = gameTestCase{ Snakes: []Snake{ { ID: "one", - Body: []Point{{1, 2}, {1, 1}, {1, 1}}, + Body: []Point{{X: 1, Y: 2}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100, EliminatedCause: EliminatedByCollision, EliminatedBy: "two", @@ -48,7 +48,7 @@ var constrictorMoveAndCollideMAD = gameTestCase{ }, { ID: "two", - Body: []Point{{1, 1}, {1, 2}, {1, 2}}, + Body: []Point{{X: 1, Y: 1}, {X: 1, Y: 2}, {X: 1, Y: 2}}, Health: 100, EliminatedCause: EliminatedByCollision, EliminatedBy: "one", diff --git a/maps/empty_test.go b/maps/empty_test.go index 39b4432..faa6a6c 100644 --- a/maps/empty_test.go +++ b/maps/empty_test.go @@ -28,95 +28,53 @@ func TestEmptyMapSetupBoard(t *testing.T) { "empty 7x7", rules.NewBoardState(7, 7), rules.MinRand, - &rules.BoardState{ - Width: 7, - Height: 7, - Snakes: []rules.Snake{}, - Food: []rules.Point{}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(7, 7), nil, }, { "not enough room for snakes 7x7", - &rules.BoardState{ - Width: 7, - Height: 7, - Snakes: generateSnakes(17), - Food: []rules.Point{}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(7, 7).WithSnakes(generateSnakes(17)), rules.MinRand, nil, rules.ErrorTooManySnakes, }, { "not enough room for snakes 5x5", - &rules.BoardState{ - Width: 5, - Height: 5, - Snakes: generateSnakes(14), - Food: []rules.Point{}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(5, 5).WithSnakes(generateSnakes(14)), rules.MinRand, nil, rules.ErrorTooManySnakes, }, { "full 11x11 min", - &rules.BoardState{ - Width: 11, - Height: 11, - Snakes: generateSnakes(8), - Food: []rules.Point{}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(11, 11).WithSnakes(generateSnakes(8)), rules.MinRand, - &rules.BoardState{ - Width: 11, - Height: 11, - Snakes: []rules.Snake{ - {ID: "1", Body: []rules.Point{{X: 1, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100}, - {ID: "2", Body: []rules.Point{{X: 1, Y: 9}, {X: 1, Y: 9}, {X: 1, Y: 9}}, Health: 100}, - {ID: "3", Body: []rules.Point{{X: 9, Y: 1}, {X: 9, Y: 1}, {X: 9, Y: 1}}, Health: 100}, - {ID: "4", Body: []rules.Point{{X: 9, Y: 9}, {X: 9, Y: 9}, {X: 9, Y: 9}}, Health: 100}, - {ID: "5", Body: []rules.Point{{X: 1, Y: 5}, {X: 1, Y: 5}, {X: 1, Y: 5}}, Health: 100}, - {ID: "6", Body: []rules.Point{{X: 5, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 1}}, Health: 100}, - {ID: "7", Body: []rules.Point{{X: 5, Y: 9}, {X: 5, Y: 9}, {X: 5, Y: 9}}, Health: 100}, - {ID: "8", Body: []rules.Point{{X: 9, Y: 5}, {X: 9, Y: 5}, {X: 9, Y: 5}}, Health: 100}, - }, - Food: []rules.Point{}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(11, 11).WithSnakes([]rules.Snake{ + {ID: "1", Body: []rules.Point{{X: 1, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100}, + {ID: "2", Body: []rules.Point{{X: 1, Y: 9}, {X: 1, Y: 9}, {X: 1, Y: 9}}, Health: 100}, + {ID: "3", Body: []rules.Point{{X: 9, Y: 1}, {X: 9, Y: 1}, {X: 9, Y: 1}}, Health: 100}, + {ID: "4", Body: []rules.Point{{X: 9, Y: 9}, {X: 9, Y: 9}, {X: 9, Y: 9}}, Health: 100}, + {ID: "5", Body: []rules.Point{{X: 1, Y: 5}, {X: 1, Y: 5}, {X: 1, Y: 5}}, Health: 100}, + {ID: "6", Body: []rules.Point{{X: 5, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 1}}, Health: 100}, + {ID: "7", Body: []rules.Point{{X: 5, Y: 9}, {X: 5, Y: 9}, {X: 5, Y: 9}}, Health: 100}, + {ID: "8", Body: []rules.Point{{X: 9, Y: 5}, {X: 9, Y: 5}, {X: 9, Y: 5}}, Health: 100}, + }), nil, }, { "full 11x11 max", - &rules.BoardState{ - Width: 11, - Height: 11, - Snakes: generateSnakes(8), - Food: []rules.Point{}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(11, 11).WithSnakes(generateSnakes(8)), rules.MaxRand, - &rules.BoardState{ - Width: 11, - Height: 11, - Snakes: []rules.Snake{ - {ID: "1", Body: []rules.Point{{X: 5, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 1}}, Health: 100}, - {ID: "2", Body: []rules.Point{{X: 5, Y: 9}, {X: 5, Y: 9}, {X: 5, Y: 9}}, Health: 100}, - {ID: "3", Body: []rules.Point{{X: 9, Y: 5}, {X: 9, Y: 5}, {X: 9, Y: 5}}, Health: 100}, - {ID: "4", Body: []rules.Point{{X: 1, Y: 5}, {X: 1, Y: 5}, {X: 1, Y: 5}}, Health: 100}, - {ID: "5", Body: []rules.Point{{X: 1, Y: 9}, {X: 1, Y: 9}, {X: 1, Y: 9}}, Health: 100}, - {ID: "6", Body: []rules.Point{{X: 9, Y: 1}, {X: 9, Y: 1}, {X: 9, Y: 1}}, Health: 100}, - {ID: "7", Body: []rules.Point{{X: 9, Y: 9}, {X: 9, Y: 9}, {X: 9, Y: 9}}, Health: 100}, - {ID: "8", Body: []rules.Point{{X: 1, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100}, - }, - Food: []rules.Point{}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(11, 11).WithSnakes([]rules.Snake{ + {ID: "1", Body: []rules.Point{{X: 5, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 1}}, Health: 100}, + {ID: "2", Body: []rules.Point{{X: 5, Y: 9}, {X: 5, Y: 9}, {X: 5, Y: 9}}, Health: 100}, + {ID: "3", Body: []rules.Point{{X: 9, Y: 5}, {X: 9, Y: 5}, {X: 9, Y: 5}}, Health: 100}, + {ID: "4", Body: []rules.Point{{X: 1, Y: 5}, {X: 1, Y: 5}, {X: 1, Y: 5}}, Health: 100}, + {ID: "5", Body: []rules.Point{{X: 1, Y: 9}, {X: 1, Y: 9}, {X: 1, Y: 9}}, Health: 100}, + {ID: "6", Body: []rules.Point{{X: 9, Y: 1}, {X: 9, Y: 1}, {X: 9, Y: 1}}, Health: 100}, + {ID: "7", Body: []rules.Point{{X: 9, Y: 9}, {X: 9, Y: 9}, {X: 9, Y: 9}}, Health: 100}, + {ID: "8", Body: []rules.Point{{X: 1, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100}, + }), nil, }, } @@ -139,24 +97,13 @@ func TestEmptyMapSetupBoard(t *testing.T) { func TestEmptyMapUpdateBoard(t *testing.T) { m := maps.EmptyMap{} - initialBoardState := &rules.BoardState{ - Width: 2, - Height: 2, - Snakes: []rules.Snake{}, - Food: []rules.Point{{X: 0, Y: 0}}, - Hazards: []rules.Point{}, - } + initialBoardState := rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 0}}) settings := rules.NewSettingsWithParams(rules.ParamFoodSpawnChance, "50", rules.ParamMinimumFood, "2").WithRand(rules.MaxRand) nextBoardState := initialBoardState.Clone() err := m.UpdateBoard(initialBoardState.Clone(), settings, maps.NewBoardStateEditor(nextBoardState)) require.NoError(t, err) - require.Equal(t, &rules.BoardState{ - Width: 2, - Height: 2, - Snakes: []rules.Snake{}, - Food: []rules.Point{{X: 0, Y: 0}}, - Hazards: []rules.Point{}, - }, nextBoardState) + expectedBoardState := rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 0}}) + require.Equal(t, expectedBoardState, nextBoardState) } diff --git a/maps/game_map.go b/maps/game_map.go index 5ab76b4..5788d74 100644 --- a/maps/game_map.go +++ b/maps/game_map.go @@ -166,6 +166,12 @@ type Editor interface { // Note: the body values in the return value are a copy and modifying them won't affect the board. SnakeBodies() map[string][]rules.Point + // Get an editable reference to the BoardState's GameState field + GameState() map[string]string + + // Get an editable reference to the BoardState's PointState field + PointState() map[rules.Point]int + // Given a list of Snakes and a list of head coordinates, randomly place // the snakes on those coordinates, or return an error if placement of all // Snakes is impossible. @@ -270,6 +276,16 @@ func (editor *BoardStateEditor) SnakeBodies() map[string][]rules.Point { return result } +// Get an editable reference to the BoardState's GameState field +func (editor *BoardStateEditor) GameState() map[string]string { + return editor.boardState.GameState +} + +// Get an editable reference to the BoardState's PointState field +func (editor *BoardStateEditor) PointState() map[rules.Point]int { + return editor.boardState.PointState +} + // Given a list of Snakes and a list of head coordinates, randomly place // the snakes on those coordinates, or return an error if placement of all // Snakes is impossible. diff --git a/maps/game_map_test.go b/maps/game_map_test.go index 7ce3865..3224042 100644 --- a/maps/game_map_test.go +++ b/maps/game_map_test.go @@ -135,18 +135,16 @@ func TestBoardStateEditor(t *testing.T) { editor.PlaceSnake("existing_snake", []rules.Point{{X: 5, Y: 2}, {X: 5, Y: 1}, {X: 5, Y: 0}}, 99) editor.PlaceSnake("new_snake", []rules.Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 1}}, 98) - require.Equal(t, &rules.BoardState{ - Width: 11, - Height: 11, - Food: []rules.Point{ + expected := rules.NewBoardState(11, 11). + WithFood([]rules.Point{ {X: 1, Y: 3}, {X: 3, Y: 7}, - }, - Hazards: []rules.Point{ + }). + WithHazards([]rules.Point{ {X: 1, Y: 3}, {X: 3, Y: 7}, - }, - Snakes: []rules.Snake{ + }). + WithSnakes([]rules.Snake{ { ID: "existing_snake", Health: 99, @@ -157,8 +155,8 @@ func TestBoardStateEditor(t *testing.T) { Health: 98, Body: []rules.Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 1}}, }, - }, - }, boardState) + }) + require.Equal(t, expected, boardState) require.Equal(t, []rules.Point{ {X: 1, Y: 3}, diff --git a/maps/helpers_test.go b/maps/helpers_test.go index fdf7e5b..84349ab 100644 --- a/maps/helpers_test.go +++ b/maps/helpers_test.go @@ -82,11 +82,10 @@ func TestUpdateBoard(t *testing.T) { }, } - previousBoardState := &rules.BoardState{ - Turn: 0, - Food: []rules.Point{{X: 0, Y: 1}}, - Hazards: []rules.Point{{X: 3, Y: 4}}, - Snakes: []rules.Snake{ + previousBoardState := rules.NewBoardState(5, 5). + WithFood([]rules.Point{{X: 0, Y: 1}}). + WithHazards([]rules.Point{{X: 3, Y: 4}}). + WithSnakes([]rules.Snake{ { ID: "1", Health: 100, @@ -96,9 +95,7 @@ func TestUpdateBoard(t *testing.T) { {X: 6, Y: 2}, }, }, - }, - } - + }) maps.TestMap(testMap.ID(), testMap, func() { boardState, err := maps.UpdateBoard(testMap.ID(), previousBoardState, rules.Settings{}) diff --git a/maps/standard_test.go b/maps/standard_test.go index ab9107e..1b8613f 100644 --- a/maps/standard_test.go +++ b/maps/standard_test.go @@ -29,65 +29,29 @@ func TestStandardMapSetupBoard(t *testing.T) { "empty 7x7", rules.NewBoardState(7, 7), rules.MinRand, - &rules.BoardState{ - Width: 7, - Height: 7, - Snakes: []rules.Snake{}, - Food: []rules.Point{{X: 3, Y: 3}}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(7, 7).WithFood([]rules.Point{{X: 3, Y: 3}}), nil, }, { "not enough room for snakes 7x7", - &rules.BoardState{ - Width: 7, - Height: 7, - Snakes: generateSnakes(17), - Food: []rules.Point{}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(7, 7).WithSnakes(generateSnakes(17)), rules.MinRand, nil, rules.ErrorTooManySnakes, }, { "not enough room for snakes 5x5", - &rules.BoardState{ - Width: 5, - Height: 5, - Snakes: generateSnakes(14), - Food: []rules.Point{}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(5, 5).WithSnakes(generateSnakes(14)), rules.MinRand, nil, rules.ErrorTooManySnakes, }, { "full 11x11 min", - &rules.BoardState{ - Width: 11, - Height: 11, - Snakes: generateSnakes(8), - Food: []rules.Point{}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(11, 11).WithSnakes(generateSnakes(8)), rules.MinRand, - &rules.BoardState{ - Width: 11, - Height: 11, - Snakes: []rules.Snake{ - {ID: "1", Body: []rules.Point{{X: 1, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100}, - {ID: "2", Body: []rules.Point{{X: 1, Y: 9}, {X: 1, Y: 9}, {X: 1, Y: 9}}, Health: 100}, - {ID: "3", Body: []rules.Point{{X: 9, Y: 1}, {X: 9, Y: 1}, {X: 9, Y: 1}}, Health: 100}, - {ID: "4", Body: []rules.Point{{X: 9, Y: 9}, {X: 9, Y: 9}, {X: 9, Y: 9}}, Health: 100}, - {ID: "5", Body: []rules.Point{{X: 1, Y: 5}, {X: 1, Y: 5}, {X: 1, Y: 5}}, Health: 100}, - {ID: "6", Body: []rules.Point{{X: 5, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 1}}, Health: 100}, - {ID: "7", Body: []rules.Point{{X: 5, Y: 9}, {X: 5, Y: 9}, {X: 5, Y: 9}}, Health: 100}, - {ID: "8", Body: []rules.Point{{X: 9, Y: 5}, {X: 9, Y: 5}, {X: 9, Y: 5}}, Health: 100}, - }, - Food: []rules.Point{ + rules.NewBoardState(11, 11). + WithFood([]rules.Point{ {X: 0, Y: 2}, {X: 0, Y: 8}, {X: 8, Y: 0}, @@ -97,35 +61,25 @@ func TestStandardMapSetupBoard(t *testing.T) { {X: 4, Y: 10}, {X: 10, Y: 4}, {X: 5, Y: 5}, - }, - Hazards: []rules.Point{}, - }, + }). + WithSnakes([]rules.Snake{ + {ID: "1", Body: []rules.Point{{X: 1, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100}, + {ID: "2", Body: []rules.Point{{X: 1, Y: 9}, {X: 1, Y: 9}, {X: 1, Y: 9}}, Health: 100}, + {ID: "3", Body: []rules.Point{{X: 9, Y: 1}, {X: 9, Y: 1}, {X: 9, Y: 1}}, Health: 100}, + {ID: "4", Body: []rules.Point{{X: 9, Y: 9}, {X: 9, Y: 9}, {X: 9, Y: 9}}, Health: 100}, + {ID: "5", Body: []rules.Point{{X: 1, Y: 5}, {X: 1, Y: 5}, {X: 1, Y: 5}}, Health: 100}, + {ID: "6", Body: []rules.Point{{X: 5, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 1}}, Health: 100}, + {ID: "7", Body: []rules.Point{{X: 5, Y: 9}, {X: 5, Y: 9}, {X: 5, Y: 9}}, Health: 100}, + {ID: "8", Body: []rules.Point{{X: 9, Y: 5}, {X: 9, Y: 5}, {X: 9, Y: 5}}, Health: 100}, + }), nil, }, { "full 11x11 max", - &rules.BoardState{ - Width: 11, - Height: 11, - Snakes: generateSnakes(8), - Food: []rules.Point{}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(11, 11).WithSnakes(generateSnakes(8)), rules.MaxRand, - &rules.BoardState{ - Width: 11, - Height: 11, - Snakes: []rules.Snake{ - {ID: "1", Body: []rules.Point{{X: 5, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 1}}, Health: 100}, - {ID: "2", Body: []rules.Point{{X: 5, Y: 9}, {X: 5, Y: 9}, {X: 5, Y: 9}}, Health: 100}, - {ID: "3", Body: []rules.Point{{X: 9, Y: 5}, {X: 9, Y: 5}, {X: 9, Y: 5}}, Health: 100}, - {ID: "4", Body: []rules.Point{{X: 1, Y: 5}, {X: 1, Y: 5}, {X: 1, Y: 5}}, Health: 100}, - {ID: "5", Body: []rules.Point{{X: 1, Y: 9}, {X: 1, Y: 9}, {X: 1, Y: 9}}, Health: 100}, - {ID: "6", Body: []rules.Point{{X: 9, Y: 1}, {X: 9, Y: 1}, {X: 9, Y: 1}}, Health: 100}, - {ID: "7", Body: []rules.Point{{X: 9, Y: 9}, {X: 9, Y: 9}, {X: 9, Y: 9}}, Health: 100}, - {ID: "8", Body: []rules.Point{{X: 1, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100}, - }, - Food: []rules.Point{ + rules.NewBoardState(11, 11). + WithFood([]rules.Point{ {X: 6, Y: 0}, {X: 6, Y: 10}, {X: 10, Y: 6}, @@ -135,9 +89,17 @@ func TestStandardMapSetupBoard(t *testing.T) { {X: 10, Y: 8}, {X: 2, Y: 0}, {X: 5, Y: 5}, - }, - Hazards: []rules.Point{}, - }, + }). + WithSnakes([]rules.Snake{ + {ID: "1", Body: []rules.Point{{X: 5, Y: 1}, {X: 5, Y: 1}, {X: 5, Y: 1}}, Health: 100}, + {ID: "2", Body: []rules.Point{{X: 5, Y: 9}, {X: 5, Y: 9}, {X: 5, Y: 9}}, Health: 100}, + {ID: "3", Body: []rules.Point{{X: 9, Y: 5}, {X: 9, Y: 5}, {X: 9, Y: 5}}, Health: 100}, + {ID: "4", Body: []rules.Point{{X: 1, Y: 5}, {X: 1, Y: 5}, {X: 1, Y: 5}}, Health: 100}, + {ID: "5", Body: []rules.Point{{X: 1, Y: 9}, {X: 1, Y: 9}, {X: 1, Y: 9}}, Health: 100}, + {ID: "6", Body: []rules.Point{{X: 9, Y: 1}, {X: 9, Y: 1}, {X: 9, Y: 1}}, Health: 100}, + {ID: "7", Body: []rules.Point{{X: 9, Y: 9}, {X: 9, Y: 9}, {X: 9, Y: 9}}, Health: 100}, + {ID: "8", Body: []rules.Point{{X: 1, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100}, + }), nil, }, } @@ -174,109 +136,49 @@ func TestStandardMapUpdateBoard(t *testing.T) { rules.NewBoardState(2, 2), rules.NewSettingsWithParams(rules.ParamFoodSpawnChance, "0", rules.ParamMinimumFood, "0"), rules.MinRand, - &rules.BoardState{ - Width: 2, - Height: 2, - Snakes: []rules.Snake{}, - Food: []rules.Point{}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(2, 2), }, { "empty MinimumFood", rules.NewBoardState(2, 2), rules.NewSettingsWithParams(rules.ParamFoodSpawnChance, "0", rules.ParamMinimumFood, "2"), rules.MinRand, - &rules.BoardState{ - Width: 2, - Height: 2, - Snakes: []rules.Snake{}, - Food: []rules.Point{{X: 0, Y: 0}, {X: 0, Y: 1}}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 0}, {X: 0, Y: 1}}), }, { "not empty MinimumFood", - &rules.BoardState{ - Width: 2, - Height: 2, - Snakes: []rules.Snake{}, - Food: []rules.Point{{X: 0, Y: 1}}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 1}}), rules.NewSettingsWithParams(rules.ParamFoodSpawnChance, "0", rules.ParamMinimumFood, "2"), rules.MinRand, - &rules.BoardState{ - Width: 2, - Height: 2, - Snakes: []rules.Snake{}, - Food: []rules.Point{{X: 0, Y: 1}, {X: 0, Y: 0}}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 1}, {X: 0, Y: 0}}), }, { "empty FoodSpawnChance inactive", rules.NewBoardState(2, 2), rules.NewSettingsWithParams(rules.ParamFoodSpawnChance, "50", rules.ParamMinimumFood, "0"), rules.MinRand, - &rules.BoardState{ - Width: 2, - Height: 2, - Snakes: []rules.Snake{}, - Food: []rules.Point{}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(2, 2), }, { "empty FoodSpawnChance active", rules.NewBoardState(2, 2), rules.NewSettingsWithParams(rules.ParamFoodSpawnChance, "50", rules.ParamMinimumFood, "0"), rules.MaxRand, - &rules.BoardState{ - Width: 2, - Height: 2, - Snakes: []rules.Snake{}, - Food: []rules.Point{{X: 0, Y: 1}}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 1}}), }, { "not empty FoodSpawnChance active", - &rules.BoardState{ - Width: 2, - Height: 2, - Snakes: []rules.Snake{}, - Food: []rules.Point{{X: 0, Y: 0}}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 0}}), rules.NewSettingsWithParams(rules.ParamFoodSpawnChance, "50", rules.ParamMinimumFood, "0"), rules.MaxRand, - &rules.BoardState{ - Width: 2, - Height: 2, - Snakes: []rules.Snake{}, - Food: []rules.Point{{X: 0, Y: 0}, {X: 1, Y: 0}}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 0}, {X: 1, Y: 0}}), }, { "not empty FoodSpawnChance no room", - &rules.BoardState{ - Width: 2, - Height: 2, - Snakes: []rules.Snake{}, - Food: []rules.Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 0}, {X: 1, Y: 1}}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 0}, {X: 1, Y: 1}}), rules.NewSettingsWithParams(rules.ParamFoodSpawnChance, "50", rules.ParamMinimumFood, "0"), rules.MaxRand, - &rules.BoardState{ - Width: 2, - Height: 2, - Snakes: []rules.Snake{}, - Food: []rules.Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 0}, {X: 1, Y: 1}}, - Hazards: []rules.Point{}, - }, + rules.NewBoardState(2, 2).WithFood([]rules.Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 0}, {X: 1, Y: 1}}), }, } for _, test := range tests { diff --git a/pipeline_test.go b/pipeline_test.go index ccd1c29..085a3e9 100644 --- a/pipeline_test.go +++ b/pipeline_test.go @@ -21,17 +21,17 @@ func TestPipeline(t *testing.T) { r.RegisterPipelineStage("astage", mockStageFn(false, nil)) p = rules.NewPipelineFromRegistry(r) require.Equal(t, rules.ErrorNoStages, p.Err()) - _, _, err = p.Execute(&rules.BoardState{}, rules.Settings{}, nil) + _, _, err = p.Execute(rules.NewBoardState(0, 0), rules.Settings{}, nil) require.Equal(t, rules.ErrorNoStages, err) // test that an unregistered stage name errors p = rules.NewPipelineFromRegistry(r, "doesntexist") - _, _, err = p.Execute(&rules.BoardState{}, rules.Settings{}, nil) + _, _, err = p.Execute(rules.NewBoardState(0, 0), rules.Settings{}, nil) require.Equal(t, rules.ErrorStageNotFound, p.Err()) require.Equal(t, rules.ErrorStageNotFound, err) // simplest case - one stage - ended, next, err := rules.NewPipelineFromRegistry(r, "astage").Execute(&rules.BoardState{}, rules.Settings{}, nil) + ended, next, err := rules.NewPipelineFromRegistry(r, "astage").Execute(rules.NewBoardState(0, 0), rules.Settings{}, nil) require.NoError(t, err) require.NoError(t, err) require.NotNil(t, next) @@ -39,20 +39,20 @@ func TestPipeline(t *testing.T) { // test that the pipeline short-circuits for a stage that errors r.RegisterPipelineStage("errors", mockStageFn(false, errors.New(""))) - ended, next, err = rules.NewPipelineFromRegistry(r, "errors", "astage").Execute(&rules.BoardState{}, rules.Settings{}, nil) + ended, next, err = rules.NewPipelineFromRegistry(r, "errors", "astage").Execute(rules.NewBoardState(0, 0), rules.Settings{}, nil) require.Error(t, err) require.NotNil(t, next) require.False(t, ended) // test that the pipeline short-circuits for a stage that ends r.RegisterPipelineStage("ends", mockStageFn(true, nil)) - ended, next, err = rules.NewPipelineFromRegistry(r, "ends", "astage").Execute(&rules.BoardState{}, rules.Settings{}, nil) + ended, next, err = rules.NewPipelineFromRegistry(r, "ends", "astage").Execute(rules.NewBoardState(0, 0), rules.Settings{}, nil) require.NoError(t, err) require.NotNil(t, next) require.True(t, ended) // test that the pipeline runs normally for multiple stages - ended, next, err = rules.NewPipelineFromRegistry(r, "astage", "ends").Execute(&rules.BoardState{}, rules.Settings{}, nil) + ended, next, err = rules.NewPipelineFromRegistry(r, "astage", "ends").Execute(rules.NewBoardState(0, 0), rules.Settings{}, nil) require.NoError(t, err) require.NotNil(t, next) require.True(t, ended) diff --git a/royale.go b/royale.go index 75a3a04..88a1fcb 100644 --- a/royale.go +++ b/royale.go @@ -53,7 +53,7 @@ func PopulateHazardsRoyale(b *BoardState, settings Settings, moves []SnakeMove) for x := 0; x < b.Width; x++ { for y := 0; y < b.Height; y++ { if x < minX || x > maxX || y < minY || y > maxY { - b.Hazards = append(b.Hazards, Point{x, y}) + b.Hazards = append(b.Hazards, Point{X: x, Y: y}) } } } diff --git a/royale_test.go b/royale_test.go index da2efb0..c08fe5b 100644 --- a/royale_test.go +++ b/royale_test.go @@ -57,39 +57,39 @@ func TestRoyaleHazards(t *testing.T) { {Width: 3, Height: 3, Turn: 9, ShrinkEveryNTurns: 10, ExpectedHazards: []Point{}}, { Width: 3, Height: 3, Turn: 10, ShrinkEveryNTurns: 10, - ExpectedHazards: []Point{{0, 0}, {0, 1}, {0, 2}}, + ExpectedHazards: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}}, }, { Width: 3, Height: 3, Turn: 11, ShrinkEveryNTurns: 10, - ExpectedHazards: []Point{{0, 0}, {0, 1}, {0, 2}}, + ExpectedHazards: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}}, }, { Width: 3, Height: 3, Turn: 19, ShrinkEveryNTurns: 10, - ExpectedHazards: []Point{{0, 0}, {0, 1}, {0, 2}}, + ExpectedHazards: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}}, }, { Width: 3, Height: 3, Turn: 20, ShrinkEveryNTurns: 10, - ExpectedHazards: []Point{{0, 0}, {0, 1}, {0, 2}, {1, 2}, {2, 2}}, + ExpectedHazards: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}, {X: 1, Y: 2}, {X: 2, Y: 2}}, }, { Width: 3, Height: 3, Turn: 31, ShrinkEveryNTurns: 10, - ExpectedHazards: []Point{{0, 0}, {0, 1}, {0, 2}, {1, 1}, {1, 2}, {2, 1}, {2, 2}}, + ExpectedHazards: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}, {X: 1, Y: 1}, {X: 1, Y: 2}, {X: 2, Y: 1}, {X: 2, Y: 2}}, }, { Width: 3, Height: 3, Turn: 42, ShrinkEveryNTurns: 10, - ExpectedHazards: []Point{{0, 0}, {0, 1}, {0, 2}, {1, 0}, {1, 1}, {1, 2}, {2, 0}, {2, 1}, {2, 2}}, + ExpectedHazards: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}, {X: 1, Y: 0}, {X: 1, Y: 1}, {X: 1, Y: 2}, {X: 2, Y: 0}, {X: 2, Y: 1}, {X: 2, Y: 2}}, }, { Width: 3, Height: 3, Turn: 53, ShrinkEveryNTurns: 10, - ExpectedHazards: []Point{{0, 0}, {0, 1}, {0, 2}, {1, 0}, {1, 1}, {1, 2}, {2, 0}, {2, 1}, {2, 2}}, + ExpectedHazards: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}, {X: 1, Y: 0}, {X: 1, Y: 1}, {X: 1, Y: 2}, {X: 2, Y: 0}, {X: 2, Y: 1}, {X: 2, Y: 2}}, }, { Width: 3, Height: 3, Turn: 64, ShrinkEveryNTurns: 10, - ExpectedHazards: []Point{{0, 0}, {0, 1}, {0, 2}, {1, 0}, {1, 1}, {1, 2}, {2, 0}, {2, 1}, {2, 2}}, + ExpectedHazards: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}, {X: 1, Y: 0}, {X: 1, Y: 1}, {X: 1, Y: 2}, {X: 2, Y: 0}, {X: 2, Y: 1}, {X: 2, Y: 2}}, }, { Width: 3, Height: 3, Turn: 6987, ShrinkEveryNTurns: 10, - ExpectedHazards: []Point{{0, 0}, {0, 1}, {0, 2}, {1, 0}, {1, 1}, {1, 2}, {2, 0}, {2, 1}, {2, 2}}, + ExpectedHazards: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}, {X: 1, Y: 0}, {X: 1, Y: 1}, {X: 1, Y: 2}, {X: 2, Y: 0}, {X: 2, Y: 1}, {X: 2, Y: 2}}, }, } @@ -137,12 +137,12 @@ var royaleCaseHazardsPlaced = gameTestCase{ Snakes: []Snake{ { ID: "one", - Body: []Point{{1, 1}, {1, 2}}, + Body: []Point{{X: 1, Y: 1}, {X: 1, Y: 2}}, Health: 100, }, { ID: "two", - Body: []Point{{3, 4}, {3, 3}}, + Body: []Point{{X: 3, Y: 4}, {X: 3, Y: 3}}, Health: 100, }, { @@ -152,7 +152,7 @@ var royaleCaseHazardsPlaced = gameTestCase{ EliminatedCause: EliminatedByOutOfBounds, }, }, - Food: []Point{{0, 0}, {1, 0}}, + Food: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}}, Hazards: []Point{}, }, []SnakeMove{ @@ -167,12 +167,12 @@ var royaleCaseHazardsPlaced = gameTestCase{ Snakes: []Snake{ { ID: "one", - Body: []Point{{1, 0}, {1, 1}, {1, 1}}, + Body: []Point{{X: 1, Y: 0}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100, }, { ID: "two", - Body: []Point{{3, 5}, {3, 4}}, + Body: []Point{{X: 3, Y: 5}, {X: 3, Y: 4}}, Health: 99, }, { @@ -182,7 +182,7 @@ var royaleCaseHazardsPlaced = gameTestCase{ EliminatedCause: EliminatedByOutOfBounds, }, }, - Food: []Point{{0, 0}}, + Food: []Point{{X: 0, Y: 0}}, Hazards: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 2, Y: 0}, {X: 3, Y: 0}, {X: 4, Y: 0}, {X: 5, Y: 0}, {X: 6, Y: 0}, {X: 7, Y: 0}, {X: 8, Y: 0}, {X: 9, Y: 0}}, }, } diff --git a/solo_test.go b/solo_test.go index a47f02b..599d3a4 100644 --- a/solo_test.go +++ b/solo_test.go @@ -70,11 +70,11 @@ var soloCaseNotOver = gameTestCase{ Snakes: []Snake{ { ID: "one", - Body: []Point{{1, 1}, {1, 2}}, + Body: []Point{{X: 1, Y: 1}, {X: 1, Y: 2}}, Health: 100, }, }, - Food: []Point{{0, 0}, {1, 0}}, + Food: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}}, Hazards: []Point{}, }, []SnakeMove{ @@ -87,11 +87,11 @@ var soloCaseNotOver = gameTestCase{ Snakes: []Snake{ { ID: "one", - Body: []Point{{1, 0}, {1, 1}, {1, 1}}, + Body: []Point{{X: 1, Y: 0}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100, }, }, - Food: []Point{{0, 0}}, + Food: []Point{{X: 0, Y: 0}}, Hazards: []Point{}, }, } diff --git a/standard_test.go b/standard_test.go index 94a8bbe..188e176 100644 --- a/standard_test.go +++ b/standard_test.go @@ -44,16 +44,16 @@ var standardCaseErrNoMoveFound = gameTestCase{ Snakes: []Snake{ { ID: "one", - Body: []Point{{1, 1}, {1, 2}}, + Body: []Point{{X: 1, Y: 1}, {X: 1, Y: 2}}, Health: 100, }, { ID: "two", - Body: []Point{{3, 4}, {3, 3}}, + Body: []Point{{X: 3, Y: 4}, {X: 3, Y: 3}}, Health: 100, }, }, - Food: []Point{{0, 0}, {1, 0}}, + Food: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}}, Hazards: []Point{}, }, []SnakeMove{ @@ -72,7 +72,7 @@ var standardCaseErrZeroLengthSnake = gameTestCase{ Snakes: []Snake{ { ID: "one", - Body: []Point{{1, 1}, {1, 2}}, + Body: []Point{{X: 1, Y: 1}, {X: 1, Y: 2}}, Health: 100, }, { @@ -81,7 +81,7 @@ var standardCaseErrZeroLengthSnake = gameTestCase{ Health: 100, }, }, - Food: []Point{{0, 0}, {1, 0}}, + Food: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}}, Hazards: []Point{}, }, []SnakeMove{ @@ -101,12 +101,12 @@ var standardCaseMoveEatAndGrow = gameTestCase{ Snakes: []Snake{ { ID: "one", - Body: []Point{{1, 1}, {1, 2}}, + Body: []Point{{X: 1, Y: 1}, {X: 1, Y: 2}}, Health: 100, }, { ID: "two", - Body: []Point{{3, 4}, {3, 3}}, + Body: []Point{{X: 3, Y: 4}, {X: 3, Y: 3}}, Health: 100, }, { @@ -116,7 +116,7 @@ var standardCaseMoveEatAndGrow = gameTestCase{ EliminatedCause: EliminatedByOutOfBounds, }, }, - Food: []Point{{0, 0}, {1, 0}}, + Food: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}}, Hazards: []Point{}, }, []SnakeMove{ @@ -131,12 +131,12 @@ var standardCaseMoveEatAndGrow = gameTestCase{ Snakes: []Snake{ { ID: "one", - Body: []Point{{1, 0}, {1, 1}, {1, 1}}, + Body: []Point{{X: 1, Y: 0}, {X: 1, Y: 1}, {X: 1, Y: 1}}, Health: 100, }, { ID: "two", - Body: []Point{{3, 5}, {3, 4}}, + Body: []Point{{X: 3, Y: 5}, {X: 3, Y: 4}}, Health: 99, }, { @@ -146,7 +146,7 @@ var standardCaseMoveEatAndGrow = gameTestCase{ EliminatedCause: EliminatedByOutOfBounds, }, }, - Food: []Point{{0, 0}}, + Food: []Point{{X: 0, Y: 0}}, Hazards: []Point{}, }, } @@ -162,12 +162,12 @@ var standardMoveAndCollideMAD = gameTestCase{ Snakes: []Snake{ { ID: "one", - Body: []Point{{1, 1}, {2, 1}}, + Body: []Point{{X: 1, Y: 1}, {X: 2, Y: 1}}, Health: 99, }, { ID: "two", - Body: []Point{{1, 2}, {2, 2}}, + Body: []Point{{X: 1, Y: 2}, {X: 2, Y: 2}}, Health: 99, }, }, @@ -185,7 +185,7 @@ var standardMoveAndCollideMAD = gameTestCase{ Snakes: []Snake{ { ID: "one", - Body: []Point{{1, 2}, {1, 1}}, + Body: []Point{{X: 1, Y: 2}, {X: 1, Y: 1}}, Health: 98, EliminatedCause: EliminatedByCollision, EliminatedBy: "two", @@ -193,7 +193,7 @@ var standardMoveAndCollideMAD = gameTestCase{ }, { ID: "two", - Body: []Point{{1, 1}, {1, 2}}, + Body: []Point{{X: 1, Y: 1}, {X: 1, Y: 2}}, Health: 98, EliminatedCause: EliminatedByCollision, EliminatedBy: "one", @@ -240,16 +240,16 @@ func TestEatingOnLastMove(t *testing.T) { Snakes: []Snake{ { ID: "one", - Body: []Point{{0, 2}, {0, 1}, {0, 0}}, + Body: []Point{{X: 0, Y: 2}, {X: 0, Y: 1}, {X: 0, Y: 0}}, Health: 1, }, { ID: "two", - Body: []Point{{3, 2}, {3, 3}, {3, 4}}, + Body: []Point{{X: 3, Y: 2}, {X: 3, Y: 3}, {X: 3, Y: 4}}, Health: 1, }, }, - Food: []Point{{0, 3}, {9, 9}}, + Food: []Point{{X: 0, Y: 3}, {X: 9, Y: 9}}, }, []SnakeMove{ {ID: "one", Move: MoveUp}, @@ -262,18 +262,18 @@ func TestEatingOnLastMove(t *testing.T) { Snakes: []Snake{ { ID: "one", - Body: []Point{{0, 3}, {0, 2}, {0, 1}, {0, 1}}, + Body: []Point{{X: 0, Y: 3}, {X: 0, Y: 2}, {X: 0, Y: 1}, {X: 0, Y: 1}}, Health: 100, }, { ID: "two", - Body: []Point{{3, 1}, {3, 2}, {3, 3}}, + Body: []Point{{X: 3, Y: 1}, {X: 3, Y: 2}, {X: 3, Y: 3}}, Health: 0, EliminatedCause: EliminatedByOutOfHealth, EliminatedOnTurn: 1, }, }, - Food: []Point{{9, 9}}, + Food: []Point{{X: 9, Y: 9}}, }, }, } @@ -313,16 +313,16 @@ func TestHeadToHeadOnFood(t *testing.T) { Snakes: []Snake{ { ID: "one", - Body: []Point{{0, 2}, {0, 1}, {0, 0}}, + Body: []Point{{X: 0, Y: 2}, {X: 0, Y: 1}, {X: 0, Y: 0}}, Health: 10, }, { ID: "two", - Body: []Point{{0, 4}, {0, 5}, {0, 6}}, + Body: []Point{{X: 0, Y: 4}, {X: 0, Y: 5}, {X: 0, Y: 6}}, Health: 10, }, }, - Food: []Point{{0, 3}, {9, 9}}, + Food: []Point{{X: 0, Y: 3}, {X: 9, Y: 9}}, }, []SnakeMove{ {ID: "one", Move: MoveUp}, @@ -335,7 +335,7 @@ func TestHeadToHeadOnFood(t *testing.T) { Snakes: []Snake{ { ID: "one", - Body: []Point{{0, 3}, {0, 2}, {0, 1}, {0, 1}}, + Body: []Point{{X: 0, Y: 3}, {X: 0, Y: 2}, {X: 0, Y: 1}, {X: 0, Y: 1}}, Health: 100, EliminatedCause: EliminatedByHeadToHeadCollision, EliminatedBy: "two", @@ -343,14 +343,14 @@ func TestHeadToHeadOnFood(t *testing.T) { }, { ID: "two", - Body: []Point{{0, 3}, {0, 4}, {0, 5}, {0, 5}}, + Body: []Point{{X: 0, Y: 3}, {X: 0, Y: 4}, {X: 0, Y: 5}, {X: 0, Y: 5}}, Health: 100, EliminatedCause: EliminatedByHeadToHeadCollision, EliminatedBy: "one", EliminatedOnTurn: 42, }, }, - Food: []Point{{9, 9}}, + Food: []Point{{X: 9, Y: 9}}, }, }, { @@ -361,16 +361,16 @@ func TestHeadToHeadOnFood(t *testing.T) { Snakes: []Snake{ { ID: "one", - Body: []Point{{0, 2}, {0, 1}, {0, 0}}, + Body: []Point{{X: 0, Y: 2}, {X: 0, Y: 1}, {X: 0, Y: 0}}, Health: 10, }, { ID: "two", - Body: []Point{{0, 4}, {0, 5}, {0, 6}, {0, 7}}, + Body: []Point{{X: 0, Y: 4}, {X: 0, Y: 5}, {X: 0, Y: 6}, {X: 0, Y: 7}}, Health: 10, }, }, - Food: []Point{{0, 3}, {9, 9}}, + Food: []Point{{X: 0, Y: 3}, {X: 9, Y: 9}}, }, []SnakeMove{ {ID: "one", Move: MoveUp}, @@ -383,7 +383,7 @@ func TestHeadToHeadOnFood(t *testing.T) { Snakes: []Snake{ { ID: "one", - Body: []Point{{0, 3}, {0, 2}, {0, 1}, {0, 1}}, + Body: []Point{{X: 0, Y: 3}, {X: 0, Y: 2}, {X: 0, Y: 1}, {X: 0, Y: 1}}, Health: 100, EliminatedCause: EliminatedByHeadToHeadCollision, EliminatedBy: "two", @@ -391,11 +391,11 @@ func TestHeadToHeadOnFood(t *testing.T) { }, { ID: "two", - Body: []Point{{0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 6}}, + Body: []Point{{X: 0, Y: 3}, {X: 0, Y: 4}, {X: 0, Y: 5}, {X: 0, Y: 6}, {X: 0, Y: 6}}, Health: 100, }, }, - Food: []Point{{9, 9}}, + Food: []Point{{X: 9, Y: 9}}, }, }, } @@ -429,22 +429,22 @@ func TestRegressionIssue19(t *testing.T) { Snakes: []Snake{ { ID: "one", - Body: []Point{{0, 2}, {0, 1}, {0, 0}}, + Body: []Point{{X: 0, Y: 2}, {X: 0, Y: 1}, {X: 0, Y: 0}}, Health: 100, }, { ID: "two", - Body: []Point{{0, 5}, {0, 6}, {0, 7}}, + Body: []Point{{X: 0, Y: 5}, {X: 0, Y: 6}, {X: 0, Y: 7}}, Health: 100, }, { ID: "eliminated", - Body: []Point{{0, 0}, {0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}}, + Body: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}, {X: 0, Y: 3}, {X: 0, Y: 4}, {X: 0, Y: 5}, {X: 0, Y: 6}}, Health: 0, EliminatedCause: EliminatedByOutOfHealth, }, }, - Food: []Point{{9, 9}}, + Food: []Point{{X: 9, Y: 9}}, }, []SnakeMove{ {ID: "one", Move: MoveUp}, @@ -457,22 +457,22 @@ func TestRegressionIssue19(t *testing.T) { Snakes: []Snake{ { ID: "one", - Body: []Point{{0, 3}, {0, 2}, {0, 1}}, + Body: []Point{{X: 0, Y: 3}, {X: 0, Y: 2}, {X: 0, Y: 1}}, Health: 99, }, { ID: "two", - Body: []Point{{0, 4}, {0, 5}, {0, 6}}, + Body: []Point{{X: 0, Y: 4}, {X: 0, Y: 5}, {X: 0, Y: 6}}, Health: 99, }, { ID: "eliminated", - Body: []Point{{0, 0}, {0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}}, + Body: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}, {X: 0, Y: 3}, {X: 0, Y: 4}, {X: 0, Y: 5}, {X: 0, Y: 6}}, Health: 0, EliminatedCause: EliminatedByOutOfHealth, }, }, - Food: []Point{{9, 9}}, + Food: []Point{{X: 9, Y: 9}}, }, }, } @@ -497,17 +497,17 @@ func TestMoveSnakes(t *testing.T) { Snakes: []Snake{ { ID: "one", - Body: []Point{{10, 110}, {11, 110}}, + Body: []Point{{X: 10, Y: 110}, {X: 11, Y: 110}}, Health: 111111, }, { ID: "two", - Body: []Point{{23, 220}, {22, 220}, {21, 220}, {20, 220}}, + Body: []Point{{X: 23, Y: 220}, {X: 22, Y: 220}, {X: 21, Y: 220}, {X: 20, Y: 220}}, Health: 222222, }, { ID: "three", - Body: []Point{{0, 0}}, + Body: []Point{{X: 0, Y: 0}}, Health: 1, EliminatedCause: EliminatedByOutOfBounds, }, @@ -523,29 +523,29 @@ func TestMoveSnakes(t *testing.T) { ExpectedThree []Point }{ { - MoveDown, []Point{{10, 109}, {10, 110}}, - MoveUp, []Point{{23, 221}, {23, 220}, {22, 220}, {21, 220}}, - MoveDown, []Point{{0, 0}}, + MoveDown, []Point{{X: 10, Y: 109}, {X: 10, Y: 110}}, + MoveUp, []Point{{X: 23, Y: 221}, {X: 23, Y: 220}, {X: 22, Y: 220}, {X: 21, Y: 220}}, + MoveDown, []Point{{X: 0, Y: 0}}, }, { - MoveRight, []Point{{11, 109}, {10, 109}}, - MoveLeft, []Point{{22, 221}, {23, 221}, {23, 220}, {22, 220}}, - MoveDown, []Point{{0, 0}}, + MoveRight, []Point{{X: 11, Y: 109}, {X: 10, Y: 109}}, + MoveLeft, []Point{{X: 22, Y: 221}, {X: 23, Y: 221}, {X: 23, Y: 220}, {X: 22, Y: 220}}, + MoveDown, []Point{{X: 0, Y: 0}}, }, { - MoveRight, []Point{{12, 109}, {11, 109}}, - MoveLeft, []Point{{21, 221}, {22, 221}, {23, 221}, {23, 220}}, - MoveDown, []Point{{0, 0}}, + MoveRight, []Point{{X: 12, Y: 109}, {X: 11, Y: 109}}, + MoveLeft, []Point{{X: 21, Y: 221}, {X: 22, Y: 221}, {X: 23, Y: 221}, {X: 23, Y: 220}}, + MoveDown, []Point{{X: 0, Y: 0}}, }, { - MoveRight, []Point{{13, 109}, {12, 109}}, - MoveLeft, []Point{{20, 221}, {21, 221}, {22, 221}, {23, 221}}, - MoveDown, []Point{{0, 0}}, + MoveRight, []Point{{X: 13, Y: 109}, {X: 12, Y: 109}}, + MoveLeft, []Point{{X: 20, Y: 221}, {X: 21, Y: 221}, {X: 22, Y: 221}, {X: 23, Y: 221}}, + MoveDown, []Point{{X: 0, Y: 0}}, }, { - MoveDown, []Point{{13, 108}, {13, 109}}, - MoveUp, []Point{{20, 222}, {20, 221}, {21, 221}, {22, 221}}, - MoveDown, []Point{{0, 0}}, + MoveDown, []Point{{X: 13, Y: 108}, {X: 13, Y: 109}}, + MoveUp, []Point{{X: 20, Y: 222}, {X: 20, Y: 221}, {X: 21, Y: 221}, {X: 22, Y: 221}}, + MoveDown, []Point{{X: 0, Y: 0}}, }, } @@ -589,7 +589,7 @@ func TestMoveSnakesWrongID(t *testing.T) { Snakes: []Snake{ { ID: "one", - Body: []Point{{1, 1}}, + Body: []Point{{X: 1, Y: 1}}, }, }, } @@ -610,11 +610,11 @@ func TestMoveSnakesNotEnoughMoves(t *testing.T) { Snakes: []Snake{ { ID: "one", - Body: []Point{{1, 1}}, + Body: []Point{{X: 1, Y: 1}}, }, { ID: "two", - Body: []Point{{2, 2}}, + Body: []Point{{X: 2, Y: 2}}, }, }, } @@ -635,7 +635,7 @@ func TestMoveSnakesExtraMovesIgnored(t *testing.T) { Snakes: []Snake{ { ID: "one", - Body: []Point{{1, 1}}, + Body: []Point{{X: 1, Y: 1}}, }, }, } @@ -653,7 +653,7 @@ func TestMoveSnakesExtraMovesIgnored(t *testing.T) { r := getStandardRuleset(Settings{}) _, err := MoveSnakesStandard(b, r.Settings(), moves) require.NoError(t, err) - require.Equal(t, []Point{{1, 0}}, b.Snakes[0].Body) + require.Equal(t, []Point{{X: 1, Y: 0}}, b.Snakes[0].Body) } func TestMoveSnakesDefault(t *testing.T) { @@ -663,34 +663,34 @@ func TestMoveSnakesDefault(t *testing.T) { Expected []Point }{ { - Body: []Point{{0, 0}}, + Body: []Point{{X: 0, Y: 0}}, Move: "invalid", - Expected: []Point{{0, 1}}, + Expected: []Point{{X: 0, Y: 1}}, }, { - Body: []Point{{5, 5}, {5, 5}}, + Body: []Point{{X: 5, Y: 5}, {X: 5, Y: 5}}, Move: "", - Expected: []Point{{5, 6}, {5, 5}}, + Expected: []Point{{X: 5, Y: 6}, {X: 5, Y: 5}}, }, { - Body: []Point{{5, 5}, {5, 4}}, - Expected: []Point{{5, 6}, {5, 5}}, + Body: []Point{{X: 5, Y: 5}, {X: 5, Y: 4}}, + Expected: []Point{{X: 5, Y: 6}, {X: 5, Y: 5}}, }, { - Body: []Point{{5, 4}, {5, 5}}, - Expected: []Point{{5, 3}, {5, 4}}, + Body: []Point{{X: 5, Y: 4}, {X: 5, Y: 5}}, + Expected: []Point{{X: 5, Y: 3}, {X: 5, Y: 4}}, }, { - Body: []Point{{5, 4}, {5, 5}}, - Expected: []Point{{5, 3}, {5, 4}}, + Body: []Point{{X: 5, Y: 4}, {X: 5, Y: 5}}, + Expected: []Point{{X: 5, Y: 3}, {X: 5, Y: 4}}, }, { - Body: []Point{{4, 5}, {5, 5}}, - Expected: []Point{{3, 5}, {4, 5}}, + Body: []Point{{X: 4, Y: 5}, {X: 5, Y: 5}}, + Expected: []Point{{X: 3, Y: 5}, {X: 4, Y: 5}}, }, { - Body: []Point{{5, 5}, {4, 5}}, - Expected: []Point{{6, 5}, {5, 5}}, + Body: []Point{{X: 5, Y: 5}, {X: 4, Y: 5}}, + Expected: []Point{{X: 6, Y: 5}, {X: 5, Y: 5}}, }, } @@ -725,50 +725,50 @@ func TestGetDefaultMove(t *testing.T) { ExpectedMove: MoveUp, }, { - SnakeBody: []Point{{0, 0}}, + SnakeBody: []Point{{X: 0, Y: 0}}, ExpectedMove: MoveUp, }, { - SnakeBody: []Point{{-1, -1}}, + SnakeBody: []Point{{X: -1, Y: -1}}, ExpectedMove: MoveUp, }, // Stacked (fallback to default) { - SnakeBody: []Point{{2, 2}, {2, 2}}, + SnakeBody: []Point{{X: 2, Y: 2}, {X: 2, Y: 2}}, ExpectedMove: MoveUp, }, // Neck next to head { - SnakeBody: []Point{{2, 2}, {2, 1}}, + SnakeBody: []Point{{X: 2, Y: 2}, {X: 2, Y: 1}}, ExpectedMove: MoveUp, }, { - SnakeBody: []Point{{2, 2}, {2, 3}}, + SnakeBody: []Point{{X: 2, Y: 2}, {X: 2, Y: 3}}, ExpectedMove: MoveDown, }, { - SnakeBody: []Point{{2, 2}, {1, 2}}, + SnakeBody: []Point{{X: 2, Y: 2}, {X: 1, Y: 2}}, ExpectedMove: MoveRight, }, { - SnakeBody: []Point{{2, 2}, {3, 2}}, + SnakeBody: []Point{{X: 2, Y: 2}, {X: 3, Y: 2}}, ExpectedMove: MoveLeft, }, // Board wrap cases { - SnakeBody: []Point{{0, 0}, {0, 2}}, + SnakeBody: []Point{{X: 0, Y: 0}, {X: 0, Y: 2}}, ExpectedMove: MoveUp, }, { - SnakeBody: []Point{{0, 0}, {2, 0}}, + SnakeBody: []Point{{X: 0, Y: 0}, {X: 2, Y: 0}}, ExpectedMove: MoveRight, }, { - SnakeBody: []Point{{0, 2}, {0, 0}}, + SnakeBody: []Point{{X: 0, Y: 2}, {X: 0, Y: 0}}, ExpectedMove: MoveDown, }, { - SnakeBody: []Point{{2, 0}, {0, 0}}, + SnakeBody: []Point{{X: 2, Y: 0}, {X: 0, Y: 0}}, ExpectedMove: MoveLeft, }, } @@ -783,15 +783,15 @@ func TestReduceSnakeHealth(t *testing.T) { b := &BoardState{ Snakes: []Snake{ { - Body: []Point{{0, 0}, {0, 1}}, + Body: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}}, Health: 99, }, { - Body: []Point{{5, 8}, {6, 8}, {7, 8}}, + Body: []Point{{X: 5, Y: 8}, {X: 6, Y: 8}, {X: 7, Y: 8}}, Health: 2, }, { - Body: []Point{{0, 0}, {0, 1}}, + Body: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}}, Health: 50, EliminatedCause: EliminatedByCollision, }, @@ -886,7 +886,7 @@ func TestSnakeIsOutOfBounds(t *testing.T) { s := Snake{Body: []Point{test.Point}} require.Equal(t, test.Expected, snakeIsOutOfBounds(&s, boardWidth, boardHeight), "Head%+v", test.Point) // Test with point as body - s = Snake{Body: []Point{{0, 0}, {0, 0}, test.Point}} + s = Snake{Body: []Point{{X: 0, Y: 0}, {X: 0, Y: 0}, test.Point}} require.Equal(t, test.Expected, snakeIsOutOfBounds(&s, boardWidth, boardHeight), "Body%+v", test.Point) } } @@ -896,26 +896,26 @@ func TestSnakeHasBodyCollidedSelf(t *testing.T) { Body []Point Expected bool }{ - {[]Point{{1, 1}}, false}, + {[]Point{{X: 1, Y: 1}}, false}, // Self stacks should self collide // (we rely on snakes moving before we check self-collision on turn one) - {[]Point{{2, 2}, {2, 2}}, true}, - {[]Point{{3, 3}, {3, 3}, {3, 3}}, true}, - {[]Point{{5, 5}, {5, 5}, {5, 5}, {5, 5}, {5, 5}}, true}, + {[]Point{{X: 2, Y: 2}, {X: 2, Y: 2}}, true}, + {[]Point{{X: 3, Y: 3}, {X: 3, Y: 3}, {X: 3, Y: 3}}, true}, + {[]Point{{X: 5, Y: 5}, {X: 5, Y: 5}, {X: 5, Y: 5}, {X: 5, Y: 5}, {X: 5, Y: 5}}, true}, // Non-collision cases - {[]Point{{0, 0}, {1, 0}, {1, 0}}, false}, - {[]Point{{0, 0}, {1, 0}, {2, 0}}, false}, - {[]Point{{0, 0}, {1, 0}, {2, 0}, {2, 0}, {2, 0}}, false}, - {[]Point{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}}, false}, - {[]Point{{0, 0}, {0, 1}, {0, 2}}, false}, - {[]Point{{0, 0}, {0, 1}, {0, 2}, {0, 2}, {0, 2}}, false}, - {[]Point{{0, 0}, {0, 1}, {0, 2}, {0, 3}, {0, 4}}, false}, + {[]Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 0}}, false}, + {[]Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 2, Y: 0}}, false}, + {[]Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 2, Y: 0}, {X: 2, Y: 0}, {X: 2, Y: 0}}, false}, + {[]Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 2, Y: 0}, {X: 3, Y: 0}, {X: 4, Y: 0}}, false}, + {[]Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}}, false}, + {[]Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}, {X: 0, Y: 2}, {X: 0, Y: 2}}, false}, + {[]Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}, {X: 0, Y: 3}, {X: 0, Y: 4}}, false}, // Collision cases - {[]Point{{0, 0}, {1, 0}, {0, 0}}, true}, - {[]Point{{0, 0}, {0, 0}, {1, 0}}, true}, - {[]Point{{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}}, true}, - {[]Point{{4, 4}, {3, 4}, {3, 3}, {4, 4}, {4, 4}}, true}, - {[]Point{{3, 3}, {3, 4}, {3, 3}, {4, 4}, {4, 5}}, true}, + {[]Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 0, Y: 0}}, true}, + {[]Point{{X: 0, Y: 0}, {X: 0, Y: 0}, {X: 1, Y: 0}}, true}, + {[]Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 1}, {X: 0, Y: 1}, {X: 0, Y: 0}}, true}, + {[]Point{{X: 4, Y: 4}, {X: 3, Y: 4}, {X: 3, Y: 3}, {X: 4, Y: 4}, {X: 4, Y: 4}}, true}, + {[]Point{{X: 3, Y: 3}, {X: 3, Y: 4}, {X: 3, Y: 3}, {X: 4, Y: 4}, {X: 4, Y: 5}}, true}, } for _, test := range tests { @@ -932,38 +932,38 @@ func TestSnakeHasBodyCollidedOther(t *testing.T) { }{ { // Just heads - []Point{{0, 0}}, - []Point{{1, 1}}, + []Point{{X: 0, Y: 0}}, + []Point{{X: 1, Y: 1}}, false, }, { // Head-to-heads are not considered in body collisions - []Point{{0, 0}}, - []Point{{0, 0}}, + []Point{{X: 0, Y: 0}}, + []Point{{X: 0, Y: 0}}, false, }, { // Stacked bodies - []Point{{0, 0}}, - []Point{{0, 0}, {0, 0}}, + []Point{{X: 0, Y: 0}}, + []Point{{X: 0, Y: 0}, {X: 0, Y: 0}}, true, }, { // Separate stacked bodies - []Point{{0, 0}, {0, 0}, {0, 0}}, - []Point{{1, 1}, {1, 1}, {1, 1}}, + []Point{{X: 0, Y: 0}, {X: 0, Y: 0}, {X: 0, Y: 0}}, + []Point{{X: 1, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 1}}, false, }, { // Stacked bodies, separated heads - []Point{{0, 0}, {1, 0}, {1, 0}}, - []Point{{2, 0}, {1, 0}, {1, 0}}, + []Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 0}}, + []Point{{X: 2, Y: 0}, {X: 1, Y: 0}, {X: 1, Y: 0}}, false, }, { // Mid-snake collision - []Point{{1, 1}}, - []Point{{0, 1}, {1, 1}, {2, 1}}, + []Point{{X: 1, Y: 1}}, + []Point{{X: 0, Y: 1}, {X: 1, Y: 1}, {X: 2, Y: 1}}, true, }, } @@ -984,50 +984,50 @@ func TestSnakeHasLostHeadToHead(t *testing.T) { }{ { // Just heads - []Point{{0, 0}}, - []Point{{1, 1}}, + []Point{{X: 0, Y: 0}}, + []Point{{X: 1, Y: 1}}, false, false, }, { // Just heads colliding - []Point{{0, 0}}, - []Point{{0, 0}}, + []Point{{X: 0, Y: 0}}, + []Point{{X: 0, Y: 0}}, true, true, }, { // One snake larger - []Point{{0, 0}, {1, 0}, {2, 0}}, - []Point{{0, 0}}, + []Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 2, Y: 0}}, + []Point{{X: 0, Y: 0}}, false, true, }, { // Other snake equal - []Point{{0, 0}, {1, 0}, {2, 0}}, - []Point{{0, 0}, {0, 1}, {0, 2}}, + []Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 2, Y: 0}}, + []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}}, true, true, }, { // Other snake longer - []Point{{0, 0}, {1, 0}, {2, 0}}, - []Point{{0, 0}, {0, 1}, {0, 2}, {0, 3}}, + []Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 2, Y: 0}}, + []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}, {X: 0, Y: 3}}, true, false, }, { // Body collision - []Point{{0, 1}, {1, 1}, {2, 1}}, - []Point{{0, 0}, {0, 1}, {0, 2}, {0, 3}}, + []Point{{X: 0, Y: 1}, {X: 1, Y: 1}, {X: 2, Y: 1}}, + []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}, {X: 0, Y: 3}}, false, false, }, { // Separate stacked bodies, head collision - []Point{{3, 10}, {2, 10}, {2, 10}}, - []Point{{3, 10}, {4, 10}, {4, 10}}, + []Point{{X: 3, Y: 10}, {X: 2, Y: 10}, {X: 2, Y: 10}}, + []Point{{X: 3, Y: 10}, {X: 4, Y: 10}, {X: 4, Y: 10}}, true, true, }, { // Separate stacked bodies, head collision - []Point{{10, 3}, {10, 2}, {10, 1}, {10, 0}}, - []Point{{10, 3}, {10, 4}, {10, 5}}, + []Point{{X: 10, Y: 3}, {X: 10, Y: 2}, {X: 10, Y: 1}, {X: 10, Y: 0}}, + []Point{{X: 10, Y: 3}, {X: 10, Y: 4}, {X: 10, Y: 5}}, false, true, }, } @@ -1068,7 +1068,7 @@ func TestMaybeEliminateSnakes(t *testing.T) { { "Single Starvation", []Snake{ - {ID: "1", Body: []Point{{1, 1}}}, + {ID: "1", Body: []Point{{X: 1, Y: 1}}}, }, []string{EliminatedByOutOfHealth}, []string{""}, @@ -1077,7 +1077,7 @@ func TestMaybeEliminateSnakes(t *testing.T) { { "Not Eliminated", []Snake{ - {ID: "1", Health: 1, Body: []Point{{1, 1}}}, + {ID: "1", Health: 1, Body: []Point{{X: 1, Y: 1}}}, }, []string{NotEliminated}, []string{""}, @@ -1086,7 +1086,7 @@ func TestMaybeEliminateSnakes(t *testing.T) { { "Out of Bounds", []Snake{ - {ID: "1", Health: 1, Body: []Point{{-1, 1}}}, + {ID: "1", Health: 1, Body: []Point{{X: -1, Y: 1}}}, }, []string{EliminatedByOutOfBounds}, []string{""}, @@ -1095,7 +1095,7 @@ func TestMaybeEliminateSnakes(t *testing.T) { { "Self Collision", []Snake{ - {ID: "1", Health: 1, Body: []Point{{0, 0}, {0, 1}, {0, 0}}}, + {ID: "1", Health: 1, Body: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 0}}}, }, []string{EliminatedBySelfCollision}, []string{"1"}, @@ -1104,8 +1104,8 @@ func TestMaybeEliminateSnakes(t *testing.T) { { "Multiple Separate Deaths", []Snake{ - {ID: "1", Health: 1, Body: []Point{{0, 0}, {0, 1}, {0, 0}}}, - {ID: "2", Health: 1, Body: []Point{{-1, 1}}}, + {ID: "1", Health: 1, Body: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 0}}}, + {ID: "2", Health: 1, Body: []Point{{X: -1, Y: 1}}}, }, []string{ EliminatedBySelfCollision, @@ -1116,8 +1116,8 @@ func TestMaybeEliminateSnakes(t *testing.T) { { "Other Collision", []Snake{ - {ID: "1", Health: 1, Body: []Point{{0, 2}, {0, 3}, {0, 4}}}, - {ID: "2", Health: 1, Body: []Point{{0, 0}, {0, 1}, {0, 2}}}, + {ID: "1", Health: 1, Body: []Point{{X: 0, Y: 2}, {X: 0, Y: 3}, {X: 0, Y: 4}}}, + {ID: "2", Health: 1, Body: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}}}, }, []string{ EliminatedByCollision, @@ -1128,9 +1128,9 @@ func TestMaybeEliminateSnakes(t *testing.T) { { "All Eliminated Head 2 Head", []Snake{ - {ID: "1", Health: 1, Body: []Point{{1, 1}}}, - {ID: "2", Health: 1, Body: []Point{{1, 1}}}, - {ID: "3", Health: 1, Body: []Point{{1, 1}}}, + {ID: "1", Health: 1, Body: []Point{{X: 1, Y: 1}}}, + {ID: "2", Health: 1, Body: []Point{{X: 1, Y: 1}}}, + {ID: "3", Health: 1, Body: []Point{{X: 1, Y: 1}}}, }, []string{ EliminatedByHeadToHeadCollision, @@ -1143,9 +1143,9 @@ func TestMaybeEliminateSnakes(t *testing.T) { { "One Snake wins Head 2 Head", []Snake{ - {ID: "1", Health: 1, Body: []Point{{1, 1}, {0, 1}}}, - {ID: "2", Health: 1, Body: []Point{{1, 1}, {1, 2}, {1, 3}}}, - {ID: "3", Health: 1, Body: []Point{{1, 1}}}, + {ID: "1", Health: 1, Body: []Point{{X: 1, Y: 1}, {X: 0, Y: 1}}}, + {ID: "2", Health: 1, Body: []Point{{X: 1, Y: 1}, {X: 1, Y: 2}, {X: 1, Y: 3}}}, + {ID: "3", Health: 1, Body: []Point{{X: 1, Y: 1}}}, }, []string{ EliminatedByHeadToHeadCollision, @@ -1158,11 +1158,11 @@ func TestMaybeEliminateSnakes(t *testing.T) { { "All Snakes Body Eliminated", []Snake{ - {ID: "1", Health: 1, Body: []Point{{4, 4}, {3, 3}}}, - {ID: "2", Health: 1, Body: []Point{{3, 3}, {2, 2}}}, - {ID: "3", Health: 1, Body: []Point{{2, 2}, {1, 1}}}, - {ID: "4", Health: 1, Body: []Point{{1, 1}, {4, 4}}}, - {ID: "5", Health: 1, Body: []Point{{4, 4}}}, // Body collision takes priority + {ID: "1", Health: 1, Body: []Point{{X: 4, Y: 4}, {X: 3, Y: 3}}}, + {ID: "2", Health: 1, Body: []Point{{X: 3, Y: 3}, {X: 2, Y: 2}}}, + {ID: "3", Health: 1, Body: []Point{{X: 2, Y: 2}, {X: 1, Y: 1}}}, + {ID: "4", Health: 1, Body: []Point{{X: 1, Y: 1}, {X: 4, Y: 4}}}, + {ID: "5", Health: 1, Body: []Point{{X: 4, Y: 4}}}, // Body collision takes priority }, []string{ EliminatedByCollision, @@ -1177,10 +1177,10 @@ func TestMaybeEliminateSnakes(t *testing.T) { { "All Snakes Eliminated Head 2 Head", []Snake{ - {ID: "1", Health: 1, Body: []Point{{4, 4}, {4, 5}}}, - {ID: "2", Health: 1, Body: []Point{{4, 4}, {4, 3}}}, - {ID: "3", Health: 1, Body: []Point{{4, 4}, {5, 4}}}, - {ID: "4", Health: 1, Body: []Point{{4, 4}, {3, 4}}}, + {ID: "1", Health: 1, Body: []Point{{X: 4, Y: 4}, {X: 4, Y: 5}}}, + {ID: "2", Health: 1, Body: []Point{{X: 4, Y: 4}, {X: 4, Y: 3}}}, + {ID: "3", Health: 1, Body: []Point{{X: 4, Y: 4}, {X: 5, Y: 4}}}, + {ID: "4", Health: 1, Body: []Point{{X: 4, Y: 4}, {X: 3, Y: 4}}}, }, []string{ EliminatedByHeadToHeadCollision, @@ -1194,10 +1194,10 @@ func TestMaybeEliminateSnakes(t *testing.T) { { "4 Snakes Head 2 Head", []Snake{ - {ID: "1", Health: 1, Body: []Point{{4, 4}, {4, 5}}}, - {ID: "2", Health: 1, Body: []Point{{4, 4}, {4, 3}}}, - {ID: "3", Health: 1, Body: []Point{{4, 4}, {5, 4}, {6, 4}}}, - {ID: "4", Health: 1, Body: []Point{{4, 4}, {3, 4}}}, + {ID: "1", Health: 1, Body: []Point{{X: 4, Y: 4}, {X: 4, Y: 5}}}, + {ID: "2", Health: 1, Body: []Point{{X: 4, Y: 4}, {X: 4, Y: 3}}}, + {ID: "3", Health: 1, Body: []Point{{X: 4, Y: 4}, {X: 5, Y: 4}, {X: 6, Y: 4}}}, + {ID: "4", Health: 1, Body: []Point{{X: 4, Y: 4}, {X: 3, Y: 4}}}, }, []string{ EliminatedByHeadToHeadCollision, @@ -1235,12 +1235,12 @@ func TestMaybeEliminateSnakesPriority(t *testing.T) { }{ { []Snake{ - {ID: "1", Health: 0, Body: []Point{{-1, 0}, {0, 0}, {1, 0}}}, - {ID: "2", Health: 1, Body: []Point{{-1, 0}, {0, 0}, {1, 0}}}, - {ID: "3", Health: 1, Body: []Point{{1, 0}, {0, 0}, {1, 0}}}, - {ID: "4", Health: 1, Body: []Point{{1, 0}, {1, 1}, {1, 2}}}, - {ID: "5", Health: 1, Body: []Point{{2, 2}, {2, 1}, {2, 0}}}, - {ID: "6", Health: 1, Body: []Point{{2, 2}, {2, 3}, {2, 4}, {2, 5}}}, + {ID: "1", Health: 0, Body: []Point{{X: -1, Y: 0}, {X: 0, Y: 0}, {X: 1, Y: 0}}}, + {ID: "2", Health: 1, Body: []Point{{X: -1, Y: 0}, {X: 0, Y: 0}, {X: 1, Y: 0}}}, + {ID: "3", Health: 1, Body: []Point{{X: 1, Y: 0}, {X: 0, Y: 0}, {X: 1, Y: 0}}}, + {ID: "4", Health: 1, Body: []Point{{X: 1, Y: 0}, {X: 1, Y: 1}, {X: 1, Y: 2}}}, + {ID: "5", Health: 1, Body: []Point{{X: 2, Y: 2}, {X: 2, Y: 1}, {X: 2, Y: 0}}}, + {ID: "6", Health: 1, Body: []Point{{X: 2, Y: 2}, {X: 2, Y: 3}, {X: 2, Y: 4}, {X: 2, Y: 5}}}, }, []string{ EliminatedByOutOfHealth, @@ -1277,50 +1277,50 @@ func TestMaybeDamageHazards(t *testing.T) { }{ {}, { - Snakes: []Snake{{Body: []Point{{0, 0}}}}, + Snakes: []Snake{{Body: []Point{{X: 0, Y: 0}}}}, Hazards: []Point{}, ExpectedEliminatedCauses: []string{NotEliminated}, ExpectedEliminatedByIDs: []string{""}, ExpectedEliminatedOnTurns: []int{0}, }, { - Snakes: []Snake{{Body: []Point{{0, 0}}}}, - Hazards: []Point{{0, 0}}, + Snakes: []Snake{{Body: []Point{{X: 0, Y: 0}}}}, + Hazards: []Point{{X: 0, Y: 0}}, ExpectedEliminatedCauses: []string{EliminatedByHazard}, ExpectedEliminatedByIDs: []string{""}, ExpectedEliminatedOnTurns: []int{42}, }, { - Snakes: []Snake{{Body: []Point{{0, 0}}}}, - Hazards: []Point{{0, 0}}, - Food: []Point{{0, 0}}, + Snakes: []Snake{{Body: []Point{{X: 0, Y: 0}}}}, + Hazards: []Point{{X: 0, Y: 0}}, + Food: []Point{{X: 0, Y: 0}}, ExpectedEliminatedCauses: []string{NotEliminated}, ExpectedEliminatedByIDs: []string{""}, ExpectedEliminatedOnTurns: []int{0}, }, { - Snakes: []Snake{{Body: []Point{{0, 0}, {1, 0}, {2, 0}}}}, - Hazards: []Point{{1, 0}, {2, 0}}, + Snakes: []Snake{{Body: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 2, Y: 0}}}}, + Hazards: []Point{{X: 1, Y: 0}, {X: 2, Y: 0}}, ExpectedEliminatedCauses: []string{NotEliminated}, ExpectedEliminatedByIDs: []string{""}, ExpectedEliminatedOnTurns: []int{0}, }, { Snakes: []Snake{ - {Body: []Point{{0, 0}, {1, 0}, {2, 0}}}, - {Body: []Point{{3, 3}, {3, 4}, {3, 5}, {3, 6}}}, + {Body: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 2, Y: 0}}}, + {Body: []Point{{X: 3, Y: 3}, {X: 3, Y: 4}, {X: 3, Y: 5}, {X: 3, Y: 6}}}, }, - Hazards: []Point{{1, 0}, {2, 0}, {3, 4}, {3, 5}, {3, 6}}, + Hazards: []Point{{X: 1, Y: 0}, {X: 2, Y: 0}, {X: 3, Y: 4}, {X: 3, Y: 5}, {X: 3, Y: 6}}, ExpectedEliminatedCauses: []string{NotEliminated, NotEliminated}, ExpectedEliminatedByIDs: []string{"", ""}, ExpectedEliminatedOnTurns: []int{0, 0}, }, { Snakes: []Snake{ - {Body: []Point{{0, 0}, {1, 0}, {2, 0}}}, - {Body: []Point{{3, 3}, {3, 4}, {3, 5}, {3, 6}}}, + {Body: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 2, Y: 0}}}, + {Body: []Point{{X: 3, Y: 3}, {X: 3, Y: 4}, {X: 3, Y: 5}, {X: 3, Y: 6}}}, }, - Hazards: []Point{{3, 3}}, + Hazards: []Point{{X: 3, Y: 3}}, ExpectedEliminatedCauses: []string{NotEliminated, EliminatedByHazard}, ExpectedEliminatedByIDs: []string{"", ""}, ExpectedEliminatedOnTurns: []int{0, 42}, @@ -1369,9 +1369,9 @@ func TestHazardDamagePerTurn(t *testing.T) { } for _, test := range tests { - b := &BoardState{Snakes: []Snake{{Health: test.Health, Body: []Point{{0, 0}}}}, Hazards: []Point{{0, 0}}} + b := &BoardState{Snakes: []Snake{{Health: test.Health, Body: []Point{{X: 0, Y: 0}}}}, Hazards: []Point{{X: 0, Y: 0}}} if test.Food { - b.Food = []Point{{0, 0}} + b.Food = []Point{{X: 0, Y: 0}} } r := getStandardRuleset(NewSettingsWithParams(ParamHazardDamagePerTurn, fmt.Sprint(test.HazardDamagePerTurn))) @@ -1393,59 +1393,59 @@ func TestMaybeFeedSnakes(t *testing.T) { { Name: "snake not on food", Snakes: []Snake{ - {Health: 5, Body: []Point{{0, 0}, {0, 1}, {0, 2}}}, + {Health: 5, Body: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}}}, }, - Food: []Point{{3, 3}}, + Food: []Point{{X: 3, Y: 3}}, ExpectedSnakes: []Snake{ - {Health: 5, Body: []Point{{0, 0}, {0, 1}, {0, 2}}}, + {Health: 5, Body: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}}}, }, - ExpectedFood: []Point{{3, 3}}, + ExpectedFood: []Point{{X: 3, Y: 3}}, }, { Name: "snake on food", Snakes: []Snake{ - {Health: SnakeMaxHealth - 1, Body: []Point{{2, 1}, {1, 1}, {1, 2}, {2, 2}}}, + {Health: SnakeMaxHealth - 1, Body: []Point{{X: 2, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 2}, {X: 2, Y: 2}}}, }, - Food: []Point{{2, 1}}, + Food: []Point{{X: 2, Y: 1}}, ExpectedSnakes: []Snake{ - {Health: SnakeMaxHealth, Body: []Point{{2, 1}, {1, 1}, {1, 2}, {2, 2}, {2, 2}}}, + {Health: SnakeMaxHealth, Body: []Point{{X: 2, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 2}, {X: 2, Y: 2}, {X: 2, Y: 2}}}, }, ExpectedFood: []Point{}, }, { Name: "food under body", Snakes: []Snake{ - {Body: []Point{{0, 0}, {0, 1}, {0, 2}}}, + {Body: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}}}, }, - Food: []Point{{0, 1}}, + Food: []Point{{X: 0, Y: 1}}, ExpectedSnakes: []Snake{ - {Body: []Point{{0, 0}, {0, 1}, {0, 2}}}, + {Body: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}}}, }, - ExpectedFood: []Point{{0, 1}}, + ExpectedFood: []Point{{X: 0, Y: 1}}, }, { Name: "snake on food but already eliminated", Snakes: []Snake{ - {Body: []Point{{0, 0}, {0, 1}, {0, 2}}, EliminatedCause: "EliminatedByOutOfBounds"}, + {Body: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}}, EliminatedCause: "EliminatedByOutOfBounds"}, }, - Food: []Point{{0, 0}}, + Food: []Point{{X: 0, Y: 0}}, ExpectedSnakes: []Snake{ - {Body: []Point{{0, 0}, {0, 1}, {0, 2}}}, + {Body: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}}}, }, - ExpectedFood: []Point{{0, 0}}, + ExpectedFood: []Point{{X: 0, Y: 0}}, }, { Name: "multiple snakes on same food", Snakes: []Snake{ - {Health: SnakeMaxHealth, Body: []Point{{0, 0}, {0, 1}, {0, 2}}}, - {Health: SnakeMaxHealth - 9, Body: []Point{{0, 0}, {1, 0}, {2, 0}}}, + {Health: SnakeMaxHealth, Body: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}}}, + {Health: SnakeMaxHealth - 9, Body: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 2, Y: 0}}}, }, - Food: []Point{{0, 0}, {4, 4}}, + Food: []Point{{X: 0, Y: 0}, {X: 4, Y: 4}}, ExpectedSnakes: []Snake{ - {Health: SnakeMaxHealth, Body: []Point{{0, 0}, {0, 1}, {0, 2}, {0, 2}}}, - {Health: SnakeMaxHealth, Body: []Point{{0, 0}, {1, 0}, {2, 0}, {2, 0}}}, + {Health: SnakeMaxHealth, Body: []Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: 2}, {X: 0, Y: 2}}}, + {Health: SnakeMaxHealth, Body: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}, {X: 2, Y: 0}, {X: 2, Y: 0}}}, }, - ExpectedFood: []Point{{4, 4}}, + ExpectedFood: []Point{{X: 4, Y: 4}}, }, } @@ -1476,7 +1476,7 @@ func TestMaybeSpawnFoodMinimum(t *testing.T) { {0, []Point{}, 0}, {1, []Point{}, 1}, {9, []Point{}, 9}, - {7, []Point{{4, 5}, {4, 4}, {4, 1}}, 7}, + {7, []Point{{X: 4, Y: 5}, {X: 4, Y: 4}, {X: 4, Y: 1}}, 7}, } for _, test := range tests { @@ -1485,8 +1485,8 @@ func TestMaybeSpawnFoodMinimum(t *testing.T) { Height: 11, Width: 11, Snakes: []Snake{ - {Body: []Point{{1, 0}, {1, 1}}}, - {Body: []Point{{0, 1}, {0, 2}, {0, 3}}}, + {Body: []Point{{X: 1, Y: 0}, {X: 1, Y: 1}}}, + {Body: []Point{{X: 0, Y: 1}, {X: 0, Y: 2}, {X: 0, Y: 3}}}, }, Food: test.Food, } @@ -1503,8 +1503,8 @@ func TestMaybeSpawnFoodZeroChance(t *testing.T) { Height: 11, Width: 11, Snakes: []Snake{ - {Body: []Point{{1, 0}, {1, 1}}}, - {Body: []Point{{0, 1}, {0, 2}, {0, 3}}}, + {Body: []Point{{X: 1, Y: 0}, {X: 1, Y: 1}}}, + {Body: []Point{{X: 0, Y: 1}, {X: 0, Y: 2}, {X: 0, Y: 3}}}, }, Food: []Point{}, } @@ -1521,8 +1521,8 @@ func TestMaybeSpawnFoodHundredChance(t *testing.T) { Height: 11, Width: 11, Snakes: []Snake{ - {Body: []Point{{1, 0}, {1, 1}}}, - {Body: []Point{{0, 1}, {0, 2}, {0, 3}}}, + {Body: []Point{{X: 1, Y: 0}, {X: 1, Y: 1}}}, + {Body: []Point{{X: 0, Y: 1}, {X: 0, Y: 2}, {X: 0, Y: 3}}}, }, Food: []Point{}, } @@ -1542,10 +1542,10 @@ func TestMaybeSpawnFoodHalfChance(t *testing.T) { // Use pre-tested seeds and results {123, []Point{}, 1}, {12345, []Point{}, 0}, - {456, []Point{{4, 4}}, 1}, - {789, []Point{{4, 4}}, 2}, - {511, []Point{{4, 4}}, 1}, - {165, []Point{{4, 4}}, 2}, + {456, []Point{{X: 4, Y: 4}}, 1}, + {789, []Point{{X: 4, Y: 4}}, 2}, + {511, []Point{{X: 4, Y: 4}}, 1}, + {165, []Point{{X: 4, Y: 4}}, 2}, } r := getStandardRuleset(NewSettingsWithParams(ParamFoodSpawnChance, "50")) @@ -1554,8 +1554,8 @@ func TestMaybeSpawnFoodHalfChance(t *testing.T) { Height: 4, Width: 5, Snakes: []Snake{ - {Body: []Point{{1, 0}, {1, 1}}}, - {Body: []Point{{0, 1}, {0, 2}, {0, 3}}}, + {Body: []Point{{X: 1, Y: 0}, {X: 1, Y: 1}}}, + {Body: []Point{{X: 0, Y: 1}, {X: 0, Y: 2}, {X: 0, Y: 3}}}, }, Food: test.Food, } diff --git a/wrapped_test.go b/wrapped_test.go index 9eb7c5a..8eb3b31 100644 --- a/wrapped_test.go +++ b/wrapped_test.go @@ -16,10 +16,10 @@ func TestLeft(t *testing.T) { Width: 11, Height: 11, Snakes: []Snake{ - {ID: "bottomLeft", Health: 10, Body: []Point{{0, 0}}}, - {ID: "bottomRight", Health: 10, Body: []Point{{10, 0}}}, - {ID: "topLeft", Health: 10, Body: []Point{{0, 10}}}, - {ID: "topRight", Health: 10, Body: []Point{{10, 10}}}, + {ID: "bottomLeft", Health: 10, Body: []Point{{X: 0, Y: 0}}}, + {ID: "bottomRight", Health: 10, Body: []Point{{X: 10, Y: 0}}}, + {ID: "topLeft", Health: 10, Body: []Point{{X: 0, Y: 10}}}, + {ID: "topRight", Health: 10, Body: []Point{{X: 10, Y: 10}}}, }, } @@ -38,10 +38,10 @@ func TestLeft(t *testing.T) { require.Equal(t, len(boardState.Snakes), len(nextBoardState.Snakes)) expectedSnakes := []Snake{ - {ID: "bottomLeft", Health: 10, Body: []Point{{10, 0}}}, - {ID: "bottomRight", Health: 10, Body: []Point{{9, 0}}}, - {ID: "topLeft", Health: 10, Body: []Point{{10, 10}}}, - {ID: "topRight", Health: 10, Body: []Point{{9, 10}}}, + {ID: "bottomLeft", Health: 10, Body: []Point{{X: 10, Y: 0}}}, + {ID: "bottomRight", Health: 10, Body: []Point{{X: 9, Y: 0}}}, + {ID: "topLeft", Health: 10, Body: []Point{{X: 10, Y: 10}}}, + {ID: "topRight", Health: 10, Body: []Point{{X: 9, Y: 10}}}, } for i, snake := range nextBoardState.Snakes { require.Equal(t, expectedSnakes[i].ID, snake.ID, snake.ID) @@ -56,10 +56,10 @@ func TestRight(t *testing.T) { Width: 11, Height: 11, Snakes: []Snake{ - {ID: "bottomLeft", Health: 10, Body: []Point{{0, 0}}}, - {ID: "bottomRight", Health: 10, Body: []Point{{10, 0}}}, - {ID: "topLeft", Health: 10, Body: []Point{{0, 10}}}, - {ID: "topRight", Health: 10, Body: []Point{{10, 10}}}, + {ID: "bottomLeft", Health: 10, Body: []Point{{X: 0, Y: 0}}}, + {ID: "bottomRight", Health: 10, Body: []Point{{X: 10, Y: 0}}}, + {ID: "topLeft", Health: 10, Body: []Point{{X: 0, Y: 10}}}, + {ID: "topRight", Health: 10, Body: []Point{{X: 10, Y: 10}}}, }, } @@ -78,10 +78,10 @@ func TestRight(t *testing.T) { require.Equal(t, len(boardState.Snakes), len(nextBoardState.Snakes)) expectedSnakes := []Snake{ - {ID: "bottomLeft", Health: 10, Body: []Point{{1, 0}}}, - {ID: "bottomRight", Health: 10, Body: []Point{{0, 0}}}, - {ID: "topLeft", Health: 10, Body: []Point{{1, 10}}}, - {ID: "topRight", Health: 10, Body: []Point{{0, 10}}}, + {ID: "bottomLeft", Health: 10, Body: []Point{{X: 1, Y: 0}}}, + {ID: "bottomRight", Health: 10, Body: []Point{{X: 0, Y: 0}}}, + {ID: "topLeft", Health: 10, Body: []Point{{X: 1, Y: 10}}}, + {ID: "topRight", Health: 10, Body: []Point{{X: 0, Y: 10}}}, } for i, snake := range nextBoardState.Snakes { require.Equal(t, expectedSnakes[i].ID, snake.ID, snake.ID) @@ -96,10 +96,10 @@ func TestUp(t *testing.T) { Width: 11, Height: 11, Snakes: []Snake{ - {ID: "bottomLeft", Health: 10, Body: []Point{{0, 0}}}, - {ID: "bottomRight", Health: 10, Body: []Point{{10, 0}}}, - {ID: "topLeft", Health: 10, Body: []Point{{0, 10}}}, - {ID: "topRight", Health: 10, Body: []Point{{10, 10}}}, + {ID: "bottomLeft", Health: 10, Body: []Point{{X: 0, Y: 0}}}, + {ID: "bottomRight", Health: 10, Body: []Point{{X: 10, Y: 0}}}, + {ID: "topLeft", Health: 10, Body: []Point{{X: 0, Y: 10}}}, + {ID: "topRight", Health: 10, Body: []Point{{X: 10, Y: 10}}}, }, } @@ -118,10 +118,10 @@ func TestUp(t *testing.T) { require.Equal(t, len(boardState.Snakes), len(nextBoardState.Snakes)) expectedSnakes := []Snake{ - {ID: "bottomLeft", Health: 10, Body: []Point{{0, 1}}}, - {ID: "bottomRight", Health: 10, Body: []Point{{10, 1}}}, - {ID: "topLeft", Health: 10, Body: []Point{{0, 0}}}, - {ID: "topRight", Health: 10, Body: []Point{{10, 0}}}, + {ID: "bottomLeft", Health: 10, Body: []Point{{X: 0, Y: 1}}}, + {ID: "bottomRight", Health: 10, Body: []Point{{X: 10, Y: 1}}}, + {ID: "topLeft", Health: 10, Body: []Point{{X: 0, Y: 0}}}, + {ID: "topRight", Health: 10, Body: []Point{{X: 10, Y: 0}}}, } for i, snake := range nextBoardState.Snakes { require.Equal(t, expectedSnakes[i].ID, snake.ID, snake.ID) @@ -136,10 +136,10 @@ func TestDown(t *testing.T) { Width: 11, Height: 11, Snakes: []Snake{ - {ID: "bottomLeft", Health: 10, Body: []Point{{0, 0}}}, - {ID: "bottomRight", Health: 10, Body: []Point{{10, 0}}}, - {ID: "topLeft", Health: 10, Body: []Point{{0, 10}}}, - {ID: "topRight", Health: 10, Body: []Point{{10, 10}}}, + {ID: "bottomLeft", Health: 10, Body: []Point{{X: 0, Y: 0}}}, + {ID: "bottomRight", Health: 10, Body: []Point{{X: 10, Y: 0}}}, + {ID: "topLeft", Health: 10, Body: []Point{{X: 0, Y: 10}}}, + {ID: "topRight", Health: 10, Body: []Point{{X: 10, Y: 10}}}, }, } @@ -158,10 +158,10 @@ func TestDown(t *testing.T) { require.Equal(t, len(boardState.Snakes), len(nextBoardState.Snakes)) expectedSnakes := []Snake{ - {ID: "bottomLeft", Health: 10, Body: []Point{{0, 10}}}, - {ID: "bottomRight", Health: 10, Body: []Point{{10, 10}}}, - {ID: "topLeft", Health: 10, Body: []Point{{0, 9}}}, - {ID: "topRight", Health: 10, Body: []Point{{10, 9}}}, + {ID: "bottomLeft", Health: 10, Body: []Point{{X: 0, Y: 10}}}, + {ID: "bottomRight", Health: 10, Body: []Point{{X: 10, Y: 10}}}, + {ID: "topLeft", Health: 10, Body: []Point{{X: 0, Y: 9}}}, + {ID: "topRight", Health: 10, Body: []Point{{X: 10, Y: 9}}}, } for i, snake := range nextBoardState.Snakes { require.Equal(t, expectedSnakes[i].ID, snake.ID, snake.ID) @@ -176,14 +176,14 @@ func TestEdgeCrossingCollision(t *testing.T) { Width: 11, Height: 11, Snakes: []Snake{ - {ID: "left", Health: 10, Body: []Point{{0, 5}}}, + {ID: "left", Health: 10, Body: []Point{{X: 0, Y: 5}}}, {ID: "rightEdge", Health: 10, Body: []Point{ - {10, 1}, - {10, 2}, - {10, 3}, - {10, 4}, - {10, 5}, - {10, 6}, + {X: 10, Y: 1}, + {X: 10, Y: 2}, + {X: 10, Y: 3}, + {X: 10, Y: 4}, + {X: 10, Y: 5}, + {X: 10, Y: 6}, }}, }, } @@ -201,14 +201,14 @@ func TestEdgeCrossingCollision(t *testing.T) { require.Equal(t, len(boardState.Snakes), len(nextBoardState.Snakes)) expectedSnakes := []Snake{ - {ID: "left", Health: 0, Body: []Point{{10, 5}}, EliminatedCause: EliminatedByCollision, EliminatedBy: "rightEdge"}, + {ID: "left", Health: 0, Body: []Point{{X: 10, Y: 5}}, EliminatedCause: EliminatedByCollision, EliminatedBy: "rightEdge"}, {ID: "rightEdge", Health: 10, Body: []Point{ - {10, 0}, - {10, 1}, - {10, 2}, - {10, 3}, - {10, 4}, - {10, 5}, + {X: 10, Y: 0}, + {X: 10, Y: 1}, + {X: 10, Y: 2}, + {X: 10, Y: 3}, + {X: 10, Y: 4}, + {X: 10, Y: 5}, }}, } for i, snake := range nextBoardState.Snakes { @@ -224,11 +224,11 @@ func TestEdgeCrossingEating(t *testing.T) { Width: 11, Height: 11, Snakes: []Snake{ - {ID: "left", Health: 10, Body: []Point{{0, 5}, {1, 5}}}, - {ID: "other", Health: 10, Body: []Point{{5, 5}}}, + {ID: "left", Health: 10, Body: []Point{{X: 0, Y: 5}, {X: 1, Y: 5}}}, + {ID: "other", Health: 10, Body: []Point{{X: 5, Y: 5}}}, }, Food: []Point{ - {10, 5}, + {X: 10, Y: 5}, }, } @@ -245,8 +245,8 @@ func TestEdgeCrossingEating(t *testing.T) { require.Equal(t, len(boardState.Snakes), len(nextBoardState.Snakes)) expectedSnakes := []Snake{ - {ID: "left", Health: 100, Body: []Point{{10, 5}, {0, 5}, {0, 5}}}, - {ID: "other", Health: 9, Body: []Point{{4, 5}}}, + {ID: "left", Health: 100, Body: []Point{{X: 10, Y: 5}, {X: 0, Y: 5}, {X: 0, Y: 5}}}, + {ID: "other", Health: 9, Body: []Point{{X: 4, Y: 5}}}, } for i, snake := range nextBoardState.Snakes { require.Equal(t, expectedSnakes[i].ID, snake.ID, snake.ID) @@ -281,12 +281,12 @@ var wrappedCaseMoveAndWrap = gameTestCase{ Snakes: []Snake{ { ID: "one", - Body: []Point{{0, 0}, {1, 0}}, + Body: []Point{{X: 0, Y: 0}, {X: 1, Y: 0}}, Health: 100, }, { ID: "two", - Body: []Point{{3, 4}, {3, 3}}, + Body: []Point{{X: 3, Y: 4}, {X: 3, Y: 3}}, Health: 100, }, { @@ -311,12 +311,12 @@ var wrappedCaseMoveAndWrap = gameTestCase{ Snakes: []Snake{ { ID: "one", - Body: []Point{{9, 0}, {0, 0}}, + Body: []Point{{X: 9, Y: 0}, {X: 0, Y: 0}}, Health: 99, }, { ID: "two", - Body: []Point{{3, 5}, {3, 4}}, + Body: []Point{{X: 3, Y: 5}, {X: 3, Y: 4}}, Health: 99, }, {