Isolate and improve logic to determine default move.
This commit is contained in:
parent
a1ee890dde
commit
020303a8dd
2 changed files with 107 additions and 19 deletions
60
standard.go
60
standard.go
|
|
@ -98,8 +98,20 @@ func (r *StandardRuleset) moveSnakes(b *BoardState, moves []SnakeMove) error {
|
||||||
|
|
||||||
for _, move := range moves {
|
for _, move := range moves {
|
||||||
if move.ID == snake.ID {
|
if move.ID == snake.ID {
|
||||||
var newHead = Point{}
|
appliedMove := move.Move
|
||||||
switch move.Move {
|
switch move.Move {
|
||||||
|
case MoveUp, MoveDown, MoveRight, MoveLeft:
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
appliedMove = r.getDefaultMove(snake.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
newHead := Point{}
|
||||||
|
switch appliedMove {
|
||||||
|
// Guaranteed to be one of these options given the clause above
|
||||||
|
case MoveUp:
|
||||||
|
newHead.X = snake.Body[0].X
|
||||||
|
newHead.Y = snake.Body[0].Y + 1
|
||||||
case MoveDown:
|
case MoveDown:
|
||||||
newHead.X = snake.Body[0].X
|
newHead.X = snake.Body[0].X
|
||||||
newHead.Y = snake.Body[0].Y - 1
|
newHead.Y = snake.Body[0].Y - 1
|
||||||
|
|
@ -109,24 +121,6 @@ func (r *StandardRuleset) moveSnakes(b *BoardState, moves []SnakeMove) error {
|
||||||
case MoveRight:
|
case MoveRight:
|
||||||
newHead.X = snake.Body[0].X + 1
|
newHead.X = snake.Body[0].X + 1
|
||||||
newHead.Y = snake.Body[0].Y
|
newHead.Y = snake.Body[0].Y
|
||||||
case MoveUp:
|
|
||||||
newHead.X = snake.Body[0].X
|
|
||||||
newHead.Y = snake.Body[0].Y + 1
|
|
||||||
default:
|
|
||||||
// Default to UP
|
|
||||||
var dX int32 = 0
|
|
||||||
var dY int32 = 1
|
|
||||||
// If neck is available, use neck to determine last direction
|
|
||||||
if len(snake.Body) >= 2 {
|
|
||||||
dX = snake.Body[0].X - snake.Body[1].X
|
|
||||||
dY = snake.Body[0].Y - snake.Body[1].Y
|
|
||||||
if dX == 0 && dY == 0 {
|
|
||||||
dY = 1 // Move up if no last move was made
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Apply
|
|
||||||
newHead.X = snake.Body[0].X + dX
|
|
||||||
newHead.Y = snake.Body[0].Y + dY
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append new head, pop old tail
|
// Append new head, pop old tail
|
||||||
|
|
@ -137,6 +131,34 @@ func (r *StandardRuleset) moveSnakes(b *BoardState, moves []SnakeMove) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *StandardRuleset) getDefaultMove(snakeBody []Point) string {
|
||||||
|
if len(snakeBody) >= 2 {
|
||||||
|
// Use neck to determine last move made
|
||||||
|
head, neck := snakeBody[0], snakeBody[1]
|
||||||
|
// Situations where neck is next to head
|
||||||
|
if head.X == neck.X+1 {
|
||||||
|
return MoveRight
|
||||||
|
} else if head.X == neck.X-1 {
|
||||||
|
return MoveLeft
|
||||||
|
} else if head.Y == neck.Y+1 {
|
||||||
|
return MoveUp
|
||||||
|
} else if head.Y == neck.Y-1 {
|
||||||
|
return MoveDown
|
||||||
|
}
|
||||||
|
// Consider the wrapped cases using zero axis to anchor
|
||||||
|
if head.X == 0 && neck.X > 0 {
|
||||||
|
return MoveRight
|
||||||
|
} else if neck.X == 0 && head.X > 0 {
|
||||||
|
return MoveLeft
|
||||||
|
} else if head.Y == 0 && neck.Y > 0 {
|
||||||
|
return MoveUp
|
||||||
|
} else if neck.Y == 0 && head.Y > 0 {
|
||||||
|
return MoveDown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MoveUp
|
||||||
|
}
|
||||||
|
|
||||||
func (r *StandardRuleset) reduceSnakeHealth(b *BoardState) error {
|
func (r *StandardRuleset) reduceSnakeHealth(b *BoardState) error {
|
||||||
for i := 0; i < len(b.Snakes); i++ {
|
for i := 0; i < len(b.Snakes); i++ {
|
||||||
if b.Snakes[i].EliminatedCause == NotEliminated {
|
if b.Snakes[i].EliminatedCause == NotEliminated {
|
||||||
|
|
|
||||||
|
|
@ -658,6 +658,72 @@ func TestMoveSnakesDefault(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetDefaultMove(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
SnakeBody []Point
|
||||||
|
ExpectedMove string
|
||||||
|
}{
|
||||||
|
// Default is always up
|
||||||
|
{
|
||||||
|
SnakeBody: []Point{},
|
||||||
|
ExpectedMove: MoveUp,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SnakeBody: []Point{{0, 0}},
|
||||||
|
ExpectedMove: MoveUp,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SnakeBody: []Point{{-1, -1}},
|
||||||
|
ExpectedMove: MoveUp,
|
||||||
|
},
|
||||||
|
// Stacked (fallback to default)
|
||||||
|
{
|
||||||
|
SnakeBody: []Point{{2, 2}, {2, 2}},
|
||||||
|
ExpectedMove: MoveUp,
|
||||||
|
},
|
||||||
|
// Neck next to head
|
||||||
|
{
|
||||||
|
SnakeBody: []Point{{2, 2}, {2, 1}},
|
||||||
|
ExpectedMove: MoveUp,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SnakeBody: []Point{{2, 2}, {2, 3}},
|
||||||
|
ExpectedMove: MoveDown,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SnakeBody: []Point{{2, 2}, {1, 2}},
|
||||||
|
ExpectedMove: MoveRight,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SnakeBody: []Point{{2, 2}, {3, 2}},
|
||||||
|
ExpectedMove: MoveLeft,
|
||||||
|
},
|
||||||
|
// Board wrap cases
|
||||||
|
{
|
||||||
|
SnakeBody: []Point{{0, 0}, {0, 2}},
|
||||||
|
ExpectedMove: MoveUp,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SnakeBody: []Point{{0, 0}, {2, 0}},
|
||||||
|
ExpectedMove: MoveRight,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SnakeBody: []Point{{0, 2}, {0, 0}},
|
||||||
|
ExpectedMove: MoveDown,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SnakeBody: []Point{{2, 0}, {0, 0}},
|
||||||
|
ExpectedMove: MoveLeft,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
r := StandardRuleset{}
|
||||||
|
for _, test := range tests {
|
||||||
|
actualMove := r.getDefaultMove(test.SnakeBody)
|
||||||
|
require.Equal(t, test.ExpectedMove, actualMove)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestReduceSnakeHealth(t *testing.T) {
|
func TestReduceSnakeHealth(t *testing.T) {
|
||||||
b := &BoardState{
|
b := &BoardState{
|
||||||
Snakes: []Snake{
|
Snakes: []Snake{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue