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.

t()

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

Link to this function

adjascent_neighbors(board, origin)

View Source (since 0.1.0)

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}
]
Link to this function

alive_snakes_remaining(board)

View Source (since 0.1.0)

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
Link to this function

all_even_points(board)

View Source (since 0.1.0)

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}
]
Link to this function

all_points(board)

View Source (since 0.1.0)

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}
]
Link to this function

any_points_occupied?(board, points)

View Source (since 0.1.0)

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
Link to this function

center_point(board)

View Source (since 0.1.0)

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}
Link to this function

diagonal_neighbors(board, origin)

View Source (since 0.1.0)

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}]
Link to this function

empty?(board)

View Source (since 0.1.0)

Specs

empty?(t()) :: boolean()

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
Link to this function

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}
Link to this function

maybe_eliminate_snakes(board)

View Source (since 0.1.0)

Specs

maybe_eliminate_snakes(t()) :: t()

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
Link to this function

maybe_feed_snakes(board)

View Source (since 0.1.0)

Specs

maybe_feed_snakes(t()) :: t()

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
Link to this function

move_snake(board, snake_id, direction)

View Source (since 0.1.0)

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"
  }
]
Link to this function

move_snakes(board, snake_moves)

View Source (since 0.1.0)

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: []}
Link to this function

occupied?(board, point)

View Source (since 0.1.0)

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
Link to this function

occupied_by_apple?(board, point)

View Source (since 0.1.0)

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
Link to this function

occupied_by_snake?(board, point)

View Source (since 0.1.0)

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
Link to this function

occupied_points(board)

View Source (since 0.1.0)

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}
]
Link to this function

out_of_bounds?(board, point)

View Source (since 0.1.0)

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
Link to this function

reduce_snake_healths(board)

View Source (since 0.1.0)

Specs

reduce_snake_healths(t()) :: t()

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
Link to this function

snake_collides_with_other_snake?(snake_a, snake_b)

View Source (since 0.1.0)

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
Link to this function

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
Link to this function

snake_out_of_bounds?(board, snake)

View Source (since 0.1.0)

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
Link to this function

spawn_apple(board, point)

View Source (since 0.1.0)

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}
Link to this function

spawn_apple_at_center(board)

View Source (since 0.1.0)

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}
Link to this function

spawn_apple_unchecked(board, point)

View Source (since 0.1.0)

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: []
}
Link to this function

spawn_apples(board, points)

View Source (since 0.1.0)

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}
Link to this function

spawn_snake(board, id, head, length \\ 3, health \\ 100)

View Source (since 0.1.0)

Specs

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}
Link to this function

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}
Link to this function

spawn_snakes(board, ids_and_heads, length \\ 3, health \\ 100)

View Source (since 0.1.0)

Specs

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}
Link to this function

unoccupied_adjascent_neighbors(board, origin)

View Source (since 0.1.0)

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}
]
Link to this function

unoccupied_diagonal_neighbors(board, origin)

View Source (since 0.1.0)

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}
]
Link to this function

unoccupied_points(board)

View Source (since 0.1.0)

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}
]
Link to this function

within_bounds?(board, point)

View Source (since 0.1.0)

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