http://nabetani.sakura.ne.jp/hena/ord10pokarest/
「ポーカーの残り+」をErlangでやってみました。2時間以上かかりました。
最初に5枚のカードと、そこから4枚取った組み合わせ(drop1)を合わせたリストを作っています。
ストレートとフラッシュの判定は4枚、5枚の両方に対応しています。
Erlangはアトム(royalとかstraightとかflushなど)を値として使えるので、判定部分(hand2)は若干わかりやすく書けました。
各関数は手抜きをして末尾再帰していません。
poker.erl
-module(poker).
-compile(export_all).
hand(Data) ->
X1 = to_array(Data),
X2 = [X1 | drop1(X1)],
X3 = lists:map(fun to_flug/1, X2),
element(2, lists:min(lists:map(fun hand2/1, X3))).
hand2(X) ->
case X of
{5, royal, straight, flush} -> {1, "RF"};
{5, _, straight, flush} -> {2, "SF"};
{5, _, _, flush} -> {3, "FL"};
{5, _, straight, _} -> {4, "ST"};
{4, _, straight, flush} -> {5, "4SF"};
{4, _, _, flush} -> {6, "4F"};
{4, _, straight, x} -> {7, "4S"};
{_, _, _, _} -> {9, "-"}
end.
to_flug(X) ->
{Straight, Royal} = is_straight(X),
{length(X), Royal, Straight, is_flush(X)}.
drop1(Data) ->
lists:foldl(fun(X, L) -> [lists:delete(X, Data) | L] end, [], Data).
to_array([]) -> [];
to_array([H|T]) ->
S = hd(T), R = tl(T),
case H of
$K -> [{S, 13} | to_array(R)];
$Q -> [{S, 12} | to_array(R)];
$J -> [{S, 11} | to_array(R)];
$1 -> [{hd(tl(T)), 10} | to_array(tl(R))];
$A -> [{S, 1} | to_array(R)];
X -> [{S, X - $0} | to_array(R)]
end.
suite(L) -> [element(1, X) || X <- L].
rank(L) -> [element(2, X) || X <- L].
is_straight(L) ->
L2 = lists:sort(rank(L)),
First = hd(L2),
case [X - First + 1 || X <- L2] of
[1,10,11,12,13] -> {straight, royal};
[1,11,12,13] -> {straight, royal};
[1,2,3,4,5] -> {straight, x};
[1,2,3,4] -> {straight, x};
_ -> {x, x}
end.
is_flush(L) -> is_flush2(suite(L)).
is_flush2([S,S,S,S,S]) -> flush;
is_flush2([S,S,S,S]) -> flush;
is_flush2(_) -> x.
tests() ->
test("Qs9s3dJd10h", "4S"), % #0
test("KdAdJd10dQd", "RF"), % #1
test("Js10sAsQsKs", "RF"), % #51
test("10dKdQdAdJd", "RF"). % #52
test(Data, Expected) ->
Result = hand(Data),
io:fwrite("~p: ~s -> ~s~n", [Result =:= Expected, Data, Result]).