房主可以创建房间,添加问题,激活答题,获取答题情况。。
玩家可以答题。
各个进程之间瞎78传系列:)
(以Kahoot为模板实现的问答toy code)
-module(kaboose). -export([ start/0, get_a_room/1, add_question/2, get_questions/1, play/1, next/1, timesup/1, join/2, leave/2, rejoin/2, guess/3, playerloop/2, add_toDist/2, correct_answer/1 ]). request_reply(Pid,Request) -> Pid ! {self(), Request}, receive {Pid, Reponse} -> Reponse end. async(Pid, Message) -> Pid ! Message. start() -> try Server = spawn(fun() -> serverloop([]) end), {ok, Server} catch _ : _ -> {error,"Failed to crate a server!/n"} end. %for server loop get_a_room(Server) -> request_reply(Server, get_a_room). %for room loop add_question(Room, {Description, Answers}) -> Question = {Description, Answers}, request_reply(Room, {add_question,Question}). get_questions(Room) -> request_reply(Room, get_questions). play(Room) -> request_reply(Room, play). %for activeroom loop next(ActiveRoom) -> request_reply(ActiveRoom,next). timesup(ActiveRoom) -> request_reply(ActiveRoom,timesup). %for player process join(ActiveRoom, NickStr) -> Nick = list_to_atom(NickStr), case request_reply(ActiveRoom,{join,NickStr}) of {ok,{NickStr,has_joined_in,ActiveRoom}} -> Ref = spawn(fun () -> ok,playerloop(Nick,[ActiveRoom]) end), register(Nick, Ref), Conductor = request_reply(ActiveRoom,get_conductor), Active = request_reply(ActiveRoom,get_pslist), % Conductor ! {Conductor, {player_joined, Nick, Active}}, async(Conductor, {Conductor,{player_joined, NickStr, Active}}), {ok,Ref}; {error,NickStr,is_taken} -> {error,NickStr,is_taken} end. leave(ActiveRoom, Ref) -> Nick = request_reply(Ref,getplayer), NickStr = atom_to_list(Nick), case request_reply(ActiveRoom,{leave,NickStr}) of {ok,{NickStr,has_left_from,ActiveRoom}} -> Conductor = request_reply(ActiveRoom,get_conductor), Active = request_reply(ActiveRoom,get_pslist), % Conductor ! {Conductor, {player_left, Nick, Active}}, async(Conductor, {Conductor,{player_left, NickStr, Active}}), request_reply(Ref,leave); {error, {NickStr, is_not_in,From}} -> {error, NickStr, is_not_in,From} end. rejoin(ActiveRoom, Ref) -> Nick = request_reply(Ref,getplayer), NickStr = atom_to_list(Nick), case request_reply(ActiveRoom,{join,NickStr}) of {ok,{NickStr,has_joined_in,ActiveRoom}} -> Conductor = request_reply(ActiveRoom,get_conductor), Active = request_reply(ActiveRoom,get_pslist), async(Conductor, {Conductor,{player_joined, NickStr, Active}}), request_reply(Ref,{rejoin,ActiveRoom}); {error,NickStr,is_taken} -> {error,NickStr,is_taken} end. guess(ActiveRoom, Ref, Index) -> ActiveQuestions = request_reply(ActiveRoom,get_activequestion), Nick = request_reply(Ref,getplayer), NickStr = atom_to_list(Nick), ACRoom = request_reply(Ref,getActiveRoom), case ActiveQuestions of [] -> ok; _ -> case ACRoom of [ActiveRoom] -> request_reply(ActiveRoom,{guess,NickStr,Index}); _ -> {error, NickStr, is_not_in, ActiveRoom} end end. %loops: serverloop(Roomlist) -> receive % Returns {Server, Room} on success or {error, Reason} if some error occured. {From, get_a_room} -> try Room = spawn(fun() -> roomloop([]) end), From ! {self(), {ok, Room}}, serverloop([Room|Roomlist]) catch _:_ -> From ! {self(), {error,"Failed to crate a room!/n"}}, serverloop(Roomlist) end end. roomloop(QuestionList) -> receive {From, {add_question, {Description, Answers} } } -> case is_string(Description) andalso member(fun ({correct, _}) -> true; (_) -> false end, Answers) of true -> From ! {self(), ok}, roomloop(lists:append(QuestionList,[{Description,Answers}])) ; false -> From ! {self(), {error, invalid_question}}, roomloop(QuestionList) end; {From, get_questions} -> From ! {self(), QuestionList}, roomloop(QuestionList); {From, play} -> CRef = From, ActiveRoom = spawn(fun () -> ok,quizloop(CRef,QuestionList,[],[],[],#{},#{}) end),%From becomes a conductor From ! {self(), {ActiveRoom,CRef}}, roomloop(QuestionList) end. quizloop(Conductor, QuestionList, ActiveQuestions, Players, Dist, LastQ, Total) -> % io:format("~n~p~p~p~p~p~p~p~n", % [Conductor, Players, QuestionList, ActiveQuestions, Dist, LastQ, Total]), receive {From, get_activequestion} -> From ! {self(),ActiveQuestions}, quizloop(Conductor,QuestionList,ActiveQuestions,Players, Dist, LastQ, Total); {From, get_conductor} -> From ! {self(),Conductor}, quizloop(Conductor,QuestionList,ActiveQuestions,Players, Dist, LastQ, Total); {From, get_pslist} -> From ! {self(),length(Players)}, quizloop(Conductor,QuestionList,ActiveQuestions,Players, Dist, LastQ, Total); {From, next} -> case From of Conductor -> case ActiveQuestions of [] -> case QuestionList of [] -> From ! {self(), {error, no_left_question}}, quizloop(Conductor,QuestionList,[],Players, Dist, LastQ, Total); _ -> [Question|Leftlist] = QuestionList, {Description,Answers} = Question, From ! {self(), {ok, {Description, Answers}}}, Length = length(Answers), NewDist = lists:duplicate(Length, 0), quizloop(Conductor,Leftlist,[Question],Players, NewDist, LastQ, Total) %change the Dist to list of 0 with right length end; _ -> From ! {self(), {error, has_active_question}}, quizloop(Conductor,QuestionList,ActiveQuestions,Players, Dist, LastQ, Total) end; _ -> From ! {self(), {error, who_are_you,from_is,From,conductor_is,Conductor}}, quizloop(Conductor,QuestionList,ActiveQuestions,Players, Dist, LastQ, Total) end; {From, timesup} -> case (ActiveQuestions =/= []) of true -> Final = QuestionList =:= [], From ! {self(), {ok, Dist, LastQ, Total, Final}}, quizloop(Conductor,QuestionList,[],Players, Dist, #{}, Total); false -> From ! {self(), {error, no_question_asked}}, quizloop(Conductor,QuestionList,[],Players, Dist, LastQ, Total) end; {From, {join, Nick}} -> case lists:member(Nick,Players) of false -> From ! {self(), {ok,{Nick,has_joined_in,self()}}}, quizloop(Conductor,QuestionList,ActiveQuestions,[Nick|Players], Dist, LastQ, Total); true -> From ! {self(), {error, Nick, is_taken}}, quizloop(Conductor,QuestionList,ActiveQuestions,Players, Dist, LastQ, Total) end; {From, {leave, Nick}} -> case lists:member(Nick,Players) of true -> From ! {self(), {ok,{Nick,has_left_from,self()}}}, quizloop(Conductor,QuestionList,ActiveQuestions,lists:delete(Nick,Players), Dist, LastQ, Total); false -> From ! {self(), {error, Nick, is_not_in,self()}}, quizloop(Conductor,QuestionList,ActiveQuestions,Players, Dist, LastQ, Total) end; {From, {guess,Nick,Index}} -> [ActiveQuestion|_] = ActiveQuestions, {_,Answers} = ActiveQuestion, NewDist = add_toDist(Index,Dist), Correct = correct_answer(Answers), case lists:member(Index,Correct) of true -> case maps:is_key(Nick,Total) of true -> OldScore = maps:get(Nick,Total), NewTotal = maps:put(Nick, OldScore+1000, Total),%should have different score standard! NewLastQ = maps:put(Nick,1000,LastQ), From ! {self(),ok}, quizloop(Conductor,QuestionList,ActiveQuestions,Players, NewDist, NewLastQ, NewTotal); false -> NewTotal = maps:put(Nick, 1000, Total),%should have different score standard! NewLastQ = maps:put(Nick,1000,LastQ), From ! {self(),ok}, quizloop(Conductor,QuestionList,ActiveQuestions,Players, NewDist, NewLastQ, NewTotal) end; false -> case maps:is_key(Nick,Total) of true -> NewLastQ = maps:put(Nick,0,LastQ), From ! {self(),ok}, quizloop(Conductor,QuestionList,ActiveQuestions,Players, NewDist, NewLastQ, Total); false -> NewTotal = maps:put(Nick, 0, Total),%should have different score standard! NewLastQ = maps:put(Nick,0,LastQ), From ! {self(),ok}, quizloop(Conductor,QuestionList,ActiveQuestions,Players, NewDist, NewLastQ, NewTotal) end, From ! {self(),ok}, quizloop(Conductor,QuestionList,ActiveQuestions,Players, NewDist, LastQ, Total) end end. playerloop(Nick,ActiveRoom) -> receive {From,getplayer} -> From ! {self(), Nick}, playerloop(Nick,ActiveRoom); {From,getActiveRoom} -> From ! {self(), ActiveRoom}, playerloop(Nick,ActiveRoom); {From,{join,Quiz}} -> From ! {self(), ok}, playerloop(Nick,[Quiz|ActiveRoom]); {From,leave} -> From ! {self(), ok}, playerloop(Nick,[]); {From,{rejoin,Quiz}} -> From ! {self(), ok}, playerloop(Nick,[Quiz|ActiveRoom]); {From,next} -> From ! {self(), {error,i_am_not_the_conductor}}, playerloop(Nick,ActiveRoom) end. % helper functions: is_string([]) -> true; is_string([X|Xs]) -> X >= 0 andalso X < 128 andalso is_string(Xs); is_string(_) -> false. add_toDist(N,Dist) -> lists:sublist(Dist,N-1) ++ [lists:nth(N,Dist)+1] ++ lists:nthtail(N,Dist). position(_, []) -> 0; position(N1,[N1|_]) -> 1; position(N1,[_|Ns]) -> 1 + position(N1,Ns). member(_, []) -> false; member(Pred, [E | List]) -> case Pred(E) of true -> true; false -> member(Pred, List) end. correct_answer(Answers) -> Correct = lists:filter(fun ({correct, _}) -> true; (_) -> false end, Answers), lists:map(fun(X) -> position(X, Answers) end,Correct).