diff --git a/lib/dojo/hand.ex b/lib/dojo/hand.ex index 58260f2..32bf40c 100644 --- a/lib/dojo/hand.ex +++ b/lib/dojo/hand.ex @@ -5,5 +5,68 @@ defmodule Dojo.Hand do evaluate(cards) end - defp evaluate(_), do: :high_card + defp evaluate(cards) do + cond do + is_royal_flush?(cards) -> + :royal_flush + is_straight_flush?(cards) -> + :straight_flush + is_flush?(cards) -> + :flush + is_straight?(cards) -> + :straight + is_pair?(cards) -> + :pair + true -> + :high_card + end + + end + + defp min_rank(cards) do + cards + |> Enum.sort(&(&1.rank <= &2.rank)) + |> List.first() + |> Map.get(:rank) + end + + defp is_straight?(cards) do + min = min_rank(cards) + list = Enum.to_list min..(min + 4) + result = cards + |> Enum.map(&(&1.rank in list)) + |> Enum.reduce(true, fn(x, acc) -> x && acc end) + end + + defp is_straight_flush?(cards) do + is_straight?(cards) && is_flush?(cards) + end + + defp is_royal_flush?(cards) do + is_straight_flush?(cards) && (min_rank(cards) == 10) + end + + defp is_flush?(cards) do + kind = cards + |> List.first() + |> Map.get(:suit) + + cards + |> Enum.map(&(&1.suit == kind)) + |> Enum.reduce(true, fn(x, acc) -> x && acc end) + end + + defp cardinality(cards) do + ranks = cards + |> Enum.map(&(&1.rank)) + + numbers = ranks + |> Enum.group_by(fn(x) -> x end) + |> Enum.map(fn({_, val}) -> length val end) + end + + defp is_pair?(cards) do + numbers = cardinality(cards) + 2 in numbers + end end diff --git a/test/dojo/hand_test.exs b/test/dojo/hand_test.exs index 5188ab3..3f78503 100644 --- a/test/dojo/hand_test.exs +++ b/test/dojo/hand_test.exs @@ -13,7 +13,7 @@ defmodule Dojo.HandTest do %Card{rank: 14, suit: :hearts} ] - assert Hand.score(cards) == :straight_flush + assert Hand.score(cards) == :royal_flush end test "evaluates flush of hearts" do @@ -63,4 +63,29 @@ defmodule Dojo.HandTest do assert Hand.score(cards) == :high_card end + + test "evaluates straight cards" do + cards = [ + %Card{rank: 2, suit: :spades}, + %Card{rank: 3, suit: :hearts}, + %Card{rank: 4, suit: :diamonds}, + %Card{rank: 5, suit: :spades}, + %Card{rank: 6, suit: :spades} + ] + + assert Hand.score(cards) == :straight + end + + + test "evaluates pair cards" do + cards = [ + %Card{rank: 2, suit: :spades}, + %Card{rank: 2, suit: :hearts}, + %Card{rank: 1, suit: :diamonds}, + %Card{rank: 5, suit: :spades}, + %Card{rank: 6, suit: :spades} + ] + + assert Hand.score(cards) == :pair + end end