-module(santa). -export([main/0, elf/2, reindeer/2]). -import(io, [fwrite/1, fwrite/2]). -import(random, [uniform/1]). -import(timer, [sleep/1]). -import(lists, [map/2]). %% Elves and Reindeer useGate(Santa, Message) -> Santa ! Message, % Send announcement receive go -> true end. % Await acknowledgement helper(Santa, Message, String, Id) -> useGate(Santa, { Message, self() }), % Announce readiness fwrite(String, [Id]), useGate(Santa, done), % Announce completion sleep( uniform(1000) ), % Snooze helper(Santa, Message, String, Id). % Lather, rinse, repeat elf(Santa, Id) -> helper(Santa, elf, "Elf ~w meeting in the study~n", Id). reindeer(Santa, Id) -> helper(Santa, deer, "Deer ~w delivering toys~n", Id). %% Santa operateGate(Helpers) -> % send 'go' acknowledgement map( (fun (Helper) -> Helper ! go end), Helpers ). waitDone(N) -> if % wait for N 'done' messages N > 0 -> receive done -> true end, waitDone(N-1); true -> true end. doit(String, Helpers) -> % A meeting or toy delivery fwrite("Ho! Ho! Ho! Lets ~s!~n", [String]), operateGate(Helpers), waitDone(length(Helpers)), operateGate(Helpers). handleHelper(N, Helpers, Message) -> % Incoming! if length(Helpers) == N -> doit(Message, Helpers), []; true -> Helpers end. santa(NElves,NDeer, E, D) -> %% The following receive expression implements the requirement %% that the deer be able to starve the elves. Fairness can be %% achieved by removing it. receive {deer, EarlyDeer} -> NED = handleHelper(NDeer, [EarlyDeer|D], "deliver toys"), santa(NElves,NDeer,E,NED) after 0 -> true end, receive {elf, Elf} -> NE = handleHelper(NElves, [Elf|E], "meet in my study"), santa(NElves,NDeer,NE,D); {deer, Deer} -> ND = handleHelper(NDeer, [Deer|D], "deliver toys"), santa(NElves,NDeer,E,ND) end. santa(NElves,NDeer) -> santa(NElves,NDeer, [], []). %% main main() -> [ spawn(santa, elf, [self(), X]) || X <- [1,2,3,4,5,6,7,8,9,10] ], [ spawn(santa, reindeer, [self(), X]) || X <- [1,2,3,4,5,6,7,8,9] ], santa(3,9).