Language detail: Erlang
Coverage: 51.85%
|
number of '+' ratings |
contribution for coverage |
Unsolved challenges
- echoクライアント (Nested Flatten)
- LL Golf Hole 4 - 文章から単語の索引を作る (Nested Flatten)
- tailの実装 (Nested Flatten)
- lessの実装 (Nested Flatten)
- 2次元ランダムウォーク (Nested Flatten)
codes
LL Golf Hole 8 - 横向きのピラミッドを作る
(Nested
Flatten)
#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 のようにして起動します。
see: Erlangのevalってこうやるのか
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
see: Wikipedia
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)
next >>
以下実行結果です。
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])).
|





匿名
#7504()
[
Erlang
]
Rating0/0=0.00
-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)].Rating0/0=0.00-0+
[ reply ]