Packages
islands_engine
0.1.21
0.2.65
0.2.64
0.2.63
0.2.62
0.2.61
0.2.60
0.2.59
0.2.58
0.2.56
0.2.55
0.2.54
0.2.53
0.2.52
0.2.51
0.2.50
0.2.49
0.2.48
0.2.47
0.2.46
0.2.45
0.2.44
0.2.43
0.2.42
0.2.41
0.2.40
0.2.39
0.2.38
0.2.37
0.2.36
0.2.35
0.2.34
0.2.33
0.2.32
0.2.31
0.2.30
0.2.29
0.2.28
0.2.27
0.2.25
0.2.24
0.2.23
0.2.22
0.2.21
0.2.20
0.2.19
0.2.18
0.2.17
0.2.16
0.2.15
0.2.13
0.2.12
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.81
0.1.80
0.1.79
0.1.78
0.1.77
0.1.76
0.1.75
0.1.73
0.1.72
0.1.71
0.1.70
0.1.69
0.1.68
0.1.67
0.1.66
0.1.65
0.1.64
0.1.63
0.1.62
0.1.61
0.1.60
0.1.59
0.1.58
0.1.57
0.1.56
0.1.55
0.1.54
0.1.53
0.1.52
0.1.51
0.1.50
0.1.49
0.1.48
0.1.47
0.1.46
0.1.45
0.1.44
0.1.43
0.1.42
0.1.41
0.1.40
0.1.39
0.1.38
0.1.37
0.1.36
0.1.35
0.1.34
0.1.33
0.1.32
0.1.31
0.1.30
0.1.29
0.1.28
0.1.27
0.1.26
0.1.25
0.1.24
0.1.23
0.1.22
0.1.21
0.1.20
0.1.19
0.1.18
0.1.17
0.1.16
0.1.15
0.1.14
0.1.13
0.1.12
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.0
Models the Game of Islands.
Current section
Files
Jump to
Current section
Files
lib/islands/engine/island.ex
defmodule Islands.Engine.Island do
@moduledoc false
use PersistConfig
alias __MODULE__
alias Islands.Engine.{Coord, Offsets}
@enforce_keys [:type, :coords, :hits]
defstruct [:type, :coords, :hits]
@type coords :: MapSet.t(Coord.t())
@type t :: %Island{type: type, coords: coords, hits: coords}
@type type :: :atoll | :dot | :l_shape | :s_shape | :square
@types Application.get_env(@app, :island_types)
@spec new(type, Coord.t()) :: {:ok, t} | {:error, atom}
def new(type, %Coord{} = origin) when type in @types do
with [_ | _] = coords <- type |> Offsets.for() |> coords(origin) do
{:ok, %Island{type: type, coords: MapSet.new(coords), hits: MapSet.new()}}
else
:error -> {:error, :invalid_island_location}
end
end
def new(_type, _origin), do: {:error, :invalid_island_args}
@spec overlaps?(t, t) :: boolean
def overlaps?(%Island{} = island, %Island{} = new_island) do
not MapSet.disjoint?(island.coords, new_island.coords)
end
@spec guess(t, Coord.t()) :: {:hit, t} | :miss
def guess(%Island{} = island, %Coord{} = guess) do
if MapSet.member?(island.coords, guess),
do: {:hit, update_in(island.hits, &MapSet.put(&1, guess))},
else: :miss
end
@spec forested?(t) :: boolean
def forested?(%Island{} = island) do
MapSet.equal?(island.coords, island.hits)
end
## Private functions
@spec coords([tuple], Coord.t()) :: [Coord.t()] | :error
defp coords(offsets, %Coord{row: row, col: col} = _origin) do
Enum.reduce_while(offsets, [], fn {row_offset, col_offset}, coords ->
case Coord.new(row + row_offset, col + col_offset) do
{:ok, coord} -> {:cont, [coord | coords]}
{:error, _reason} -> {:halt, :error}
end
end)
end
end