defmodule Perudex.Hand do
@moduledoc """
Provides functions to manipulate a hand of dice in Perudex.
"""
alias __MODULE__
defstruct [:dice, :remaining_dice, has_palificoed: false]
@type t :: %Hand{dice: [die], remaining_dice: integer(), has_palificoed: boolean()}
@type die :: 1..6
@doc """
Initialize a new hand for a player given his allowed dice holding count.
## Examples:
iex> hand = Perudex.Hand.new(%Perudex.Hand{remaining_dice: 5})
iex> %{remaining_dice: 5} = hand
iex> length(hand.dice) == hand.remaining_dice
"""
def new(%Hand{remaining_dice: remaining_dice} = hand) do
%Hand{
hand
| dice:
for _ <- 1..remaining_dice do
:rand.uniform(6)
end
}
end
@doc """
Add a die to the hand if the maximum defined by game rules is not busted.
## Examples:
iex> Perudex.Hand.add(%Perudex.Hand{remaining_dice: 4})
%Perudex.Hand{remaining_dice: 5, dice: nil}
"""
def add(%Hand{remaining_dice: remaining_dice} = hand) do
case remaining_dice < 5 do
true ->
%Hand{hand | remaining_dice: remaining_dice + 1}
_ ->
hand
end
end
@doc """
Remove a die from the hand if it is not empty.
Set has_palificoed to true if the player is dropping to his last die.
## Examples:
iex> Perudex.Hand.take(%Perudex.Hand{remaining_dice: 5})
%Perudex.Hand{remaining_dice: 4, dice: nil, has_palificoed: false}
iex> Perudex.Hand.take(%Perudex.Hand{remaining_dice: 0})
%Perudex.Hand{remaining_dice: 0, dice: nil, has_palificoed: false}
iex> Perudex.Hand.take(%Perudex.Hand{remaining_dice: 2})
%Perudex.Hand{remaining_dice: 1, dice: nil, has_palificoed: true}
"""
def take(%Hand{remaining_dice: 0} = hand) do
hand
end
def take(%Hand{remaining_dice: 2} = hand) do
%Hand{hand | remaining_dice: 1, has_palificoed: true}
end
def take(%Hand{remaining_dice: remaining_dice} = hand) do
%Hand{hand | remaining_dice: remaining_dice - 1}
end
end