Language detail: Erlang

Coverage: 51.85%
number of '+' ratings
contribution for coverage

Unsolved challenges

codes

Feed

Used modules

next >>

LL Golf Hole 8 - 横向きのピラミッドを作る (Nested Flatten)
実行するには

erlc pyramid.erl
erl -noshell -run pyramid main 自然数 -s init stop

としてください。
http://ja.doukaku.org/comment/7419/ とは違い、0 の場合エラーになります。
1
2
3
4
5
-module(pyramid).
-export([main/1]).

main([S])->N=list_to_integer(S),[io:format("~*c
",[N-abs(M),$*])||M<-lists:seq(1-N,N-1)].
#7419で投稿しましたが、push, popという関数名がそぐわない感じがしたので、
別のスタイルで書いてみました。
改行を含む文字列を前後両側に伸ばしていく感じです。
実行方法は#7419同様です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
-module(pyramid).
-export([main/1]).

main([N])->
        Len=list_to_integer(atom_to_list(N)),
        s(Len,p(Len)).

s(0,_)->0;
s(1,S)->io:format("~s", [S]);
s(N,S)->s(N - 1, p(N - 1) ++ S ++ p(N - 1)).

p(0)-> [$\n];
p(N)-> "*" ++ p(N - 1).
実行するには、以下のようにコマンド入力します。
コマンドの引数として数値を与えています。
一応、0のケースも入れておきました。

erlc スクリプトファイル名
erl -noshell -s pyramid main 自然数 -s init stop

実行例
$ erl -noshell -s pyramid main 0 -s init stop

$ erl -noshell -s pyramid main 1 -s init stop
*

$ erl -noshell -s pyramid main 3 -s init stop
*
**
***
**
*
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
-module(pyramid).
-export([main/1]).

main([N])-> push(list_to_integer(atom_to_list(N)),[]).

push(0,_)->0;
push(1,L)->io:format("~s~n",[L ++ "*"]), pop(L ++ "*");
push(N,L)->io:format("~s~n",[L ++ "*"]), push(N - 1, L ++ "*").

pop("*")-> 0;
pop([_|L])-> io:format("~s~n",[L]), pop(L).
LL Golf Hole 7 - バイト数を読みやすくする (Nested Flatten)
実行する場合は以下のようにコマンドを実行します。
数値はコマンドの引数として与えます。

erlc ファイル名
erl -noshell -s kuraidori put 数値 -s init stop

実行例
$ erl -noshell -s kuraidori put 1234567890 -s init stop
1.2G
$ erl -noshell -s kuraidori put 12345678901234 -s init stop
12.3T
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
-module(kuraidori).
-export([put/1]).

put([S]) -> loop(list_to_integer(atom_to_list(S))," KMGTPEZY").

loop(S,[H|[]]) -> pr(S,H);
loop(S,[H|_]) when S < 1000 ->
        if
        is_integer(S) -> pri(S,H);
        true -> pr(S,H)
        end;
loop(S,[_|L]) -> loop(S / 1000, L).

pr(S,K) -> io:format("~.1f~s~n",[S,[K]]).
pri(S,K) -> io:format("~.10B~s~n",[S,[K]]).
倍数になる13進数 (Nested Flatten)
erl_evalと Erlang特有のN進法表記(N#M, 基数Nは36以下)を
使ってみたらどうだろうと思って書いてみました。
基数に上限があるので汎用性に欠けると思います。

プログラムを bai13.erl というファイル名で保存して、
$ erl -noshell -s bai13 getfirst -s init stop
のようにして起動します。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
-module(bai13).
-export([getfirst/0]).

getfirst() ->
    loop(10).

loop(N) ->
    case (eval("13#" ++ integer_to_list(N) ++ ".") rem N) of
        0 -> io:format("~p~n",[N]);
        true -> loop(N + 1)
    end.

eval(Expr)->
    {ok, Tokens, _}=erl_scan:string(Expr),
    {ok,[Expression]} = erl_parse:parse_exprs(Tokens),
    {value, Ret,_} = erl_eval:expr(
        Expression ,erl_eval:bindings(erl_eval:new_bindings())
        ),
  Ret.
LL Golf Hole 6 - 10進数を2進数に基数変換する (Nested Flatten)
Erlangのインタプリタコマンドであるescriptで実行するとしたケースです。
その場合、コードの最初の行は無視されるので、コメント行となっています。

入力となる10進数は、標準入力から与えます。

実行例(スクリプトファイル名を t.erl とします)
$ escript  t.erl
2
10
$
1
2
%
main(_)->{V,_}=string:to_integer(io:get_line('')),io:format("~.2B~n",[V]).
LL Golf Hole 5 - 最上位の桁を数え上げる (Nested Flatten)
スクリプト内のリテラルとして、300という整数を与えています。

escript スクリプトのファイル名

として実行します。
この場合、最初のコメント行は必須です。
1
2
3
4
5
%
s(X,Y)when X < 10->erlang:display(Y);
s(X,Y)when X rem 10=:=0->s(X div 10,Y);
s(_,_)->0.
main(_)->[s(X,X)||X<-lists:seq(0,300)].
LL Golf Hole 3 - 13日の金曜日を数え上げる (Nested Flatten)
申し訳ありません、動かないコードを投稿してしまいました。
最初に投稿したものは、最初に空行が必要でした。
(escriptコマンドは、最初の行を無視するため)
最初の行をコメントとして、コードも多少短くしたものを再投稿いたします。

実行方法と結果は、以下のように、元記事と同様です。

escript スクリプトのファイル名
[{2009,2,13},
 {2009,3,13},
 {2009,11,13},
 {2010,8,13},
 {2011,5,13},
 {2012,1,13},
 {2012,4,13},
 {2012,7,13},
 {2013,9,13},
 {2013,12,13}]
10 days
1
2
3
4
%%
main(_)->M=[{X,Y,13}||{X,Y,13}<-a(date(),{2013,12,31}),calendar:day_of_the_week({X,Y,13})=:=5],io:format("~p~n~p days~n",[M,length(M)]).
a(X,X)->[X];
a(X,Y)->[X]++a(calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(X)+1),Y).
大元になる日付のリストは素直に1日ごとのものを生成しています。
escript ファイル名
として実行します。
実行結果例(2008/8/7に実行)
[{2009,2,13},
 {2009,3,13},
 {2009,11,13},
 {2010,8,13},
 {2011,5,13},
 {2012,1,13},
 {2012,4,13},
 {2012,7,13},
 {2013,9,13},
 {2013,12,13}]
10 days
1
2
3
4
5
6
7
8
main(_) ->
        L=a(date(),{2013,12,31}),
    M=[{X,Y,13} || {X,Y,13} <- L, calendar:day_of_the_week({X,Y,13}) =:= 5],
    io:format("~p~n~p days~n", [M, length(M)]).

a(X,X) -> [X];
a(X,Y) -> [X] ++ a(calendar:gregorian_days_to_date(
                 calendar:date_to_gregorian_days(X)+1),Y).
LL Golf Hole 2 - 文字列に含まれる単語の最初の文字を大文字にする (Nested Flatten)

Erlang 版を縮めてみました。

1
S=string,S:join([[S:to_upper(H)]++T||[H|T]<-S:tokens("LL day and night"," ")]," ").

Erlang 版を 1 文字削り損ねてました。

1
S=string,S:join([[S:to_upper(H)|T]||[H|T]<-S:tokens("LL day and night"," ")]," ").
インタープリタ(erl)のコマンドラインで実行する形式です。
文字列は、string:tokens関数の第1引数として、
ダブルクォートでくくって指定しています。
単語の区切りを1文字の空白と仮定しています。
エスケープされた文字などについては考慮していません。
特にgolfを意識したことは自分にはできませんでした。
1
string:join(lists:map(fun([H|T])->[string:to_upper(H)]++T end,string:tokens("LL day and night"," "))," ").
コード中の文字の頻度分析 (Nested Flatten)
ErlangのR13B3をCentOS5で展開したときの erlang/lib/erlang/lib 以下の *.erlの全ファイルをcatして1ファイルにまとめてから文字の頻度を調べてみました。39MBほどありました。 入力をバッファしているのは、単純に1文字ごとの入力を行うと実行がかなり遅かったためです。 ハイフンが多いのが目立ちますが、これは関数の定義などで多用されるためかもしれません。 '%'はコメントを示すために使われているので多いかもしれません。 "e", 6.5985% "-", 5.9863% "t", 4.5781% ",", 3.9575% "a", 3.6420% "s", 3.4442% "r", 3.2970% "n", 3.2844% "o", 2.8633% "c", 2.6825% "i", 2.6595% "_", 2.5216% "l", 1.9182% "d", 1.9072% "=", 1.5386% "p", 1.5198% ")", 1.5170% "(", 1.5167% "%", 1.3770% "T", 1.3100% "m", 1.2499% "u", 1.0674% "S", 1.0670% "y", 0.9540% "g", 0.9246% ">", 0.8690% "f", 0.8180% "'", 0.7649% "h", 0.6953% "}", 0.6748% "{", 0.6747% "1", 0.6745% "b", 0.6105% "E", 0.6047% "R", 0.5908% "2", 0.5786% "k", 0.5548% "v", 0.5152%
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/usr/bin/env escript
main(Filename) ->
    case file:read_file(Filename) of
        {ok, S} -> buffered_loop(S,1);
        {error, Why} -> {error, Why}
    end.

%% buffering is required to manage huge heap_area for listdata
buffered_loop(S,N) ->
    BUFSIZE = 40960,
    if
    (byte_size(S) < (N + BUFSIZE)) ->
        loop(binary_to_list(S, N, byte_size(S))),
        L = lists:sort(get()),
        Total = sumup(L, 0),
        io:format("Total characters : ~p~n",[Total]),
        show_histgram(L,Total);
    true ->
        loop(binary_to_list(S, N, N + BUFSIZE)),
        buffered_loop(S, N + BUFSIZE)
    end.

loop([]) -> [];
loop([H|L]) -> incr(H), loop(L).

incr(Chr) ->
    case Count = get(Chr) of
    undefined -> put(Chr,1);
    _ -> put(Chr,Count + 1)
    end.

sumup([H|[]], Sum) -> {_,V} = H, Sum + V;
sumup([H|L], Sum) -> {_,V} = H, sumup(L, Sum + V).

show_histgram([H|[]], Total) -> {K,V} = H, io:format("~p,~8.4f\%~n",[[K], 100 * V / Total]);
show_histgram([H|L], Total) -> {K,V} = H, io:format("~p,~8.4f\%~n",[[K], 100 * V / Total]), show_histgram(L, Total).
比較しないソートの作成 (Nested Flatten)
適当に書いていたら、quicksortのように
Pivotとして実際の要素を使えないので、
場合分けで結構バグってしまいました(恥
これもバグってるかも。

>c(sort).
{ok,sort}
> sort:main(-1,10,10, [-1,9,4,8,9,6,3,9,5,2]).
[-1,2,3,4,5,6,8,9,9,9]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
-module(sort).
-export([main/4]).

main(Min, Max, _Num, List) ->
   sort(Min, Max, List).

sort(_Min, _Max, []) -> [];
sort(_Min, _Max, [H|[]]) -> [H];
sort(Min, Min, List) -> List;
sort(Min, Max, List) ->
    Pivot = Min + ((Max - Min) div 2),
    sort(Min,Pivot, [ X || X <- List, X < Pivot ])
    ++
    [ X || X <- List, X =:= Pivot ]
    ++
    sort(Pivot+1, Max, [ X || X <- List, X > Pivot ]).
環境変数の取得 (Nested Flatten)
環境変数はosモジュールで提供されています。
Keyは引用符でくくった文字列を指定します。
1
2
3
4
5
%%全環境変数の表示
os:getenv().

%% キーを指定した場合
os:getenv(Key).
「組合せ型の最小完全ハッシュ関数」の逆関数 (Nested Flatten)
関数multiple_list/2は,Erlangのlistsモジュールにある関数duplicate/2で置き換え可能ですね.ご参考まで Kenji Rikitake, JJ1BDX
1
2
%% FYI
multiple_list(L,N) -> lists:duplicate(N,L).
ミリ秒まで含んだ時刻文字列 (Nested Flatten)
すみません、寝むくてぐだぐだな感じで。
1
2
3
> {{Y,M,D},{Ho,Mi,Se}}=calendar:now_to_local_time({Mg,S,Ms}=now()).
> element(2,regexp:gsub(lists:flatten(io_lib:format("~4w~2w~2w~2w~2w~2w.~w",[Y,M,D,Ho,Mi,Se,Ms]))," ","0")). 
"20080615141401.573000"
除算・余剰を使わずに閏年 (Nested Flatten)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
-module(leap_year).
-import(lists).
-export([is_leap_year/1]).

list_multiple_of(B,M,[]) ->
    if
        B > M -> [];
        true -> list_multiple_of(B,M,[B])
    end;
list_multiple_of(B,M,L) ->
    C = lists:nth(1,L),
    if
        C + B > M -> L;
        true -> list_multiple_of(B,M,[C + B|L])
    end.

list_leap_year(M) ->
    ((list_multiple_of(4,M,[]) -- list_multiple_of(100,M,[])) ++ list_multiple_of(400,M,[])) -- list_multiple_of(1000,M,[]).

is_leap_year(Y) ->
    length(lists:filter(fun(X) -> X == Y end, list_leap_year(Y))) > 0.
マルバツゲーム:賢いプレイヤー (Nested Flatten)
 Wikipediaの完勝手順を参考に,以下の形で実装してみました。

1. 3マス揃う場合には揃える
2. 敵方にリーチが掛かっている場合には阻止する
3. ダブルリーチが掛けられる場合には掛ける
4. 敵方がダブルリーチを掛けられる場合には,以下の方法で阻止する
4-1. 敵方のダブルリーチを阻止できる形でリーチを掛けられる場合にはリーチを掛ける
4-2. 4-1以外の場合は,直接的にダブルリーチを阻止する
5. 中央が開いていれば中央に置く
6. 敵方の角の反対が空いていれば,その角に置く
7. 角が空いていれば角に置く
8. 1~7のいずれにも該当しない場合には,空いているマスに置く

 以下実行結果です。

1> c(tic_tac_toe).
{ok,tic_tac_toe}
2> tic_tac_toe:start().
first:0,second:8762,draw:1238
ok
3> tic_tac_toe:start({fun tic_tac_toe:clever_choice/2,fun tic_tac_toe:random_choice/2}).
first:9573,second:0,draw:427
ok
4> tic_tac_toe:start({fun tic_tac_toe:clever_choice/2,fun tic_tac_toe:clever_choice/2}).
first:0,second:0,draw:10000
ok
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
-module(tic_tac_toe).
-import(io).
-import(lists).
-import(random).
-export([start/0,start/1,random_choice/2,clever_choice/2]).

create_board() -> lists:map(fun(_) -> 0 end,lists:seq(1,9,1)).

enemy(P) -> P rem 2 + 1.

move(B,1,{C,_}) -> move(B,1,C);
move(B,2,{_,C}) -> move(B,2,C);
move(B,P,C) ->
    PS = C(B,P),
    lists:sublist(B,PS - 1) ++ [P|lists:sublist(B,PS + 1,length(B) - PS)].

check_pattern() ->
    lists:map(fun(X) -> lists:seq(X,X+6,3) end, lists:seq(1,3,1)) ++
    lists:map(fun(X) -> lists:seq(X,X+2,1) end, lists:seq(1,7,3)) ++
    [lists:seq(1,9,4),lists:seq(3,7,2)].

check(B,P) ->
    lists:any(
        fun(PT) ->
            lists:all(
                fun(ST) -> ST == P end,
                lists:map(fun(X) -> lists:nth(X,B) end, PT)
            )
        end,
        check_pattern()
    ).

process(B,P,C) ->
    BN = move(B,P,C),
    R = check(BN,P),
    D = lists:all(fun(ST) -> ST /= 0 end, BN),
    if
        R -> P;
        D -> 0;
        true -> process(BN, enemy(P), C)
    end.

process(C) -> process(create_board(),1,C).

random_choice(B,_) ->
    S = lists:map(fun({PS,_}) -> PS end, lists:filter(fun({_,X}) -> X == 0 end, lists:zip(lists:seq(1,length(B),1),B))),
    lists:nth(random:uniform(length(S)),S).

will_complete(B,P,PL) ->
    lists:filter(
        fun(SL) ->
            (length(lists:filter(fun({_,S}) -> S == P end, SL)) == 2) and
            (length(lists:filter(fun({_,S}) -> S == 0 end, SL)) == 1)
        end,
        lists:map(
            fun(PP) -> lists:map(fun(PS) -> {PS,lists:nth(PS,B)} end, PP) end,
            PL
        )
    ).

proposed_complete(B,P,PL) ->
    lists:map(
        fun(SL) ->
            {PS,_} = lists:nth(1, lists:filter(fun({_,S}) -> S == 0 end, SL)),
            PS
        end,
        will_complete(B,P,PL)
    ).

check_fork(B,P) -> length(will_complete(B,P,check_pattern())) >= 2.

lookahead(F,B,P) ->
    lists:filter(
        F,
        lists:map(
            fun({PT,_}) ->{PT,lists:sublist(B,PT - 1)++[P|lists:sublist(B,PT + 1,length(B) - PT)]} end,
            lists:filter(fun({_,S}) -> S == 0 end, lists:zip(lists:seq(1,9,1),B))
        )
    ).

proposed_fork(B,P,_) ->
    lists:map(
        fun({PS,_}) -> PS end,
        lookahead(fun({_,BP}) -> check_fork(BP,P) end,B,P)
    ).

proposed_block_fork(B,P,PL) ->
    FL = proposed_fork(B,enemy(P),PL),
    F = length(FL),
    if
        F == 0 -> [];
        true ->
            lists:map(
                fun({PS,_}) -> PS end,
                lookahead(
                    fun({_,BP}) ->
                        (length(lists:subtract(proposed_complete(BP,P,check_pattern()),FL)) > 0) or
                        (length(proposed_fork(BP,enemy(P),[])) == 0)
                    end,
                    B,
                    P
                )
            )
    end.

proposed_opposite(B,P,PL) ->
    lists:filter(
        fun(PS) -> lists:nth(PS,B) == 0 end,
        lists:map(
            fun({EP,_}) ->
                {_,OP} =
                    lists:nth(1,
                        lists:filter(
                            fun({CP,_}) -> CP == EP end,
                            lists:zip(PL,lists:map(fun(X) -> 10 -X end, PL))
                        )
                    ),
                OP
            end,
            lists:filter(
                fun({_,S}) -> S == enemy(P) end,
                lists:zip(PL,lists:map(fun(PT) -> lists:nth(PT,B) end, PL))
            )
        )
    ).

proposed_space(B,_,PL) -> lists:filter(fun(PS) -> lists:nth(PS,B) == 0 end, PL).

clever_choice(B,P) ->
    lists:nth(
        1,
        lists:append(
            lists:map(
                fun({F,PP,PL}) -> F(B,PP,PL) end,
                [    {fun proposed_complete/3,P,check_pattern()},
                    {fun proposed_complete/3,enemy(P),check_pattern()},
                    {fun proposed_fork/3,P,[]},
                    {fun proposed_block_fork/3,P,[]},
                    {fun proposed_space/3,0,[5]},
                    {fun proposed_opposite/3,P,[1,3,7,9]},
                    {fun proposed_space/3,0,[1,3,7,9]},
                    {fun proposed_space/3,0,[2,4,6,8]}
                ]
            )
        )
    ).

start(C) ->
    R = lists:map(fun(_) -> process(C) end,lists:seq(1,10000,1)),
    io:format("first:~w,second:~w,draw:~w~n",lists:map(fun(P) -> length(lists:filter(fun(X) -> X == P end, R)) end,[1,2,0])).

start() -> start({fun random_choice/2,fun clever_choice/2}).
マルバツゲーム (Nested Flatten)
 以下実行結果です。

1> c(tic_tac_toe).
{ok,tic_tac_toe}
2> tic_tac_toe:start().
first:5835,second:2957,draw:1208
ok
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
-module(tic_tac_toe).
-import(io).
-import(lists).
-import(random).
-export([start/0]).

create_board() -> lists:map(fun(_) -> 0 end,lists:seq(1,9,1)).

move(B,1,{C,_}) -> move(B,1,C);
move(B,2,{_,C}) -> move(B,2,C);
move(B,P,C) ->
    PS = C(B,P),
    lists:sublist(B,PS - 1) ++ [P|lists:sublist(B,PS + 1,length(B) - PS)].

check_pattern() ->
    lists:map(fun(X) -> lists:seq(X,X+6,3) end, lists:seq(1,3,1)) ++
    lists:map(fun(X) -> lists:seq(X,X+2,1) end, lists:seq(1,7,3)) ++
    [lists:seq(1,9,4),lists:seq(3,7,2)].

check(B,P) ->
    lists:any(
        fun(PT) ->
            lists:all(
                fun(ST) -> ST == P end,
                lists:map(fun(X) -> lists:nth(X,B) end, PT)
            )
        end,
        check_pattern()
    ).

process(B,P,C) ->
    BN = move(B,P,C),
    R = check(BN,P),
    D = lists:all(fun(ST) -> ST /= 0 end, BN),
    if
        R -> P;
        D -> 0;
        true -> process(BN, P rem 2 + 1, C)
    end.

process(C) -> process(create_board(),1,C).

random_choice(B,_) ->
    S = lists:map(fun({PS,_}) -> PS end, lists:filter(fun({_,X}) -> X == 0 end, lists:zip(lists:seq(1,length(B),1),B))),
    lists:nth(random:uniform(length(S)),S).

start() ->
    R = lists:map(fun(_) -> process({fun random_choice/2,fun random_choice/2}) end,lists:seq(1,10000,1)),
    io:format("first:~w,second:~w,draw:~w~n",lists:map(fun(P) -> length(lists:filter(fun(X) -> X == P end, R)) end,[1,2,0])).
next >>

Index

Feed

Other

Link

Pathtraq

loading...