More yaku

This commit is contained in:
Correl Roush 2012-09-16 15:06:15 -04:00
parent 050f3c11eb
commit 0c58354f95
2 changed files with 118 additions and 2 deletions

View file

@ -20,6 +20,12 @@
san_kan_tsu/2,
toi_toi/2,
san_an_kou/2,
shou_san_gen/2,
honrouto/2,
honitsu/2,
jun_chan/2,
ryanpeikou/2,
chinitsu/2,
kokushi_musou/2,
ryuu_iisou/2,
dai_san_gen/2]).
@ -91,8 +97,8 @@ count_unique(L) ->
-spec iipeikou(game(), player()) -> boolean().
iipeikou(#game{}, #player{hand=#hand{melds=Melds}}) ->
Chiis = [M || M = #meld{type=chii} <- Melds],
Counts = [C || {_, C} <- count_unique(Chiis)],
lists:max(Counts) > 1 andalso lists:max(Counts) < 4.
Counts = [C || {_, C} <- count_unique(Chiis), C == 2],
length(Counts) == 1.
%% @doc Returns true for a Chanta hand
%% All melds and the pair must include a terminal or honor tile
@ -164,6 +170,23 @@ san_an_kou(#game{}, #player{hand=#hand{melds=Melds}}) ->
lists:member(T, [pon,kan])],
length(ClosedPons) =:= 3.
%% @doc Returns true for a Shou san gen hand
shou_san_gen(#game{}, #player{hand=#hand{melds=Melds}}) ->
Pons = [M || M = #meld{type=Type, tiles=[#tile{value=Value}|_]} <- Melds,
lists:member(Type, [pon, kan]),
lists:member(Value, [red, green, white])],
Pairs = [M || M = #meld{type=Type, tiles=[#tile{value=Value}|_]} <- Melds,
Type == pair,
lists:member(Value, [red, green, white])],
length(Pons) == 2 andalso length(Pairs) == 1.
%% @doc Returns true for a Honrouto hand
honrouto(#game{}, #player{hand=Hand}) ->
IsHonour = fun(T) ->
lists:member(T, ?HONOURS ++ ?TERMINALS)
end,
lists:all(IsHonour, riichi_hand:tiles(Hand)).
%% @doc Returns true for a 7-pair hand.
-spec chiitoitsu(game(), player()) -> boolean().
chiitoitsu(#game{}, #player{hand=#hand{tiles=[], melds=Melds}})
@ -171,6 +194,43 @@ chiitoitsu(#game{}, #player{hand=#hand{tiles=[], melds=Melds}})
Pairs = [S || S <- Melds, S#meld.type =:= pair],
length(Pairs) =:= 7 andalso sets:size(sets:from_list(Pairs)) =:= 7.
%% @doc Returns true for a Honitsu hand.
honitsu(#game{}, #player{hand=Hand}) ->
Tiles = riichi_hand:tiles(Hand),
Suits = sets:to_list(sets:from_list([Suit || #tile{suit=Suit} <- Tiles,
lists:member(Suit, [pin, sou, man])])),
IsHonour = fun(T) ->
lists:member(T, ?HONOURS)
end,
length(Suits) == 1 andalso lists:any(IsHonour, Tiles).
%% @doc Returns true for a Jun chan hand.
jun_chan(#game{}, #player{hand=#hand{melds=Melds}}) ->
IsTerminal = fun(T) ->
lists:member(T, ?TERMINALS)
end,
HasTerminal = fun(#meld{tiles=Tiles}) ->
lists:any(IsTerminal, Tiles)
end,
lists:all(HasTerminal, Melds).
%% @doc Returns true for a Ryanpeikou hand.
ryanpeikou(#game{}, #player{hand=#hand{melds=Melds}}) ->
Chiis = [M || M = #meld{type=chii} <- Melds],
Counts = [C || {_, C} <- count_unique(Chiis), C == 2],
length(Counts) == 2.
%% @doc Returns true for a Chinitsu hand.
chinitsu(#game{}, #player{hand=Hand}) ->
Tiles = riichi_hand:tiles(Hand),
Suits = sets:to_list(sets:from_list([Suit || #tile{suit=Suit} <- Tiles,
lists:member(Suit, [pin, sou, man])])),
IsHonour = fun(T) ->
lists:member(T, ?HONOURS)
end,
length(Suits) == 1 andalso not lists:any(IsHonour, Tiles).
%% @doc Returns true for a 13 Orphans hand.
%% The hand must contain one each of every terminal and honour tile, plus one
%% additional tile matching any of the others in the hand.

View file

@ -44,6 +44,14 @@ iipeikou_test() ->
#meld{type=chii, tiles=[#tile{suit=man, value=V} || V <- [6,7,8]]}]},
?assertEqual(true, yaku:iipeikou(#game{}, #player{hand=Hand, drawn={tsumo, #tile{suit=sou, value=6}}})).
ryanpeikou_not_iipeikou_test() ->
Hand = #hand{melds=[#meld{type=pair, tiles=lists:duplicate(2, #tile{suit=sou, value=8})},
#meld{type=chii, tiles=[#tile{suit=pin, value=V} || V <- [1,2,3]]},
#meld{type=chii, tiles=[#tile{suit=sou, value=V} || V <- [4,5,6]]},
#meld{type=chii, tiles=[#tile{suit=sou, value=V} || V <- [4,5,6]]},
#meld{type=chii, tiles=[#tile{suit=pin, value=V} || V <- [1,2,3]]}]},
?assertEqual(false, yaku:iipeikou(#game{}, #player{hand=Hand, drawn={tsumo, #tile{suit=sou, value=6}}})).
chanta_test() ->
Hand = #hand{melds=[#meld{type=pair, tiles=lists:duplicate(2, #tile{suit=dragon, value=red})},
#meld{type=chii, tiles=[#tile{suit=pin, value=V} || V <- [1,2,3]]},
@ -100,10 +108,58 @@ san_an_kou_test() ->
#meld{type=chii, tiles=[#tile{suit=man, value=V} || V <- [6,7,8]]}]},
?assertEqual(true, yaku:san_an_kou(#game{}, #player{hand=Hand, drawn={tsumo, #tile{suit=dragon, value=red}}})).
shou_san_gen_test() ->
Hand = #hand{melds=[#meld{type=chii, tiles=[#tile{suit=sou, value=V} || V <- [2,3,4]]},
#meld{type=pon, tiles=lists:duplicate(3, #tile{suit=dragon, value=red})},
#meld{type=pon, tiles=lists:duplicate(3, #tile{suit=dragon, value=green})},
#meld{type=kan, tiles=lists:duplicate(4, #tile{suit=pin, value=1})},
#meld{type=pair, tiles=lists:duplicate(2, #tile{suit=dragon, value=white})}]},
?assert(yaku:shou_san_gen(#game{}, #player{hand=Hand})).
honrouto_test() ->
Hand = #hand{melds=[#meld{type=pon, tiles=lists:duplicate(3, #tile{suit=sou, value=1})},
#meld{type=pon, tiles=lists:duplicate(3, #tile{suit=sou, value=9})},
#meld{type=pon, tiles=lists:duplicate(3, #tile{suit=dragon, value=green})},
#meld{type=kan, tiles=lists:duplicate(4, #tile{suit=pin, value=1})},
#meld{type=pair, tiles=lists:duplicate(2, #tile{suit=dragon, value=white})}]},
?assert(yaku:honrouto(#game{}, #player{hand=Hand})).
chiitoitsu_test() ->
Hand = #hand{melds=[#meld{type=pair, tiles=lists:duplicate(2, #tile{suit=pin, value=V})} || V <- lists:seq(1,7)]},
?assertEqual(true, yaku:chiitoitsu(#game{}, #player{hand=Hand})).
honitsu_test() ->
Hand = #hand{melds=[#meld{type=pair, tiles=lists:duplicate(2, #tile{suit=sou, value=8})},
#meld{type=pon, tiles=lists:duplicate(3, #tile{suit=dragon, value=red})},
#meld{type=chii, tiles=[#tile{suit=sou, value=V} || V <- [4,5,6]]},
#meld{type=chii, tiles=[#tile{suit=sou, value=V} || V <- [4,5,6]]},
#meld{type=pon, tiles=lists:duplicate(3, #tile{suit=sou, value=1})}]},
?assertEqual(true, yaku:honitsu(#game{}, #player{hand=Hand, drawn={tsumo, #tile{suit=sou, value=1}}})).
jun_chan_test() ->
Hand = #hand{melds=[#meld{type=pair, tiles=lists:duplicate(2, #tile{suit=sou, value=9})},
#meld{type=chii, tiles=[#tile{suit=pin, value=V} || V <- [1,2,3]]},
#meld{type=chii, tiles=[#tile{suit=sou, value=V} || V <- [7,8,9]]},
#meld{type=chii, tiles=[#tile{suit=sou, value=V} || V <- [7,8,9]]},
#meld{type=chii, tiles=[#tile{suit=pin, value=V} || V <- [1,2,3]]}]},
?assertEqual(true, yaku:jun_chan(#game{}, #player{hand=Hand, drawn={tsumo, #tile{suit=sou, value=7}}})).
ryanpeikou_test() ->
Hand = #hand{melds=[#meld{type=pair, tiles=lists:duplicate(2, #tile{suit=sou, value=8})},
#meld{type=chii, tiles=[#tile{suit=pin, value=V} || V <- [1,2,3]]},
#meld{type=chii, tiles=[#tile{suit=sou, value=V} || V <- [4,5,6]]},
#meld{type=chii, tiles=[#tile{suit=sou, value=V} || V <- [4,5,6]]},
#meld{type=chii, tiles=[#tile{suit=pin, value=V} || V <- [1,2,3]]}]},
?assertEqual(true, yaku:ryanpeikou(#game{}, #player{hand=Hand, drawn={tsumo, #tile{suit=sou, value=6}}})).
chinitsu_test() ->
Hand = #hand{melds=[#meld{type=pair, tiles=lists:duplicate(2, #tile{suit=sou, value=8})},
#meld{type=pon, tiles=lists:duplicate(3, #tile{suit=sou, value=9})},
#meld{type=chii, tiles=[#tile{suit=sou, value=V} || V <- [4,5,6]]},
#meld{type=chii, tiles=[#tile{suit=sou, value=V} || V <- [4,5,6]]},
#meld{type=pon, tiles=lists:duplicate(3, #tile{suit=sou, value=1})}]},
?assertEqual(true, yaku:chinitsu(#game{}, #player{hand=Hand, drawn={tsumo, #tile{suit=sou, value=1}}})).
kokushi_musou_test() ->
Hand = #hand{tiles=?TERMINALS ++ ?HONOURS -- [#tile{suit=pin, value=1}],
melds=[#meld{type=pair, tiles=lists:duplicate(2, #tile{suit=pin, value=1})}]},