Com o mestre de cerimônias criado no primeiro artigo, e o convidado criado no segundo artigo, podemos rodar o jogo!
O jogo será um novo módulo, mh_game
. Podemos começar pelos cabeçalhos obrigatórios:
-module(mh_game).
-export(play/0, play/1).
-define(ROUNDS, 1000).
-spec play() -> integer().
-spec play(Rounds :: integer()) -> integer().
A macro -define/2
define o número de rodadas em mil. A função play/0
roda o número padrão de rodadas, enquanto play/1
roda um número determinado de rodadas.
Vamos implementar play/0 para rodar o número padrão de rodadas:
play() -> play(?ROUNDS).
Nada mais complexo que isso. Agora play/1
deve ser responsável por 1levantar o mestre de cerimônias, 2rodar a quantidade correta
de rodadas e 3encerrar o processo mestre de cerimônias.
Como precisamos encerrar o processo do mestre de cerimônias, não podemossimplesmente executar a chamada da rodada, ele precisa ignorar os erros para
que mh_mc:stop/1
seja executado em qualquer ocasião:
play(Rounds) ->
mh_mc:start_link(),
case catch play(Rounds, 0) of Response -> Response end,
mh_mc:stop(),
Response.
Agora precisamos da função play/2
, que executará cada rodada.
Sendo uma função recursiva, podemos escrever primeiro a condição de parada,que é quando não há mais rodadas, retornando o acumulador:
play(0, Score) -> Score;
O passo deve executar o seguinte procedimento:
mh_guest:choose/0
);mh_mc:suggest_another_door/1
);mh_guest:change/2
);Segue então o código que executa este procedimento, acrescentando apenas um throw/1
para levantar um exceção caso ocorra um erro:
play(Rounds, Score) when Rounds > 0 ->
FirstChoice = mh_guest:choose(),
{ok, Other} = mh_mc:suggest_another_door(FirstChoice),
Door = mh_guest:change(FirstChoice, Other),
case mh_mc:get_prize(Door) of
{ok, goat} -> play(Rounds - 1, Score);
{ok, car} -> play(Rounds - 1, Score + 1);
Other -> throw(Other)
end.
Compile e rode. Meu resultado foi:
sh$ erlc mh_game.erl
sh$ erl
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:4:4] [async-threads:10]
[hipe] [kernel-poll:false] [dtrace]
Eshell V7.3 (abort with ^G)
1> mh_game:play().
325
2> mh_game:play().
320
3> mh_game:play().
348
4> mh_game:play().
336
5gt;
Não importa quantas vezes rode, fica sempre próximo de 333 acertos em mil,333‰, ou seja 33,3%, uma chance em três.
No entanto, se compilarmos com a flag -Dchange
, o resultado muda radicalmente:
sh$ erlc -Dchange mh_game.erl[br/]
sh$ erl
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:4:4] [async-threads:10]
[hipe] [kernel-poll:false] [dtrace]
Eshell V7.3 (abort with ^G)
1> mh_game:play().
645
2> mh_game:play().
673
3> mh_game:play().
681
3> mh_game:play().
665
4>
Novamente o resultado está sempre por volta do complementar, que são 667acertos em mil, 667‰, 66,7%, duas em três.
Com isso, está provado o Paradoxo de Monty Hall!
Erlang | Functional | Logical