「ダイスを 30 個同時に振って、すべて 1 の目が出たら負け」をやろうとして失敗した

30分プログラム、その598。「ダイスを 30 個同時に振って、すべて 1 の目が出たら負け」をやろうとして失敗した。これだと確実に死にます。

  1. 今日はErlangでやろう
  2. Erlangだからプロセスを鬼のように作りたいな。そうだダイスをプロセスで表現しよう!
  3. 乱数はプロセスごとに状態を持つので、常に同じ値が生成される
  4. 常に1の目のでるダイスが完成! <- イマココ

使い方

% 30個のダイスでチャレンジ
1> dice:start(30).
=== 1th try ===
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
dice is 1
1

ソースコード

-module(dice).
-compile([export_all]).

dice(Pid) ->
    N = random:uniform(6),
    io:format("dice is ~p~n",[N]),
    Pid ! {dice,N}.

times(0,_) ->
    undefined;
times(1,F) ->
    F();
times(N,F) ->
    F(),
    times(N-1,F).

eat()->
    receive
	_ ->
	    eat()
    after 0 ->
	    ate
    end.

is_all_one(0)->
    true;
is_all_one(Count)->
    receive
      {dice,1} ->
	    is_all_one(Count-1);
	_ ->
	    eat(),
	    false
    end.

try_roll(N)->
    Self = self(),
    times(N,fun () -> spawn(fun() -> dice(Self) end) end),
    is_all_one(N).

count_tries(Count,N)->
    io:format("=== ~pth try ===~n",[Count]),
    case try_roll(N) of
	true ->
	    Count;
	_ ->
	    count_tries(Count+1,N)
    end.

start(N) ->
    count_tries(1,N).