Erlang/Elixir 这几天练练手,同一个练习题写了一个 Ruby 版本,一个 Elixir 版本

fredwu · 2016年08月27日 · 最后由 wadexing 回复于 2016年09月01日 · 7889 次阅读
本帖已被管理员设置为精华贴

前几天和同事在聊面试时的练习题,谈到了这个扑克牌的练习题:http://codingdojo.org/cgi-bin/index.pl?KataPokerHands

于是我就兴起用 ruby 练了一下,再用 elixir 练了一下:

https://github.com/fredwu/kata-poker-hands-ruby https://github.com/fredwu/kata-poker-hands-elixir

欢迎拍砖。:)

代码量还是 ruby 少点?

→ cloc lib                           ~/Downloads/kata-poker-hands-elixir-master
      17 text files.
      17 unique files.                              
       0 files ignored.

github.com/AlDanial/cloc v 1.70  T=0.09 s (188.3 files/s, 7774.9 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Elixir                          17            121             29            552
-------------------------------------------------------------------------------
SUM:                            17            121             29            552
-------------------------------------------------------------------------------
→                                    ~/Downloads/kata-poker-hands-elixir-master
→ cloc lib                             ~/Downloads/kata-poker-hands-ruby-master
      16 text files.
      16 unique files.                              
       0 files ignored.

github.com/AlDanial/cloc v 1.70  T=0.08 s (208.5 files/s, 4912.7 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Ruby                            16             54             16            307
-------------------------------------------------------------------------------
SUM:                            16             54             16            307
-------------------------------------------------------------------------------
→                                      ~/Downloads/kata-poker-hands-ruby-master
lgn21st 将本帖设为了精华贴。 08月28日 12:01

刚学 elixir,还不太会用,勉强实现了。

defmodule Poker do

  @ranks ["high card", "pair", "two pairs", "three of a kind", "straight",
   "flush", "full house", "four of a kind", "straight flush"]
  @values [2, 3, 4, 5, 6, 7, 8, 9, 10, "Jack", "Queen", "King", "Ace"]

  def start(str) do
    str
    |> String.trim
    |> String.split("\n")
    |> Enum.map(&String.trim(&1, "Black: "))
    |> Enum.map(&String.split(&1, "  White: "))
    |> Enum.map(fn([b, w]) -> compare(b, w) end)
  end

  def compare(b, w) do
    [b, w]
    |> Enum.map(&parse/1)
    |> winner_is
  end

  defp parse(str) do
    str
    |> String.trim
    |> String.split("\s")
    |> Enum.map(fn
      <<?A, s>> -> [ 14, s]
      <<?K, s>> -> [ 13, s]
      <<?Q, s>> -> [ 12, s]
      <<?J, s>> -> [ 11, s]
      <<?T, s>> -> [ 10, s]
      <<x, s>> -> [x-?0, s]
    end)
    |> Enum.sort(&>/2)
    |> rank_and_value
  end

  defp rank_and_value(cards) do
    x = hd(hd(cards))
    y = x-1
    z = x-2
    u = x-3
    v = x-4
    case cards do
      [[^x,a],[^y,a],[^z,a],[^u,a],[^v,a]] -> [rank: 9, value: x]
      [[x,_],[x,_],[x,_],[x,_],[y,_]] -> [rank: 8, value: x]
      [[x,_],[y,_],[y,_],[y,_],[y,_]] -> [rank: 8, value: y]
      [[x,_],[x,_],[x,_],[y,_],[y,_]] -> [rank: 7, value: x]
      [[x,_],[x,_],[y,_],[y,_],[y,_]] -> [rank: 7, value: y]
      [[x,a],[_,a],[_,a],[_,a],[_,a]] -> [rank: 6, value: x]
      [[^x,_],[^y,_],[^z,_],[^u,_],[^v,_]] -> [rank: 5, value: x]
      [[x,_],[x,_],[x,_],[y,_],[z,_]] -> [rank: 4, value: x]
      [[x,_],[y,_],[z,_],[z,_],[z,_]] -> [rank: 4, value: z]
      [[x,_],[x,_],[y,_],[y,_],[z,_]] -> [rank: 3, value: [x,y,z]]
      [[x,_],[x,_],[y,_],[z,_],[z,_]] -> [rank: 3, value: [x,z,y]]
      [[x,_],[y,_],[y,_],[z,_],[z,_]] -> [rank: 3, value: [y,z,x]]
      [[x,_],[x,_],[y,_],[z,_],[u,_]] -> [rank: 2, value: [x,y,z,u]]
      [[x,_],[y,_],[y,_],[z,_],[u,_]] -> [rank: 2, value: [y,x,z,u]]
      [[x,_],[y,_],[z,_],[z,_],[u,_]] -> [rank: 2, value: [z,x,y,u]]
      [[x,_],[y,_],[z,_],[u,_],[u,_]] -> [rank: 2, value: [u,x,y,z]]
      [[x,_],[y,_],[z,_],[u,_],[v,_]] -> [rank: 1, value: [x,y,z,u,v]]
    end
  end

  defp winner_is([black, white]) do
    black_rank = Enum.at(@ranks, black[:rank]-1)
    white_rank = Enum.at(@ranks, white[:rank]-1)
    cond do
      black[:rank] > white[:rank] ->
        IO.puts "Black wins. - with #{black_rank}"
      black[:rank] < white[:rank] ->
        IO.puts "White wins. - with #{white_rank}"
      true -> value_compare([black, white])
    end
  end

  defp value_compare([black, white]) do
    black_rank = Enum.at(@ranks, black[:rank]-1)
    white_rank = Enum.at(@ranks, white[:rank]-1)
    cond do
      black[:value] > white[:value] ->
        black_value = value_message(black[:value], white[:value])
        IO.puts "Black wins. - with #{black_rank}: #{black_value}"
      black[:value] < white[:value] ->
        white_value = value_message(white[:value], black[:value])
        IO.puts "White wins. - with #{white_rank}: #{white_value}"
      true -> IO.puts "Tie."
    end
  end

  defp value_message(a,b) do
    unless is_list(a) do
      Enum.at(@values, a-2)
    else
      Enum.at(@values, first_uniq_value(a, b)-2)
    end
  end

  defp first_uniq_value(a, b) when hd(a) == hd(b) do
    first_uniq_value(tl(a), tl(b))
  end

  defp first_uniq_value(a, b), do: hd(a)

end

IO.inspect Poker.start(
"Black: 2H 3D 5S 9C KD  White: 2C 3H 4S 8C AH
Black: 2H 4S 4C 2D 4H  White: 2S 8S AS QS 3S
Black: 2H 3D 5S 9C KD  White: 2C 3H 4S 8C KH
Black: 2H 3D 5S 9C KD  White: 2D 3H 5C 9S KH")

输出

White wins. - with high card: Ace
Black wins. - with full house
Black wins. - with high card: 9
Tie.
[:ok, :ok, :ok, :ok]

我的代码太可怕了。。。

好凶残的代码,Elixir 好可怕 #4 楼 @Ljzn

#5 楼 @Ljzn 其实还可以编译期把所有的组合全算好…………

@fredwu 新增一个 Crystal version. 欢迎拍砖。😳 https://github.com/mimosa/kata-poker-hands-crystal

≡ cloc src                                    kata-poker-hands-crystal ≡ MASTER
      17 text files.
      17 unique files.                              
       0 files ignored.

github.com/AlDanial/cloc v 1.70  T=0.06 s (301.9 files/s, 6163.1 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Crystal                         17             49              0            298
-------------------------------------------------------------------------------
SUM:                            17             49              0            298
-------------------------------------------------------------------------------

看了几个实现,都认为 A 2 3 4 5 是 Straight.

规则是这么描述的:

For scoring purposes, the suits are unordered while the values are ordered as given above, with 2 being the lowest and ace the highest value. Straight: Hand contains 5 cards with consecutive values. Hands which both contain a straight are ranked by their highest card.

并没有表明可以循环排列。

而且如果 A 2 3 4 5 是 Straight,那和 T J Q K A 比那个大?和 9 T J Q K 比较又如何?

为什么都来比代码行数了啊~~~~~

#9 楼 @zlx_star A 2 3 4 5 是 Straight,10 J Q K A 也是 Straight,10 J Q K A 最大因为这里的 Ace 是 high card

#9 楼 @zlx_star 其实原本我没去实现 A 2 3 4 5,因为的确规则里没有谈及到,但同事看了后问了我一下,于是我就去把它实现了。😅

#12 楼 @fredwu 作为练习的确是如此,给代码点个赞 还没有 Rust 版本,整了一个:移步 gist 吐槽

#9 楼 @zlx_star 我觉得 A2345 不能算顺子

太长的代码放到 gist 吧,不好阅读。

#14 楼 @Ljzn 我也是这么觉得,严格按照题目描述。 不过显然,要算的话难度更大,作为 kata 练习来说,why not?

需要 登录 后方可回复, 如果你还没有账号请 注册新账号