前几天和同事在聊面试时的练习题,谈到了这个扑克牌的练习题: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 版,1 文件带测试:
https://gist.github.com/luikore/0c99af986ae99d2626e601de6ae1e09a
代码量还是 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
刚学 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]
@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
比较又如何?