mirror of
https://github.com/correl/riichi.git
synced 2024-11-27 11:09:56 +00:00
Initial commit
This commit is contained in:
commit
a68168d651
9 changed files with 232 additions and 0 deletions
14
Makefile
Normal file
14
Makefile
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
.PHONY: all deps compile test clean
|
||||||
|
|
||||||
|
REBAR=./rebar
|
||||||
|
|
||||||
|
all: deps compile
|
||||||
|
|
||||||
|
deps:
|
||||||
|
@$(REBAR) get-deps
|
||||||
|
compile: deps
|
||||||
|
@$(REBAR) compile
|
||||||
|
test:
|
||||||
|
@$(REBAR) skip_deps=true eunit
|
||||||
|
clean:
|
||||||
|
@$(REBAR) clean
|
4
include/riichi.hrl
Normal file
4
include/riichi.hrl
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
-record(tile, {
|
||||||
|
suit,
|
||||||
|
value
|
||||||
|
}).
|
BIN
rebar
vendored
Executable file
BIN
rebar
vendored
Executable file
Binary file not shown.
1
rebar.config
Normal file
1
rebar.config
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{cover_enabled, true}.
|
12
src/riichi.app.src
Normal file
12
src/riichi.app.src
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{application, riichi,
|
||||||
|
[
|
||||||
|
{description, ""},
|
||||||
|
{vsn, "1"},
|
||||||
|
{registered, []},
|
||||||
|
{applications, [
|
||||||
|
kernel,
|
||||||
|
stdlib
|
||||||
|
]},
|
||||||
|
{mod, { riichi_app, []}},
|
||||||
|
{env, []}
|
||||||
|
]}.
|
73
src/riichi.erl
Normal file
73
src/riichi.erl
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
-module(riichi).
|
||||||
|
|
||||||
|
-include("riichi.hrl").
|
||||||
|
|
||||||
|
-export([
|
||||||
|
is_valid_tile/1,
|
||||||
|
dora/1,
|
||||||
|
nearest/2,
|
||||||
|
score/3
|
||||||
|
]).
|
||||||
|
|
||||||
|
is_valid_tile(#tile{suit=dragon, value=Value}) ->
|
||||||
|
lists:member(Value, [white, green, red]);
|
||||||
|
is_valid_tile(#tile{suit=wind, value=Value}) ->
|
||||||
|
lists:member(Value, [east, south, west, north]);
|
||||||
|
is_valid_tile(#tile{suit=Suit, value=Value}) ->
|
||||||
|
ValidSuit = lists:member(Suit, [pin, sou, man]),
|
||||||
|
ValidValue = is_integer(Value) and (Value > 0) and (Value < 10),
|
||||||
|
ValidSuit and ValidValue;
|
||||||
|
is_valid_tile(_) ->
|
||||||
|
false.
|
||||||
|
|
||||||
|
dora(#tile{suit=dragon, value=Value}=Indicator) ->
|
||||||
|
case Value of
|
||||||
|
white -> Indicator#tile{value=green};
|
||||||
|
green -> Indicator#tile{value=red};
|
||||||
|
red -> Indicator#tile{value=white}
|
||||||
|
end;
|
||||||
|
dora(#tile{suit=wind, value=Value}=Indicator) ->
|
||||||
|
case Value of
|
||||||
|
east -> Indicator#tile{value=south};
|
||||||
|
south -> Indicator#tile{value=west};
|
||||||
|
west -> Indicator#tile{value=north};
|
||||||
|
north -> Indicator#tile{value=east}
|
||||||
|
end;
|
||||||
|
dora(#tile{value=Value}=Indicator) ->
|
||||||
|
case is_valid_tile(Indicator) of
|
||||||
|
false ->
|
||||||
|
throw({error, invalid_tile});
|
||||||
|
_ ->
|
||||||
|
if
|
||||||
|
Value == 9 -> Indicator#tile{value=1};
|
||||||
|
true -> Indicator#tile{value=Value + 1}
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
nearest(Num, To) when Num rem To == 0 ->
|
||||||
|
Num;
|
||||||
|
nearest(Num, To) ->
|
||||||
|
Num - (Num rem To) + To.
|
||||||
|
|
||||||
|
|
||||||
|
score(_Fu, Yaku, Limit) when (Yaku >= 5) and (Limit == true) ->
|
||||||
|
if
|
||||||
|
Yaku < 6 ->
|
||||||
|
2000;
|
||||||
|
Yaku < 8 ->
|
||||||
|
3000;
|
||||||
|
Yaku < 11 ->
|
||||||
|
4000;
|
||||||
|
Yaku < 14 ->
|
||||||
|
6000;
|
||||||
|
true ->
|
||||||
|
8000
|
||||||
|
end;
|
||||||
|
score(Fu, Yaku, Limit) ->
|
||||||
|
Score = nearest(Fu * round(math:pow(2, 2 + Yaku)), 100),
|
||||||
|
if
|
||||||
|
Limit and (Score > 2000) ->
|
||||||
|
2000;
|
||||||
|
true ->
|
||||||
|
Score
|
||||||
|
end.
|
16
src/riichi_app.erl
Normal file
16
src/riichi_app.erl
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
-module(riichi_app).
|
||||||
|
|
||||||
|
-behaviour(application).
|
||||||
|
|
||||||
|
%% Application callbacks
|
||||||
|
-export([start/2, stop/1]).
|
||||||
|
|
||||||
|
%% ===================================================================
|
||||||
|
%% Application callbacks
|
||||||
|
%% ===================================================================
|
||||||
|
|
||||||
|
start(_StartType, _StartArgs) ->
|
||||||
|
riichi_sup:start_link().
|
||||||
|
|
||||||
|
stop(_State) ->
|
||||||
|
ok.
|
28
src/riichi_sup.erl
Normal file
28
src/riichi_sup.erl
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
-module(riichi_sup).
|
||||||
|
|
||||||
|
-behaviour(supervisor).
|
||||||
|
|
||||||
|
%% API
|
||||||
|
-export([start_link/0]).
|
||||||
|
|
||||||
|
%% Supervisor callbacks
|
||||||
|
-export([init/1]).
|
||||||
|
|
||||||
|
%% Helper macro for declaring children of supervisor
|
||||||
|
-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
|
||||||
|
|
||||||
|
%% ===================================================================
|
||||||
|
%% API functions
|
||||||
|
%% ===================================================================
|
||||||
|
|
||||||
|
start_link() ->
|
||||||
|
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||||
|
|
||||||
|
%% ===================================================================
|
||||||
|
%% Supervisor callbacks
|
||||||
|
%% ===================================================================
|
||||||
|
|
||||||
|
init([]) ->
|
||||||
|
{ok, { {one_for_one, 5, 10}, []} }.
|
||||||
|
|
84
test/riichi_tests.erl
Normal file
84
test/riichi_tests.erl
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
-module(riichi_tests).
|
||||||
|
|
||||||
|
-include("riichi.hrl").
|
||||||
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
valid_tile_dragon_test_() ->
|
||||||
|
[?_assert(riichi:is_valid_tile(#tile{suit=dragon, value=Value})) || Value <- [white, green, red]].
|
||||||
|
valid_tile_wind_test_() ->
|
||||||
|
[?_assert(riichi:is_valid_tile(#tile{suit=wind, value=Value})) || Value <- [east, south, west, north]].
|
||||||
|
valid_tile_suit_test_() ->
|
||||||
|
[?_assert(riichi:is_valid_tile(#tile{suit=Suit, value=Value})) || Suit <- [pin, sou, man], Value <- lists:seq(1,9)].
|
||||||
|
|
||||||
|
invalid_tile_test_() ->
|
||||||
|
[?_assertNot(riichi:is_valid_tile(Tile))
|
||||||
|
|| Tile <-
|
||||||
|
[
|
||||||
|
#tile{suit=badsuit, value=1},
|
||||||
|
#tile{suit=dragon, value=hidden},
|
||||||
|
#tile{suit=wind, value=broken},
|
||||||
|
#tile{suit=pin, value=0},
|
||||||
|
#tile{suit=sou, value=-1},
|
||||||
|
#tile{suit=man, value=10},
|
||||||
|
not_a_tile
|
||||||
|
]
|
||||||
|
].
|
||||||
|
|
||||||
|
dora_dragon_test_() ->
|
||||||
|
[?_assertEqual(riichi:dora(#tile{suit=dragon, value=Indicator}), #tile{suit=dragon, value=Dora})
|
||||||
|
|| {Indicator, Dora} <-
|
||||||
|
[
|
||||||
|
{white, green},
|
||||||
|
{green, red},
|
||||||
|
{red, white}
|
||||||
|
]
|
||||||
|
].
|
||||||
|
|
||||||
|
dora_wind_test_() ->
|
||||||
|
[?_assertEqual(riichi:dora(#tile{suit=wind, value=Indicator}), #tile{suit=wind, value=Dora})
|
||||||
|
|| {Indicator, Dora} <-
|
||||||
|
[
|
||||||
|
{east, south},
|
||||||
|
{south, west},
|
||||||
|
{west, north},
|
||||||
|
{north, east}
|
||||||
|
]
|
||||||
|
].
|
||||||
|
|
||||||
|
dora_suit_test_() ->
|
||||||
|
[?_assertEqual(riichi:dora(#tile{suit=Suit, value=Indicator}), #tile{suit=Suit, value=Dora})
|
||||||
|
||
|
||||||
|
{Indicator, Dora} <-
|
||||||
|
[{1,2}, {2,3}, {3,4}, {4,5}, {5,6}, {6,7}, {7,8}, {8,9}, {9,1}],
|
||||||
|
Suit <- [pin, sou, man]
|
||||||
|
].
|
||||||
|
|
||||||
|
dora_invalid_test() ->
|
||||||
|
?assertException(throw, {error, invalid_tile}, riichi:dora(#tile{suit=pin, value=9001})).
|
||||||
|
|
||||||
|
nearest_test_() ->
|
||||||
|
[?_assertEqual(riichi:nearest(Val, 10), 80) || Val <- lists:seq(71,80)].
|
||||||
|
|
||||||
|
score_yaku_limit_test_() ->
|
||||||
|
[?_assertEqual(riichi:score(30, Yaku, true), Score)
|
||||||
|
|| {Yaku, Score} <-
|
||||||
|
[
|
||||||
|
{ 5, 2000},
|
||||||
|
{ 6, 3000},
|
||||||
|
{ 7, 3000},
|
||||||
|
{ 8, 4000},
|
||||||
|
{ 9, 4000},
|
||||||
|
{10, 4000},
|
||||||
|
{11, 6000},
|
||||||
|
{12, 6000},
|
||||||
|
{13, 6000},
|
||||||
|
{14, 8000},
|
||||||
|
{1000, 8000}
|
||||||
|
]
|
||||||
|
].
|
||||||
|
|
||||||
|
score_fu_limit_test() ->
|
||||||
|
?assertEqual(riichi:score(80, 4, true), 2000).
|
||||||
|
|
||||||
|
score_rounded_test() ->
|
||||||
|
?assertEqual(riichi:score(20, 1, true), 200). % 160 rounded up
|
Loading…
Reference in a new issue