Snek v0.4.0 Snek.Board.Snake View Source
Represents a snake on a board.
You may also refer to it as a "snake on a plane", as the joke goes in the Battlesnake community. 😎
Link to this section Summary
Types
A unique ID to differentiate between snakes on a board
A valid direction for a snake to move according to the game rules.
Whether a snake is currently alive, or has been eliminated.
A snake on a board.
Functions
Returns true if and only if the snake is alive (not eliminated).
Returns true if and only if the snake is eliminated.
Feed a snake and grow its tail.
Grow a snake's tail.
Returns the head of a snake.
Decrements the snake's health by 1 point.
Moves the snake one space in a given direction.
Returns the point that is one step toward a given direction from this snake's perspective.
Link to this section Types
Specs
id() :: any()
A unique ID to differentiate between snakes on a board
Specs
snake_move() :: :north | :south | :east | :west | :forward | :backward | :left | :right
A valid direction for a snake to move according to the game rules.
Specs
state() :: :alive | {:eliminated, :starvation} | {:eliminated, :out_of_bounds} | {:eliminated, :self_collision} | {:eliminated, :collision, id()} | {:eliminated, :head_to_head, id()}
Whether a snake is currently alive, or has been eliminated.
If eliminated, the reason is encoded. If the elimination was caused by an opponent, the opponent's snake ID is also specified.
Specs
t() :: %Snek.Board.Snake{ body: [Snek.Board.Point.t()], health: non_neg_integer(), id: any(), state: state() }
A snake on a board.
Link to this section Functions
Specs
Returns true if and only if the snake is alive (not eliminated).
This does not check whether the snake's elimination status should be changed, it is just a helper to check current state.
Examples
iex> body = [Snek.Board.Point.new(1, 0), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 2)]
iex> Snake.alive?(%Snake{id: "mysnek", state: :alive, health: 98, body: body})
true
iex> body = [Snek.Board.Point.new(1, 0), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 2)]
iex> Snake.alive?(%Snake{id: "mysnek", state: {:eliminated, :starvation}, health: 0, body: body})
false
Specs
Returns true if and only if the snake is eliminated.
This does not check whether the snake's elimination status should be changed, it is just a helper to check current state.
Examples
iex> body = [Snek.Board.Point.new(1, 0), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 2)]
iex> Snake.eliminated?(%Snake{id: "mysnek", state: :alive, health: 98, body: body})
false
iex> body = [Snek.Board.Point.new(1, 0), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 2)]
iex> Snake.eliminated?(%Snake{id: "mysnek", state: {:eliminated, :starvation}, health: 0, body: body})
true
Specs
feed(t(), non_neg_integer()) :: t()
Feed a snake and grow its tail.
A snake is fed by restoring its health to a given value, and adding a part to its tail. The new tail part is added in the same position as the current tail (the last body part). Tail body parts may overlap until the snake moves.
Returns the modified snake.
Examples
iex> body = [Snek.Board.Point.new(1, 0), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 2)]
iex> snake = %Snake{id: "mysnek", state: :alive, health: 98, body: body}
iex> Snake.feed(snake, 100)
%Snake{
id: "mysnek",
state: :alive,
health: 100,
body: [
Snek.Board.Point.new(1, 0),
Snek.Board.Point.new(1, 1),
Snek.Board.Point.new(1, 2),
Snek.Board.Point.new(1, 2)
]
}
Specs
Grow a snake's tail.
Adds a part to the snake's tail. The new tail part is added in the same position as the current tail (the last body part). Tail body parts may overlap until the snake moves.
This is equivelent to the tail growth in feed/2
but without affecting the
snake's health.
Returns the modified snake.
Examples
iex> body = [Snek.Board.Point.new(1, 0), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 2)]
iex> snake = %Snake{id: "mysnek", state: :alive, health: 98, body: body}
iex> Snake.grow(snake)
%Snake{
id: "mysnek",
state: :alive,
health: 98,
body: [
Snek.Board.Point.new(1, 0),
Snek.Board.Point.new(1, 1),
Snek.Board.Point.new(1, 2),
Snek.Board.Point.new(1, 2)
]
}
iex> snake = %Snake{id: "mysnek", state: :alive, health: 100, body: []}
iex> snake == Snake.grow(snake)
true
Specs
head(t()) :: Snek.Board.Point.t() | nil
Returns the head of a snake.
If the snake has at least one body part, the first body part (the head) is
returned. Otherwise, nil
is returned.
Examples
iex> body = [Snek.Board.Point.new(1, 2), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1)]
iex> snake = %Snake{id: "mysnek", state: :alive, health: 100, body: body}
iex> Snake.head(snake)
%Snek.Board.Point{x: 1, y: 2}
iex> snake = %Snake{id: "mysnek", state: :alive, health: 100, body: []}
iex> Snake.head(snake)
nil
Specs
Decrements the snake's health by 1 point.
Returns the modified snake.
Examples
iex> body = List.duplicate(Snek.Board.Point.new(1, 1), 3)
iex> snake = %Snake{id: "mysnek", state: :alive, health: 100, body: body}
iex> Snake.hurt(snake).health
99
Specs
move(t(), snake_move() | nil) :: t()
Moves the snake one space in a given direction.
Moving consists of adding a body part to the head of the snake in the given direction, and also removing the tail body part. The snake's body length remains unchanged.
If the snake is already eliminated or the snake does not have any body parts, no move will be applied and the snake will remain unchanged.
If the direction given is :left
, :right
, :forward
or :backward
, then
the snake is moved in that direction relative to the snake's last moved
direction.
If the direction given is nil
, or not a valid direction in which to move,
the snake will be moved in the :forward
direction. If the snake does not
have both head and neck body parts, or the head and neck are at teh same
position, the snake will default to moving :north
instead, as in that case
the last moved direction cannot be extrapolated.
If the snake is already eliminated it will not be moved.
Returns the modified snake.
Examples
iex> body = [Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1)]
iex> snake = %Snake{id: "mysnek", state: :alive, health: 100, body: body}
iex> Snake.move(snake, :north)
%Snake{
id: "mysnek",
state: :alive,
health: 100,
body: [Snek.Board.Point.new(1, 0), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1)]
}
iex> body = [Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1)]
iex> snake = %Snake{id: "mysnek", state: {:eliminated, :starvation}, health: 0, body: body}
iex> snake == Snake.move(snake, :north)
true
iex> snake = %Snake{id: "mysnek", state: :alive, health: 100, body: []}
iex> snake == Snake.move(snake, :north)
true
iex> body = [Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1)]
iex> snake = %Snake{id: "mysnek", state: :alive, health: 100, body: body}
iex> snake |> Snake.move(:east) |> Snake.move(nil)
%Snake{
id: "mysnek",
state: :alive,
health: 100,
body: [Snek.Board.Point.new(3, 1), Snek.Board.Point.new(2, 1), Snek.Board.Point.new(1, 1)]
}
iex> body = [Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1)]
iex> snake = %Snake{id: "mysnek", state: :alive, health: 100, body: body}
iex> snake |> Snake.move(:east) |> Snake.move(:left) |> Snake.move(:right)
%Snake{
id: "mysnek",
state: :alive,
health: 100,
body: [Snek.Board.Point.new(3, 0), Snek.Board.Point.new(2, 0), Snek.Board.Point.new(2, 1)]
}
Specs
step(t(), Snek.Board.Point.direction() | snake_move()) :: Snek.Board.Point.t()
Returns the point that is one step toward a given direction from this snake's perspective.
If the snake has no body parts, nil
is returned instead of a point.
If the direction given is :left
, :right
, :forward
, or :backward
then
the point returned will be in that direction relative to the snake's last
moved direction. If the snake does not have both head and neck body parts, or
the head and neck are at the same position, then nil
will be returned
instead of a point, as in that case the last moved direction cannot be
extrapolated.
Examples
iex> body = [Snek.Board.Point.new(2, 1), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1)]
iex> snake = %Snake{id: "snek0", state: :alive, health: 99, body: body}
iex> Snake.step(snake, :north)
%Snek.Board.Point{x: 2, y: 0}
iex> body = [Snek.Board.Point.new(2, 1), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1)]
iex> snake = %Snake{id: "snek0", state: :alive, health: 99, body: body}
iex> Snake.step(snake, :left)
%Snek.Board.Point{x: 2, y: 0}
iex> body = [Snek.Board.Point.new(2, 1), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1)]
iex> snake = %Snake{id: "snek0", state: :alive, health: 99, body: body}
iex> Snake.step(snake, :east)
%Snek.Board.Point{x: 3, y: 1}
iex> body = [Snek.Board.Point.new(2, 1), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1)]
iex> snake = %Snake{id: "snek0", state: :alive, health: 99, body: body}
iex> Snake.step(snake, :forward)
%Snek.Board.Point{x: 3, y: 1}
iex> body = [Snek.Board.Point.new(2, 1), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1)]
iex> snake = %Snake{id: "snek0", state: :alive, health: 99, body: body}
iex> Snake.step(snake, :right)
%Snek.Board.Point{x: 2, y: 2}
iex> body = [Snek.Board.Point.new(2, 1), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1)]
iex> snake = %Snake{id: "snek0", state: :alive, health: 99, body: body}
iex> Snake.step(snake, :south)
%Snek.Board.Point{x: 2, y: 2}
iex> body = [Snek.Board.Point.new(2, 1), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1)]
iex> snake = %Snake{id: "snek0", state: :alive, health: 99, body: body}
iex> Snake.step(snake, :backward)
%Snek.Board.Point{x: 1, y: 1}
iex> body = [Snek.Board.Point.new(2, 1), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1)]
iex> snake = %Snake{id: "snek0", state: :alive, health: 99, body: body}
iex> Snake.step(snake, :west)
%Snek.Board.Point{x: 1, y: 1}
iex> snake = %Snake{id: "snek0", state: :alive, health: 0, body: []}
iex> Snake.step(snake, :south)
nil
iex> body = [Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1), Snek.Board.Point.new(1, 1)]
iex> snake = %Snake{id: "snek0", state: :alive, health: 100, body: body}
iex> Snake.step(snake, :forward)
nil