Packages
islands_grid
0.1.8
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.3
0.1.2
0.1.1
A grid (map of maps) and functions for the Game of Islands.
Current section
Files
Jump to
Current section
Files
lib/islands/grid.ex
# ┌───────────────────────────────────────────────────────────────────────┐
# │ Inspired by the book "Functional Web Development" by Lance Halvorsen. │
# └───────────────────────────────────────────────────────────────────────┘
defmodule Islands.Grid do
use PersistConfig
@book_ref Application.get_env(@app, :book_ref)
@moduledoc """
Creates a `grid` (map of maps) for the _Game of Islands_.
Convenience module for client applications.
Converts a `board` or `guesses` struct to a `grid` (map of maps).
Also converts a `board` or `guesses` struct to a list of maps.
\n##### #{@book_ref}
"""
import Enum, only: [reduce: 3]
alias __MODULE__.Tile
alias IO.ANSI.Plus, as: ANSI
alias Islands.{Board, Coord, Guesses, Island}
@coord_range 1..10
@type t :: %{Coord.row() => %{Coord.col() => atom}}
@type tile_fun :: (atom -> ANSI.ansidata())
@doc """
Returns an "empty" grid.
"""
@spec new :: t
def new do
for row <- @coord_range, into: %{} do
{row, for(col <- @coord_range, into: %{}, do: {col, nil})}
end
end
@doc """
Converts a `board` or `guesses` struct to a `grid` (map of maps).
"""
@spec new(Board.t() | Guesses.t()) :: t
def new(board_or_guesses)
def new(%Board{islands: islands, misses: misses}) do
islands
|> Map.values()
|> reduce(new(), fn %Island{type: type, coords: coords, hits: hits}, grid ->
grid
|> update(coords, type)
|> update(hits, :"#{type}_hit")
end)
|> update(misses, :board_miss)
end
def new(%Guesses{hits: hits, misses: misses}),
do: new() |> update(hits, :hit) |> update(misses, :miss)
@doc """
Converts a `board` or `guesses` struct to a list of maps.
"""
@spec to_maps(Board.t() | Guesses.t(), tile_fun) :: [map]
def to_maps(board_or_guesses, fun \\ &Tile.new/1)
def to_maps(%Board{} = board, fun) when is_function(fun, 1),
do: board |> new() |> do_to_maps(fun)
def to_maps(%Guesses{} = guesses, fun) when is_function(fun, 1),
do: guesses |> new() |> do_to_maps(fun)
## Private functions
@spec update(t, Island.coords(), atom) :: t
defp update(grid, coords, value) do
coords
|> MapSet.to_list()
|> reduce(grid, fn %Coord{row: row, col: col}, grid ->
put_in(grid[row][col], value)
end)
end
@spec do_to_maps(t, tile_fun) :: [map]
defp do_to_maps(%{} = grid, fun) do
for {row_num, row_map} <- grid do
[
{"row", row_num}
| for({col_num, cell_val} <- row_map, do: {col_num, fun.(cell_val)})
]
|> Map.new()
end
end
end