# `Islands.Island`
[🔗](https://github.com/RaymondLoranger/islands_island/blob/main/lib/islands/island.ex#L4)

An island struct and functions for the _Game of Islands_.

The island struct contains the fields:

  - `type`
  - `origin`
  - `coords`
  - `hits`

representing the properties of an island in the _Game of Islands_.

##### Based on the book [Functional Web Development](https://pragprog.com/titles/lhelph/functional-web-development-with-elixir-otp-and-phoenix/) by Lance Halvorsen.

# `coords`

```elixir
@type coords() :: MapSet.t(Islands.Coord.t())
```

A set of squares

# `grid_cell`

```elixir
@type grid_cell() :: &lt;&lt;_::16&gt;&gt;
```

Grid cell e.g. "a1" or "c3"

# `grid_position`

```elixir
@type grid_position() :: %{
  gridColumnStart: Islands.Coord.col(),
  gridRowStart: Islands.Coord.row()
}
```

A map representing a CSS grid position

# `t`

```elixir
@type t() :: %Islands.Island{
  coords: coords(),
  hits: coords(),
  origin: Islands.Coord.t(),
  type: type()
}
```

An island struct for the Game of Islands

# `type`

```elixir
@type type() :: :atoll | :dot | :l_shape | :s_shape | :square
```

Island type

# `forested?`

```elixir
@spec forested?(t()) :: boolean()
```

Checks if all the squares of `island` have been hit.

## Examples

    iex> alias Islands.{Coord, Island}
    iex> dot_origin = Coord.new!(1, 1)
    iex> dot = Island.new!(:dot, dot_origin)
    iex> {:hit, updated_dot} = Island.guess(dot, dot_origin)
    iex> {Island.forested?(dot), Island.forested?(updated_dot)}
    {false, true}

# `grid_position`

```elixir
@spec grid_position(t()) :: grid_position()
```

Converts `island`'s origin into a CSS grid position.

## Examples

    iex> alias Islands.{Coord, Island}
    iex> {:ok, origin} = Coord.new(2, 3)
    iex> {:ok, atoll} = Island.new(:atoll, origin)
    iex> Island.grid_position(atoll)
    %{gridRowStart: 2, gridColumnStart: 3}

# `guess`

```elixir
@spec guess(t(), Islands.Coord.t()) :: {:hit, t()} | :miss
```

Returns `{:hit, updated_island}`, where updated_island is `island`
consequently updated if `guess` was a hit, or `:miss` otherwise.

## Examples

    iex> alias Islands.{Coord, Island}
    iex> square_origin = Coord.new!(1, 1)
    iex> square = Island.new!(:square, square_origin)
    iex> {:hit, updated_square} = Island.guess(square, square_origin)
    iex> updated_square.hits
    MapSet.new([square_origin])

    iex> alias Islands.{Coord, Island}
    iex> s_shape_origin = Coord.new!(1, 1)
    iex> s_shape = Island.new!(:s_shape, s_shape_origin)
    iex> Island.guess(s_shape, s_shape_origin)
    :miss

# `hit_cells`

```elixir
@spec hit_cells(t()) :: [grid_cell()]
```

Returns a list of hit "cells" relative to the `island`'s origin.

## Examples

    iex> alias Islands.{Coord, Island}
    iex> {:ok, origin} = Coord.new(2, 2)
    iex> {:ok, atoll} = Island.new(:atoll, origin)
    iex> {:ok, a1} = Coord.new(2, 2)
    iex> {:ok, b1} = Coord.new(2, 3)
    iex> {:ok, a3} = Coord.new(4, 2)
    iex> {:hit, atoll} = Island.guess(atoll, a1)
    iex> {:hit, atoll} = Island.guess(atoll, b1)
    iex> {:hit, atoll} = Island.guess(atoll, a3)
    iex> Island.hit_cells(atoll) |> Enum.sort()
    ["a1", "a3", "b1"]

# `new`

```elixir
@spec new(type(), Islands.Coord.t()) :: {:ok, t()} | {:error, atom()}
```

Returns `{:ok, island}` or `{:error, reason}` if given an invalid `type` or
`origin`.

## Examples

    iex> alias Islands.{Coord, Island}
    iex> {:ok, origin} = Coord.new(1, 1)
    iex> {:ok, island} = Island.new(:dot, origin)
    iex> %Island{origin: ^origin, coords: coords, hits: hits} = island
    iex> {coords, hits}
    {MapSet.new([origin]), MapSet.new()}

    iex> alias Islands.{Coord, Island}
    iex> {:ok, origin} = Coord.new(10, 9)
    iex> Island.new(:square, origin)
    {:error, :invalid_island_location}

    iex> alias Islands.{Coord, Island}
    iex> {:ok, origin} = Coord.new(1, 1)
    iex> Island.new(DOT, origin)
    iex> {:error, :invalid_island_args}

# `new!`

```elixir
@spec new!(type(), Islands.Coord.t()) :: t()
```

Returns an island struct or raises if given an invalid `type` or `origin`.

## Examples

    iex> alias Islands.{Coord, Island}
    iex> origin = Coord.new!(1, 1)
    iex> %Island{coords: coords, hits: hits} = Island.new!(:dot, origin)
    iex> {coords, hits}
    {MapSet.new([origin]), MapSet.new()}

    iex> alias Islands.{Coord, Island}
    iex> origin = Coord.new!(10, 9)
    iex> Island.new!(:square, origin)
    ** (ArgumentError) cannot create island, reason: :invalid_island_location

    iex> alias Islands.Island
    iex> origin = %{row: 10, col: 9}
    iex> Island.new!(:square, origin)
    ** (ArgumentError) cannot create island, reason: :invalid_island_args

# `overlaps?`

```elixir
@spec overlaps?(t(), t()) :: boolean()
```

Checks if `new_island` overlaps `island`.

## Examples

    iex> alias Islands.{Coord, Island}
    iex> square_origin = Coord.new!(1, 1)
    iex> atoll_origin = Coord.new!(2, 2)
    iex> square = Island.new!(:square, square_origin)
    iex> atoll = Island.new!(:atoll, atoll_origin)
    iex> Island.overlaps?(atoll, square)
    true

    iex> alias Islands.{Coord, Island}
    iex> square_origin = Coord.new!(1, 1)
    iex> atoll_origin = Coord.new!(3, 3)
    iex> square = Island.new!(:square, square_origin)
    iex> atoll = Island.new!(:atoll, atoll_origin)
    iex> Island.overlaps?(atoll, square)
    false

---

*Consult [api-reference.md](api-reference.md) for complete listing*
