Snek v0.2.0 Snek.Board View Source
A struct for representing a board position.
This may be used to keep track of state in a game, each turn of the game producing the next board position.
Link to this section Summary
Types
When spawning, {:ok, board}
if there is space available, {:error, :occupied}
otherwise.
A board position.
Functions
Returns a list of neighboring points adjascent to a point of origin.
Returns the number of snakes on the board who are still alive (not eliminated).
Returns a list of all even points on the board, alternating like a checkerboard.
Returns a list of all points on the board.
Returns true if and only if any of the given points on the board are occupied.
Returns the point at the center of the board.
Returns a list of neighboring points diagonal to a point of origin.
Returns true if and only if this board is empty, otherwise false.
Eliminate this snake if it has moved out of bounds, collided with itself, collided with another snake body, or lost in a head-to-head collision.
Eliminate snakes who have moved out of bounds, collided with themselves, collided with other snake bodies, or lost in a head-to-head collision.
Feed snakes who eat an apple.
Moves a snake on the board according to its move for this turn.
Moves each snake on the board according to their respective moves for this turn.
Returns a new empty board of a given size.
Returns true if and only if the given point on the board is occupied, otherwise false.
Returns true if and only if the given point on the board is occupied by an apple, otherwise false.
Returns true if and only if the given point on the board is occupied by a snake's body part, otherwise false.
Returns a list of all occupied points on the board.
Returns true if and only if this point is outside of the board's boundaries,
in other words the opposite of within_bounds?/2
.
Reduce the health of each snake by one point.
Returns true if and only if snake_a
's head is in collision with any of
snake_b
's body parts, excluding snake_b
's head. Otherwise, returns false.
Returns true if and only if there is a head-to-head collision between
snake_a
and snake_b
and snake_a
's body length is shorter or equal to
snake_b
's body length, thereby causing snake_a
to lose the head-to-head.
Returns true if and only if this snake has some body part outside of the board's boundaries.
Spawns an apple at the specified point on the board.
Spawns an apple in the center of the board.
Spawns an apple at the specified point on the board.
Spawns apples at each of the specified points on the board.
Spawns a snake at the specified point on the board.
Spawns a snake in the center of the board.
Spawns multiple snakes, each at a specified point on the board.
Returns a list of unoccupied neighboring points adjascent to a point of origin.
Returns a list of unoccupied neighboring points diagonal to a point of origin.
Returns a list of all unoccupied points on the board.
Returns true if and only if this point is within the board's boundaries, otherwise false.
Link to this section Types
Specs
spawn_result() :: {:ok, t()} | {:error, :occupied}
When spawning, {:ok, board}
if there is space available, {:error, :occupied}
otherwise.
Specs
t() :: %Snek.Board{ apples: [Snek.Board.Point.t()], size: Snek.Board.Size.t(), snakes: [Snek.Board.Snake.t()] }
A board position.
Link to this section Functions
Specs
adjascent_neighbors(t(), Snek.Board.Point.t()) :: [Snek.Board.Point.t()]
Returns a list of neighboring points adjascent to a point of origin.
This excludes points that are outside of the board's boundaries.
Examples
iex> board = Board.new(Board.Size.small)
iex> board |> Board.adjascent_neighbors(Board.Point.new(1, 1))
[
%Board.Point{x: 1, y: 0},
%Board.Point{x: 1, y: 2},
%Board.Point{x: 2, y: 1},
%Board.Point{x: 0, y: 1}
]
iex> board = Board.new(Board.Size.small)
iex> board |> Board.adjascent_neighbors(Board.Point.new(0, 0))
[
%Board.Point{x: 0, y: 1},
%Board.Point{x: 1, y: 0}
]
iex> board = Board.new(Board.Size.new(3, 3))
iex> board |> Board.adjascent_neighbors(Board.Point.new(2, 2))
[
%Board.Point{x: 2, y: 1},
%Board.Point{x: 1, y: 2}
]
Specs
alive_snakes_remaining(t()) :: non_neg_integer()
Returns the number of snakes on the board who are still alive (not eliminated).
Examples
iex> apple = Board.Point.new(1, 4)
iex> ids_and_heads = [{"snek0", Board.Point.new(1, 1)}, {"snek1", Board.Point.new(1, 5)}]
iex> {:ok, board0} = Board.new(Board.Size.small) |> Board.spawn_apple(apple)
iex> {:ok, board1} = Board.spawn_snakes(board0, ids_and_heads)
iex> board2 = Board.move_snakes(board1, [{"snek0", :south}, {"snek1", :north}])
iex> board3 = Board.maybe_feed_snakes(board2)
iex> board4 = Board.move_snakes(board3, [{"snek0", :south}, {"snek1", :north}])
iex> board5 = Board.maybe_eliminate_snakes(board4)
iex> Board.alive_snakes_remaining(board5)
1
Specs
all_even_points(t()) :: [Snek.Board.Point.t()]
Returns a list of all even points on the board, alternating like a checkerboard.
Examples
iex> Board.new(Board.Size.new(3, 3)) |> Board.all_even_points
[
%Board.Point{x: 0, y: 0},
%Board.Point{x: 0, y: 2},
%Board.Point{x: 1, y: 1},
%Board.Point{x: 2, y: 0},
%Board.Point{x: 2, y: 2}
]
Specs
all_points(t()) :: [Snek.Board.Point.t()]
Returns a list of all points on the board.
Examples
iex> Board.new(Board.Size.new(2, 2)) |> Board.all_points
[
%Board.Point{x: 0, y: 0},
%Board.Point{x: 0, y: 1},
%Board.Point{x: 1, y: 0},
%Board.Point{x: 1, y: 1}
]
Specs
any_points_occupied?(t(), [Snek.Board.Point.t()]) :: boolean()
Returns true if and only if any of the given points on the board are occupied.
A point may be occupied by an apple, or any snake's body part.
Examples
iex> board = Board.new(Board.Size.small)
iex> board |> Board.any_points_occupied?([Board.Point.new(1, 3), Board.Point.new(0, 0)])
false
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_apple(Board.Point.new(1, 3))
iex> board |> Board.any_points_occupied?([Board.Point.new(1, 3), Board.Point.new(0, 0)])
true
Specs
center_point(t()) :: Snek.Board.Point.t()
Returns the point at the center of the board.
If the board width or height are even, the center will be offset because boards are a discrete grid.
Examples
iex> Board.new(Board.Size.new(3, 3)) |> Board.center_point()
%Board.Point{x: 1, y: 1}
iex> Board.new(Board.Size.new(8, 8)) |> Board.center_point()
%Board.Point{x: 3, y: 3}
Specs
diagonal_neighbors(t(), Snek.Board.Point.t()) :: [Snek.Board.Point.t()]
Returns a list of neighboring points diagonal to a point of origin.
This excludes points that are outside of the board's boundaries.
Examples
iex> board = Board.new(Board.Size.small)
iex> board |> Board.diagonal_neighbors(Board.Point.new(1, 1))
[
%Board.Point{x: 0, y: 0},
%Board.Point{x: 2, y: 0},
%Board.Point{x: 2, y: 2},
%Board.Point{x: 0, y: 2}
]
iex> board = Board.new(Board.Size.small)
iex> board |> Board.diagonal_neighbors(Board.Point.new(0, 0))
[%Board.Point{x: 1, y: 1}]
iex> board = Board.new(Board.Size.new(3, 3))
iex> board |> Board.diagonal_neighbors(Board.Point.new(2, 2))
[%Board.Point{x: 1, y: 1}]
Specs
Returns true if and only if this board is empty, otherwise false.
The board is considered empty if it does not contain any snakes or apples.
Examples
iex> Board.new(Board.Size.small) |> Board.empty?
true
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_apple_at_center
iex> Board.empty?(board)
false
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_snake_at_center("mysnek")
iex> Board.empty?(board)
false
maybe_eliminate_snake(board, snake, snakes_by_length_descending)
View Source (since 0.1.0)Specs
maybe_eliminate_snake(t(), Snek.Board.Snake.t(), [Snek.Board.Snake.t()]) :: t()
Eliminate this snake if it has moved out of bounds, collided with itself, collided with another snake body, or lost in a head-to-head collision.
If the snake is already previously eliminated, it will be returned unchanged regardless of any new collisions.
Pass the snakes_by_length_descending
argument as an ordered list of all
snakes such that ambiguous collisions will be tied by snakes which appear
first in the list. For example, if longer snakes should be considered first,
pass a list of all snakes ordered by their respective lengths descending.
Examples
iex> ids_and_heads = [{"snek0", Board.Point.new(1, 1)}, {"snek1", Board.Point.new(1, 3)}]
iex> {:ok, board0} = Board.new(Board.Size.small) |> Board.spawn_snakes(ids_and_heads)
iex> board1 = Board.move_snakes(board0, [{"snek0", :south}, {"snek1", :east}])
iex> board2 = Board.move_snakes(board1, [{"snek0", :south}, {"snek1", :east}])
iex> snek0 = board2.snakes |> Enum.find(&(&1.id == "snek0"))
iex> snek0_eliminated = Board.maybe_eliminate_snake(board2, snek0, board2.snakes)
iex> snek0_eliminated.state
{:eliminated, :collision, "snek1"}
iex> snek0_double_eliminated = Board.maybe_eliminate_snake(board2, snek0_eliminated, board2.snakes)
iex> snek0_double_eliminated == snek0_eliminated
true
iex> start_length = 3
iex> start_health = 1
iex> {:ok, board0} = Board.new(Board.Size.small) |> Board.spawn_snake("snek0", Board.Point.new(1, 1), start_length, start_health)
iex> board1 = Board.reduce_snake_healths(board0)
iex> [snek0 | _] = board1.snakes
iex> snek0_eliminated = Board.maybe_eliminate_snake(board1, snek0, board1.snakes)
iex> snek0_eliminated.state
{:eliminated, :starvation}
Specs
Eliminate snakes who have moved out of bounds, collided with themselves, collided with other snake bodies, or lost in a head-to-head collision.
Eliminations are decided by maybe_eliminate_snake/3
for each snake, giving
priority to longer snakes in in ambiguous collisions.
Examples
iex> apple = Board.Point.new(1, 4)
iex> ids_and_heads = [{"snek0", Board.Point.new(1, 1)}, {"snek1", Board.Point.new(1, 5)}]
iex> {:ok, board0} = Board.new(Board.Size.small) |> Board.spawn_apple(apple)
iex> {:ok, board1} = Board.spawn_snakes(board0, ids_and_heads)
iex> board2 = Board.move_snakes(board1, [{"snek0", :south}, {"snek1", :north}])
iex> board3 = Board.maybe_feed_snakes(board2)
iex> board4 = Board.move_snakes(board3, [{"snek0", :south}, {"snek1", :north}])
iex> board5 = Board.maybe_eliminate_snakes(board4)
iex> board6 = Board.reduce_snake_healths(board5)
iex> snek0 = board6.snakes |> Enum.find(&(&1.id == "snek0"))
iex> snek1 = board6.snakes |> Enum.find(&(&1.id == "snek1"))
iex> snek0.state
{:eliminated, :head_to_head, "snek1"}
iex> snek1.state
:alive
Specs
Feed snakes who eat an apple.
For all apples on the board, if any snake eats it, remove the apple from the board and feed each snake who ate it.
A snake eats an apple if the snake's head is at the same position as the apple, and the snake is alive (not eliminated), and the snake has at least one body part.
Feeding a snake is defined by Snek.Board.Snake.feed/2
.
Returns the modified board state.
Examples
iex> apple = Board.Point.new(1, 4)
iex> ids_and_heads = [{"snek0", Board.Point.new(1, 1)}, {"snek1", Board.Point.new(1, 5)}]
iex> {:ok, board0} = Board.new(Board.Size.small) |> Board.spawn_apple(apple)
iex> {:ok, board1} = Board.spawn_snakes(board0, ids_and_heads)
iex> board2 = Board.move_snakes(board1, [{"snek0", :south}, {"snek1", :north}])
iex> board3 = Board.maybe_feed_snakes(board2)
iex> snek0 = board3.snakes |> Enum.find(&(&1.id == "snek0"))
iex> snek1 = board3.snakes |> Enum.find(&(&1.id == "snek1"))
iex> length(snek0.body)
3
iex> length(snek1.body)
4
iex> apple = Board.Point.new(1, 4)
iex> ids_and_heads = [{"snek0", Board.Point.new(1, 1)}, {"snek1", Board.Point.new(1, 5)}]
iex> {:ok, board0} = Board.new(Board.Size.small) |> Board.spawn_apple(apple)
iex> {:ok, board1} = Board.spawn_snakes(board0, ids_and_heads)
iex> board2 = Board.move_snakes(board1, [{"snek0", :south}, {"snek1", :east}])
iex> board3 = Board.maybe_feed_snakes(board2)
iex> snek0 = board3.snakes |> Enum.find(&(&1.id == "snek0"))
iex> snek1 = board3.snakes |> Enum.find(&(&1.id == "snek1"))
iex> length(snek0.body)
3
iex> length(snek1.body)
3
iex> board3 == board2
true
Moves a snake on the board according to its move for this turn.
A snake moves by slithering by one space per turn, in other words stepping in one direction by adding a new head part and removing a tail part.
If nil
is provided as the move, the snake will by default continue moving in
the last moved direction. If the snake has not yet moved at all since
spawning, it will default to moving :north
.
Returns a board with this snake's move applied.
Examples
iex> board0 = Board.new(Board.Size.small)
iex> {:ok, board1} = Board.spawn_snake(board0, "snek0", Board.Point.new(1, 1))
iex> board2 = Board.move_snake(board1, "snek0", :east)
iex> board2.snakes
[
%Board.Snake{
body: [%Board.Point{x: 2, y: 1}, %Board.Point{x: 1, y: 1}, %Board.Point{x: 1, y: 1}],
state: :alive,
health: 100,
id: "snek0"
}
]
Specs
move_snakes(t(), [{Snek.Board.Snake.id(), Snek.Board.Snake.snake_move() | nil}]) :: t()
move_snakes(t(), [{Snek.Board.Snake.id(), Snek.Board.Snake.snake_move() | nil}]) :: t()
Moves each snake on the board according to their respective moves for this turn.
Snakes move by slithering by one space per turn, in other words stepping in one direction by adding a new head part and removing a tail part.
If nil
is provided as a move, the snake will by default continue moving in
the last moved direction. If the snake has not yet moved at all since
spawning, it will default to moving :north
.
Returns a board with all moves applied.
Examples
iex> board0 = Board.new(Board.Size.small)
iex> {:ok, board1} = Board.spawn_snakes(board0, [{"snek0", Board.Point.new(1, 1)}, {"snek1", Board.Point.new(5, 5)}])
iex> board2 = Board.move_snakes(board1, [{"snek0", :east}, {"snek1", nil}])
iex> board2.snakes
[
%Board.Snake{
body: [%Board.Point{x: 5, y: 4}, %Board.Point{x: 5, y: 5}, %Board.Point{x: 5, y: 5}],
state: :alive,
health: 100,
id: "snek1"
},
%Board.Snake{
body: [%Board.Point{x: 2, y: 1}, %Board.Point{x: 1, y: 1}, %Board.Point{x: 1, y: 1}],
state: :alive,
health: 100,
id: "snek0"
}
]
Specs
new(Snek.Board.Size.t()) :: t()
Returns a new empty board of a given size.
Examples
iex> Board.new(Board.Size.small)
%Board{size: %Board.Size{width: 7, height: 7}, apples: [], snakes: []}
Specs
occupied?(t(), Snek.Board.Point.t()) :: boolean()
Returns true if and only if the given point on the board is occupied, otherwise false.
A point may be occupied by an apple, or any snake's body part.
Examples
iex> Board.new(Board.Size.small) |> Board.occupied?(Board.Point.new(1, 3))
false
iex> point = Board.Point.new(1, 3)
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_apple(point)
iex> Board.occupied?(board, point)
true
iex> point = Board.Point.new(1, 3)
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_snake("mysnek", point)
iex> Board.occupied?(board, point)
true
Specs
occupied_by_apple?(t(), Snek.Board.Point.t()) :: boolean()
Returns true if and only if the given point on the board is occupied by an apple, otherwise false.
Examples
iex> Board.new(Board.Size.small) |> Board.occupied_by_apple?(Board.Point.new(1, 3))
false
iex> point = Board.Point.new(1, 3)
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_apple(point)
iex> Board.occupied_by_apple?(board, point)
true
iex> point = Board.Point.new(1, 3)
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_snake("mysnek", point)
iex> Board.occupied_by_apple?(board, point)
false
Specs
occupied_by_snake?(t(), Snek.Board.Point.t()) :: boolean()
Returns true if and only if the given point on the board is occupied by a snake's body part, otherwise false.
Examples
iex> Board.new(Board.Size.small) |> Board.occupied_by_snake?(Board.Point.new(1, 3))
false
iex> point = Board.Point.new(1, 3)
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_apple(point)
iex> Board.occupied_by_snake?(board, point)
false
iex> point = Board.Point.new(1, 3)
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_snake("mysnek", point)
iex> Board.occupied_by_snake?(board, point)
true
Specs
occupied_points(t()) :: [Snek.Board.Point.t()]
Returns a list of all occupied points on the board.
Examples
iex> apple = Board.Point.new(0, 1)
iex> {:ok, board} = Board.new(Board.Size.new(2, 2)) |> Board.spawn_apple(apple)
iex> Board.occupied_points(board)
[
%Board.Point{x: 0, y: 1}
]
Specs
out_of_bounds?(t(), Snek.Board.Point.t()) :: boolean()
Returns true if and only if this point is outside of the board's boundaries,
in other words the opposite of within_bounds?/2
.
Examples
iex> board = Board.new(Board.Size.new(3, 3))
iex> board |> Board.out_of_bounds?(Board.Point.new(0, 0))
false
iex> board |> Board.out_of_bounds?(Board.Point.new(1, 2))
false
iex> board |> Board.out_of_bounds?(Board.Point.new(-1, 0))
true
iex> board |> Board.out_of_bounds?(Board.Point.new(0, 3))
true
Specs
Reduce the health of each snake by one point.
Does not affect the health of eliminated snakes.
Returns a board with all snake health reductions applied.
Examples
iex> apple = Board.Point.new(1, 4)
iex> ids_and_heads = [{"snek0", Board.Point.new(1, 1)}, {"snek1", Board.Point.new(1, 5)}]
iex> {:ok, board0} = Board.new(Board.Size.small) |> Board.spawn_apple(apple)
iex> {:ok, board1} = Board.spawn_snakes(board0, ids_and_heads)
iex> board2 = Board.move_snakes(board1, [{"snek0", :south}, {"snek1", :north}])
iex> board3 = Board.maybe_feed_snakes(board2)
iex> board4 = Board.move_snakes(board3, [{"snek0", :south}, {"snek1", :north}])
iex> board5 = Board.maybe_eliminate_snakes(board4)
iex> board6 = Board.reduce_snake_healths(board5)
iex> snek0 = board6.snakes |> Enum.find(&(&1.id == "snek0"))
iex> snek1 = board6.snakes |> Enum.find(&(&1.id == "snek1"))
iex> snek0.health # Eliminated before reducing health
100
iex> snek1.health # Not eliminiated
99
Specs
snake_collides_with_other_snake?(Snek.Board.Snake.t(), Snek.Board.Snake.t()) :: boolean()
Returns true if and only if snake_a
's head is in collision with any of
snake_b
's body parts, excluding snake_b
's head. Otherwise, returns false.
The two snake arguments commutative. One snake my collide with another snake's body, and yet the other snake's head may not be in a collision.
As such, head-to-head collisions are not detected this way. For that, use
snake_loses_head_to_head_collision?/2
instead.
Examples
iex> ids_and_heads = [{"snek0", Board.Point.new(1, 1)}, {"snek1", Board.Point.new(1, 3)}]
iex> {:ok, board0} = Board.new(Board.Size.small) |> Board.spawn_snakes(ids_and_heads)
iex> board1 = Board.move_snakes(board0, [{"snek0", :south}, {"snek1", :east}])
iex> board2 = Board.move_snakes(board1, [{"snek0", :south}, {"snek1", :east}])
iex> snek0 = board2.snakes |> Enum.find(&(&1.id == "snek0"))
iex> snek1 = board2.snakes |> Enum.find(&(&1.id == "snek1"))
iex> Board.snake_collides_with_other_snake?(snek0, snek1)
true
iex> Board.snake_collides_with_other_snake?(snek1, snek0)
false
snake_loses_head_to_head_collision?(snake_a, snake_b)
View Source (since 0.1.0)Specs
snake_loses_head_to_head_collision?(Snek.Board.Snake.t(), Snek.Board.Snake.t()) :: boolean()
Returns true if and only if there is a head-to-head collision between
snake_a
and snake_b
and snake_a
's body length is shorter or equal to
snake_b
's body length, thereby causing snake_a
to lose the head-to-head.
Examples
iex> apple = Board.Point.new(1, 4)
iex> ids_and_heads = [{"snek0", Board.Point.new(1, 1)}, {"snek1", Board.Point.new(1, 5)}]
iex> {:ok, board0} = Board.new(Board.Size.small) |> Board.spawn_apple(apple)
iex> {:ok, board1} = Board.spawn_snakes(board0, ids_and_heads)
iex> board2 = Board.move_snakes(board1, [{"snek0", :south}, {"snek1", :north}])
iex> board3 = Board.maybe_feed_snakes(board2)
iex> board4 = Board.move_snakes(board3, [{"snek0", :south}, {"snek1", :north}])
iex> snek0 = board4.snakes |> Enum.find(&(&1.id == "snek0"))
iex> snek1 = board4.snakes |> Enum.find(&(&1.id == "snek1"))
iex> Board.snake_loses_head_to_head_collision?(snek0, snek1)
true
iex> Board.snake_loses_head_to_head_collision?(snek1, snek0)
false
Specs
snake_out_of_bounds?(t(), Snek.Board.Snake.t()) :: boolean()
Returns true if and only if this snake has some body part outside of the board's boundaries.
Examples
iex> {:ok, board} = Board.new(Board.Size.new(3, 3)) |> Board.spawn_snake("mysnek", Board.Point.new(1, 1))
iex> [snake | _] = board.snakes
iex> Board.snake_out_of_bounds?(board, snake)
false
iex> {:ok, board} = Board.new(Board.Size.new(3, 3)) |> Board.spawn_snake("mysnek", Board.Point.new(0, 3))
iex> [snake | _] = board.snakes
iex> Board.snake_out_of_bounds?(board, snake)
true
Specs
spawn_apple(t(), Snek.Board.Point.t()) :: spawn_result()
Spawns an apple at the specified point on the board.
Returns {:ok, board}
if there is space available, returns
{:error, :occupied}
otherwise.
Examples
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_apple(Board.Point.new(1, 1))
iex> board
%Board{
apples: [%Board.Point{x: 1, y: 1}],
size: %Board.Size{height: 7, width: 7},
snakes: []
}
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_apple(Board.Point.new(1, 1))
iex> board |> Board.spawn_apple(Board.Point.new(1, 1))
{:error, :occupied}
Specs
spawn_apple_at_center(t()) :: spawn_result()
Spawns an apple in the center of the board.
Returns {:ok, board}
if there is space available, returns
{:error, :occupied}
otherwise.
Examples
iex> {:ok, board} = Board.new(Board.Size.new(3, 3)) |> Board.spawn_apple_at_center()
iex> board
%Board{
apples: [%Board.Point{x: 1, y: 1}],
size: %Board.Size{height: 3, width: 3},
snakes: []
}
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_apple_at_center()
iex> board |> Board.spawn_apple_at_center()
{:error, :occupied}
Specs
spawn_apple_unchecked(t(), Snek.Board.Point.t()) :: t()
Spawns an apple at the specified point on the board.
Unlike spawn_apple/2
this function will not check whether there is space
available. You are expected to only use this function if you are otherwise
performing that validation yourself. For example, it may be more efficient to
precompute available spaces before spawning many apples.
Returns a board state with the apple added.
Examples
iex> board = Board.new(Board.Size.small) |> Board.spawn_apple_unchecked(Board.Point.new(1, 1))
iex> board
%Board{
apples: [%Board.Point{x: 1, y: 1}],
size: %Board.Size{height: 7, width: 7},
snakes: []
}
Specs
spawn_apples(t(), [Snek.Board.Point.t()]) :: spawn_result()
Spawns apples at each of the specified points on the board.
Returns {:ok, board}
if there is space available, returns
{:error, :occupied}
otherwise.
Examples
iex> points = [Board.Point.new(1, 1), Board.Point.new(1, 2)]
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_apples(points)
iex> board
%Board{
apples: [
%Board.Point{x: 1, y: 1},
%Snek.Board.Point{x: 1, y: 2}
],
size: %Snek.Board.Size{height: 7, width: 7},
snakes: []
}
iex> occupied_point = Board.Point.new(1, 1)
iex> new_points = [occupied_point, Board.Point.new(1, 2)]
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_apple(occupied_point)
iex> Board.spawn_apples(board, new_points)
{:error, :occupied}
spawn_snake(board, id, head, length \\ 3, health \\ 100)
View Source (since 0.1.0)Specs
spawn_snake( t(), any(), Snek.Board.Point.t(), non_neg_integer(), non_neg_integer() ) :: spawn_result()
Spawns a snake at the specified point on the board.
Returns {:ok, board}
if there is space available, returns
{:error, :occupied}
otherwise.
Examples
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_snake("mysnek", Board.Point.new(1, 1))
iex> board.snakes
[
%Board.Snake{
body: [%Board.Point{x: 1, y: 1}, %Board.Point{x: 1, y: 1}, %Board.Point{x: 1, y: 1}],
state: :alive,
health: 100,
id: "mysnek"
}
]
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_snake("mysnek", Board.Point.new(1, 1))
iex> Board.spawn_snake(board, "mysnek", Board.Point.new(1, 1))
{:error, :occupied}
spawn_snake_at_center(board, id, length \\ 3, health \\ 100)
View Source (since 0.1.0)Specs
spawn_snake_at_center(t(), any(), non_neg_integer(), non_neg_integer()) :: spawn_result()
Spawns a snake in the center of the board.
Returns {:ok, board}
if there is space available, returns
{:error, :occupied}
otherwise.
Examples
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_snake_at_center("mysnek")
iex> board.snakes
[
%Board.Snake{
body: [%Board.Point{x: 3, y: 3}, %Board.Point{x: 3, y: 3}, %Board.Point{x: 3, y: 3}],
state: :alive,
health: 100,
id: "mysnek"
}
]
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_snake_at_center("mysnek")
iex> Board.spawn_snake_at_center(board, "mysnek")
{:error, :occupied}
spawn_snakes(board, ids_and_heads, length \\ 3, health \\ 100)
View Source (since 0.1.0)Specs
spawn_snakes( t(), [{Snek.Board.Snake.id(), Snek.Board.Point.t()}], non_neg_integer(), non_neg_integer() ) :: spawn_result()
Spawns multiple snakes, each at a specified point on the board.
Returns {:ok, board}
if there is space available, returns
{:error, :occupied}
otherwise.
Examples
iex> ids_and_heads = [{"snek1", Board.Point.new(1, 1)}, {"snek2", Board.Point.new(5, 5)}]
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_snakes(ids_and_heads)
iex> board.snakes
[
%Board.Snake{
body: [%Board.Point{x: 5, y: 5}, %Board.Point{x: 5, y: 5}, %Board.Point{x: 5, y: 5}],
state: :alive,
health: 100,
id: "snek2"
},
%Board.Snake{
body: [%Board.Point{x: 1, y: 1}, %Board.Point{x: 1, y: 1}, %Board.Point{x: 1, y: 1}],
state: :alive,
health: 100,
id: "snek1"
}
]
iex> ids_and_heads = [{"snek1", Board.Point.new(1, 1)}, {"snek2", Board.Point.new(1, 1)}]
iex> Board.new(Board.Size.small) |> Board.spawn_snakes(ids_and_heads)
{:error, :occupied}
Specs
unoccupied_adjascent_neighbors(t(), Snek.Board.Point.t()) :: [ Snek.Board.Point.t() ]
Returns a list of unoccupied neighboring points adjascent to a point of origin.
This excludes any points occupied by an apple, or any snake's body part.
This excludes points that are outside of the board's boundaries.
Examples
iex> board = Board.new(Board.Size.small)
iex> board |> Board.unoccupied_adjascent_neighbors(Board.Point.new(1, 1))
[
%Board.Point{x: 1, y: 0},
%Board.Point{x: 1, y: 2},
%Board.Point{x: 2, y: 1},
%Board.Point{x: 0, y: 1}
]
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_apple(Board.Point.new(1, 2))
iex> board |> Board.unoccupied_adjascent_neighbors(Board.Point.new(1, 1))
[
%Board.Point{x: 1, y: 0},
%Board.Point{x: 2, y: 1},
%Board.Point{x: 0, y: 1}
]
Specs
unoccupied_diagonal_neighbors(t(), Snek.Board.Point.t()) :: [ Snek.Board.Point.t() ]
Returns a list of unoccupied neighboring points diagonal to a point of origin.
This excludes any points occupied by an apple, or any snake's body part.
This excludes points that are outside of the board's boundaries.
Examples
iex> board = Board.new(Board.Size.small)
iex> board |> Board.unoccupied_diagonal_neighbors(Board.Point.new(1, 1))
[
%Board.Point{x: 0, y: 0},
%Board.Point{x: 2, y: 0},
%Board.Point{x: 2, y: 2},
%Board.Point{x: 0, y: 2}
]
iex> {:ok, board} = Board.new(Board.Size.small) |> Board.spawn_apple(Board.Point.new(0, 0))
iex> board |> Board.unoccupied_diagonal_neighbors(Board.Point.new(1, 1))
[
%Board.Point{x: 2, y: 0},
%Board.Point{x: 2, y: 2},
%Board.Point{x: 0, y: 2}
]
Specs
unoccupied_points(t()) :: [Snek.Board.Point.t()]
Returns a list of all unoccupied points on the board.
Examples
iex> apple = Board.Point.new(0, 1)
iex> {:ok, board} = Board.new(Board.Size.new(2, 2)) |> Board.spawn_apple(apple)
iex> Board.unoccupied_points(board)
[
%Board.Point{x: 0, y: 0},
%Board.Point{x: 1, y: 0},
%Board.Point{x: 1, y: 1}
]
Specs
within_bounds?(t(), Snek.Board.Point.t()) :: boolean()
Returns true if and only if this point is within the board's boundaries, otherwise false.
Examples
iex> board = Board.new(Board.Size.new(3, 3))
iex> board |> Board.within_bounds?(Board.Point.new(0, 0))
true
iex> board |> Board.within_bounds?(Board.Point.new(1, 2))
true
iex> board |> Board.within_bounds?(Board.Point.new(-1, 0))
false
iex> board |> Board.within_bounds?(Board.Point.new(0, 3))
false