Skip to content

Commit

Permalink
Isolate and improve logic to determine default move.
Browse files Browse the repository at this point in the history
  • Loading branch information
bvanvugt committed Jan 11, 2022
1 parent a1ee890 commit 020303a
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 19 deletions.
60 changes: 41 additions & 19 deletions standard.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,20 @@ func (r *StandardRuleset) moveSnakes(b *BoardState, moves []SnakeMove) error {

for _, move := range moves {
if move.ID == snake.ID {
var newHead = Point{}
appliedMove := 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:
newHead.X = snake.Body[0].X
newHead.Y = snake.Body[0].Y - 1
Expand All @@ -109,24 +121,6 @@ func (r *StandardRuleset) moveSnakes(b *BoardState, moves []SnakeMove) error {
case MoveRight:
newHead.X = snake.Body[0].X + 1
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
Expand All @@ -137,6 +131,34 @@ func (r *StandardRuleset) moveSnakes(b *BoardState, moves []SnakeMove) error {
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 {
for i := 0; i < len(b.Snakes); i++ {
if b.Snakes[i].EliminatedCause == NotEliminated {
Expand Down
66 changes: 66 additions & 0 deletions standard_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
b := &BoardState{
Snakes: []Snake{
Expand Down

0 comments on commit 020303a

Please sign in to comment.