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