zoukankan      html  css  js  c++  java
  • Erlang实现的模拟kaboose(山寨kahoot)

    房主可以创建房间,添加问题,激活答题,获取答题情况。。

    玩家可以答题。

    各个进程之间瞎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).
    

      

  • 相关阅读:
    linux下互相传文件的快捷方法
    c语言学习笔记.内存管理.
    c语言学习笔记.结构体.
    格雷码
    c语言学习笔记.指针.
    c语言学习笔记.数组.
    c语言学习笔记.关键字.存储类型关键字等
    leetcode.C.4. Median of Two Sorted Arrays
    Verilog笔记.6.FIFO
    Verilog笔记.5.同步、异步
  • 原文地址:https://www.cnblogs.com/hanani/p/9981214.html
Copyright © 2011-2022 走看看