diff --git a/src/riichi_hand.erl b/src/riichi_hand.erl index 092c431..6125b35 100644 --- a/src/riichi_hand.erl +++ b/src/riichi_hand.erl @@ -52,9 +52,11 @@ find(Tiles, Hand = #hand{tiles=HT, melds=HM}, Possible) -> find(Rest, Hand#hand{tiles=[T|HT]}, Possible) end. --spec tiles(hand()) -> [tile()]. +-spec tiles(hand() | meld()) -> [tile()]. tiles(#hand{tiles=Tiles, melds=Melds}) -> - lists:flatten([TS || #meld{tiles=TS} <- Melds]) ++ Tiles. + lists:flatten([TS || #meld{tiles=TS} <- Melds]) ++ Tiles; +tiles(#meld{tiles=Tiles}) -> + Tiles. -spec head(hand()) -> meld() | none. head(#hand{melds=Melds}) -> diff --git a/src/yaku.erl b/src/yaku.erl index e650d10..b9a6a1d 100644 --- a/src/yaku.erl +++ b/src/yaku.erl @@ -15,6 +15,7 @@ chanta/2, itsuu/2, chiitoitsu/2, + san_shoku_doujun/2, kokushi_musou/2, ryuu_iisou/2, dai_san_gen/2]). @@ -112,7 +113,25 @@ itsuu(#game{}, #player{hand=#hand{tiles=[], melds=Melds}}) -> sets:from_list([V || #tile{value=V} <- TS]) =:= sets:from_list(lists:seq(1,9)) end, Runs). - +%% @doc Returns true if the provided meld is present in the hand +%% in all three suits +-spec san_shoku(meld(), hand()) -> boolean(). +san_shoku(#meld{tiles=Tiles}, #hand{melds=Melds}) -> + [V1, V2, V3] = [V || #tile{value=V} <- Tiles], + MeldTiles = [TS || #meld{tiles=TS} <- Melds], + TSV = fun(#tile{suit=S,value=V}) -> {S,V} end, + MeldValues = lists:map(fun(L) -> lists:map(TSV, L) end, MeldTiles), + lists:all(fun(M) -> lists:member(M, MeldValues) end, + [[{S, V1}, {S, V2}, {S, V3}] + || S <- [pin, sou, man]]). + +%% @doc Returns true for a San shoku doujun hand +%% Hand must contain the same sequence in all three suits +-spec san_shoku_doujun(game(), player()) -> boolean(). +san_shoku_doujun(#game{}, #player{hand=#hand{melds=Melds}=Hand}) -> + Chiis = [M || #meld{type=chii} = M <- Melds], + lists:any(fun(M) -> san_shoku(M, Hand) end, Chiis). + %% @doc Returns true for a 7-pair hand. -spec chiitoitsu(game(), player()) -> boolean(). chiitoitsu(#game{}, #player{hand=#hand{tiles=[], melds=Melds}}) diff --git a/test/riichi_yaku_tests.erl b/test/riichi_yaku_tests.erl index aff85c1..37775a5 100644 --- a/test/riichi_yaku_tests.erl +++ b/test/riichi_yaku_tests.erl @@ -60,6 +60,14 @@ itsuu_test() -> #meld{type=chii, tiles=[#tile{suit=man, value=V} || V <- [6,7,8]]}]}, ?assertEqual(true, yaku:itsuu(#game{}, #player{hand=Hand, drawn={tsumo, #tile{suit=dragon, value=red}}})). +san_shoku_doujun_test() -> + Hand = #hand{melds=[#meld{type=pair, tiles=lists:duplicate(2, #tile{suit=sou, value=8})}, + #meld{type=chii, tiles=[#tile{suit=sou, value=V} || V <- [1,2,3]]}, + #meld{type=chii, tiles=[#tile{suit=man, value=V} || V <- [1,2,3]]}, + #meld{type=chii, tiles=[#tile{suit=pin, value=V} || V <- [1,2,3]]}, + #meld{type=chii, tiles=[#tile{suit=man, value=V} || V <- [6,7,8]]}]}, + ?assertEqual(true, yaku:san_shoku_doujun(#game{}, #player{hand=Hand, drawn={tsumo, #tile{suit=dragon, value=red}}})). + 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})).