mirror of
https://github.com/correl/riichi.git
synced 2024-11-27 11:09:56 +00:00
Updates and tests for yaku detection
This commit is contained in:
parent
200b1a1ddc
commit
e5fdb4801d
4 changed files with 84 additions and 26 deletions
|
@ -36,6 +36,17 @@ find(Tiles, Hand = #hand{tiles=HT, melds=HM}, Possible) ->
|
||||||
find(Rest, Hand#hand{tiles=[T|HT]}, Possible)
|
find(Rest, Hand#hand{tiles=[T|HT]}, Possible)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
tiles(#hand{tiles=Tiles, melds=Melds}) ->
|
||||||
|
lists:flatten([TS || #meld{tiles=TS} <- Melds]) ++ Tiles.
|
||||||
|
|
||||||
|
head(#hand{melds=Melds}) ->
|
||||||
|
case [M || M = #meld{type=pair} <- Melds] of
|
||||||
|
[Pair|_] ->
|
||||||
|
Pair;
|
||||||
|
[] ->
|
||||||
|
none
|
||||||
|
end.
|
||||||
|
|
||||||
is_complete(#hand{tiles=[], melds=Melds}=Hand) ->
|
is_complete(#hand{tiles=[], melds=Melds}=Hand) ->
|
||||||
Pairs = [M || M <- Melds, M#meld.type =:= pair],
|
Pairs = [M || M <- Melds, M#meld.type =:= pair],
|
||||||
case length(Pairs) of
|
case length(Pairs) of
|
||||||
|
|
42
src/yaku.erl
42
src/yaku.erl
|
@ -2,26 +2,32 @@
|
||||||
|
|
||||||
-include("../include/riichi.hrl").
|
-include("../include/riichi.hrl").
|
||||||
|
|
||||||
-compile([export_all]).
|
-export([yakuhai/2,
|
||||||
|
tanyao/2,
|
||||||
|
pinfu/2,
|
||||||
|
chiitoitsu/2,
|
||||||
|
kokushi_musou/2]).
|
||||||
|
|
||||||
|
yakuhai(#game{round=Round}, #player{seat=Seat, hand=#hand{melds=Melds}}) ->
|
||||||
yakuhai(#hand{melds=Melds}) ->
|
|
||||||
length(lists:filter(fun(#meld{type=Type, tiles=[T|_]}) ->
|
length(lists:filter(fun(#meld{type=Type, tiles=[T|_]}) ->
|
||||||
case {Type, T} of
|
case {Type, T} of
|
||||||
{pair, _} ->
|
{pair, _} ->
|
||||||
false;
|
false;
|
||||||
{chii, _} ->
|
{chii, _} ->
|
||||||
false;
|
false;
|
||||||
{_, #tile{suit=wind}} ->
|
{_, #tile{suit=wind, value=Round}} ->
|
||||||
% TODO: Round/Seat Winds
|
true;
|
||||||
false;
|
{_, #tile{suit=wind, value=Seat}} ->
|
||||||
|
true;
|
||||||
{_, #tile{suit=dragon}} ->
|
{_, #tile{suit=dragon}} ->
|
||||||
true
|
true;
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
Melds)).
|
Melds)).
|
||||||
|
|
||||||
tanyao(#hand{melds=Melds}) ->
|
tanyao(#game{}, #player{hand=Hand}) ->
|
||||||
not lists:any(fun(T = #tile{}) ->
|
not lists:any(fun(T = #tile{}) ->
|
||||||
case T#tile.suit of
|
case T#tile.suit of
|
||||||
dragon ->
|
dragon ->
|
||||||
|
@ -32,24 +38,30 @@ tanyao(#hand{melds=Melds}) ->
|
||||||
lists:member(T#tile.value, [1,9])
|
lists:member(T#tile.value, [1,9])
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
lists:flatten([Tiles || #meld{tiles=Tiles} <- Melds])).
|
riichi_hand:tiles(Hand)).
|
||||||
|
|
||||||
pinfu(#hand{melds=Melds}) ->
|
pinfu(#game{round=Round}, #player{seat=Seat, hand=Hand=#hand{melds=Melds}}) ->
|
||||||
% TODO: Verify closed, open wait, pair not round/seat wind
|
% TODO: Verify closed, open wait, and pair not round/seat wind
|
||||||
length([M || M = #meld{type=T} <- Melds, T =:= chii]) =:= 4.
|
Closed = lists:all(fun(T) -> T#tile.from =:= draw end, riichi_hand:tiles(Hand)),
|
||||||
|
Chiis = length([M || M = #meld{type=chii} <- Melds]) =:= 4,
|
||||||
|
#meld{type=pair, tiles=[HeadTile,HeadTile]} = riichi_hand:head(Hand),
|
||||||
|
NonValuePair = HeadTile#tile.value =/= Round
|
||||||
|
andalso HeadTile#tile.value =/= Seat
|
||||||
|
andalso HeadTile#tile.suit =/= dragon,
|
||||||
|
Closed and Chiis and NonValuePair.
|
||||||
|
|
||||||
% 7 Pairs
|
% 7 Pairs
|
||||||
chiitoitsu(#hand{tiles=[], melds=Melds})
|
chiitoitsu(#game{}, #player{hand=#hand{tiles=[], melds=Melds}})
|
||||||
when length(Melds) =:= 7 ->
|
when length(Melds) =:= 7 ->
|
||||||
Pairs = [S || S <- Melds, S#meld.type =:= pair],
|
Pairs = [S || S <- Melds, S#meld.type =:= pair],
|
||||||
length(Pairs) =:= 7 andalso sets:size(sets:from_list(Pairs)) =:= 7.
|
length(Pairs) =:= 7 andalso sets:size(sets:from_list(Pairs)) =:= 7.
|
||||||
|
|
||||||
% 13 Orphans
|
% 13 Orphans
|
||||||
kokushi_musou(#hand{tiles=Tiles, melds=[#meld{type=pair, tiles=[T,T]}]}) ->
|
kokushi_musou(#game{}, #player{hand=#hand{tiles=Tiles, melds=[#meld{type=pair, tiles=[T,T]}]}}) ->
|
||||||
not lists:any(fun(#tile{value=V}) ->
|
not lists:any(fun(#tile{value=V}) ->
|
||||||
lists:member(V, lists:seq(2,8))
|
lists:member(V, lists:seq(2,8))
|
||||||
end,
|
end,
|
||||||
[T|Tiles])
|
[T|Tiles])
|
||||||
andalso sets:size(sets:from_list([T|Tiles])) =:= 13;
|
andalso sets:size(sets:from_list([T|Tiles])) =:= 13;
|
||||||
kokushi_musou(#hand{}) ->
|
kokushi_musou(#game{}, #player{}) ->
|
||||||
false.
|
false.
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
-module(riichi_hand_tests).
|
|
||||||
|
|
||||||
-include("riichi.hrl").
|
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
|
||||||
|
|
||||||
find_hands_test() ->
|
|
||||||
Tiles = [#tile{value=N, suit=pin} || N <- [1,2,3], _ <- [1,2]],
|
|
||||||
SetHand = #hand{sets=[#set{count=2, tile=#tile{value=N, suit=pin}, open=false} || N <- [3,2,1]]},
|
|
||||||
SeqHand = #hand{sets=[#seq{tiles=[#tile{value=N, suit=pin} || N <- [1,2,3]], open=false} || _ <- [1,2]]},
|
|
||||||
Found = [H || H <- riichi_hand:find(Tiles), H#hand.tiles =:= []],
|
|
||||||
?assertEqual([SetHand, SeqHand], Found).
|
|
46
test/riichi_yaku_tests.erl
Normal file
46
test/riichi_yaku_tests.erl
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
-module(riichi_yaku_tests).
|
||||||
|
|
||||||
|
-compile(export_all).
|
||||||
|
|
||||||
|
-include("../include/riichi.hrl").
|
||||||
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
yakuhai_test_() ->
|
||||||
|
Yakuhai = [lists:duplicate(3, #tile{suit=wind, value=east}),
|
||||||
|
lists:duplicate(3, #tile{suit=wind, value=south})
|
||||||
|
] ++ [lists:duplicate(3, #tile{suit=dragon, value=V}) || V <- [red,white,green]],
|
||||||
|
Tiles = [#tile{suit=pin, value=V} || V <- [1,2] ++ lists:seq(1,9)],
|
||||||
|
Hands = [#hand{tiles=Tiles, melds=[#meld{type=pon, tiles=Y}]} || Y <- Yakuhai],
|
||||||
|
Players = [#player{seat=south, hand=H} || H <- Hands],
|
||||||
|
Games = [#game{round=east, players=[P]} || P <- Players],
|
||||||
|
[?_assertEqual(1, yaku:yakuhai(G, P)) || G = #game{players=[P]} <- Games].
|
||||||
|
|
||||||
|
multiple_yakuhai_test() ->
|
||||||
|
Yakuhai = [#meld{type=pon, tiles=lists:duplicate(3, #tile{suit=dragon, value=D})} || D <- [red,green,white]],
|
||||||
|
Player = #player{seat=south, hand=#hand{melds=Yakuhai}},
|
||||||
|
?assertEqual(3, yaku:yakuhai(#game{}, Player)).
|
||||||
|
|
||||||
|
tanyao_test() ->
|
||||||
|
Hand = #hand{melds=[#meld{type=pon, tiles=lists:duplicate(3, #tile{suit=pin, value=2})},
|
||||||
|
#meld{type=pair, tiles=lists:duplicate(2, #tile{suit=sou, value=8})},
|
||||||
|
#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=man, value=V} || V <- [6,7,8]]}]},
|
||||||
|
?assertEqual(true, yaku:tanyao(#game{}, #player{hand=Hand})).
|
||||||
|
|
||||||
|
pinfu_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=man, value=V} || V <- [6,7,8]]}]},
|
||||||
|
?assertEqual(true, yaku:pinfu(#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})).
|
||||||
|
|
||||||
|
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})}]},
|
||||||
|
?assertEqual(true, yaku:kokushi_musou(#game{}, #player{hand=Hand})).
|
Loading…
Reference in a new issue