From bcd5d51bf419eec60a5ab95c94fe1079c5b7898d Mon Sep 17 00:00:00 2001 From: MarcoTomasone Date: Tue, 25 Apr 2023 12:28:01 +0200 Subject: [PATCH 01/18] [ADD] Started ambient actor w/@Lucajett99 @minosse99 --- Actors/ambient.erl | 31 +++++++++++++++++++++++++++++++ Actors/car.erl | 19 +++++++++++++++++++ Actors/render.erl | 0 Actors/wellknown.erl | 0 4 files changed, 50 insertions(+) create mode 100644 Actors/ambient.erl create mode 100644 Actors/car.erl create mode 100644 Actors/render.erl create mode 100644 Actors/wellknown.erl diff --git a/Actors/ambient.erl b/Actors/ambient.erl new file mode 100644 index 0000000..dfe8b02 --- /dev/null +++ b/Actors/ambient.erl @@ -0,0 +1,31 @@ +%Un attore ambiente omniscente che rappresenta lo stato reale del mondo. In particolare l'ambiente conosce per ogni cella/posteggio il suo stato (libero o occupato). +% L'atomo ambient è registrato come PID dell'attore. +% +-module(ambient). + -export([main/2, ambient/1]). + + ambient(Chessboard) -> + receive + {isFree, PID, X, Y, Ref} -> %Request a car sends to the ambient + io:format("Request from ~p for parking (~p,~p)~n",[PID,X,Y]), %DEBUG + PID ! {status, Ref, lists:member({X, Y, undefined}, Chessboard)}, %Reply to the car + io:format("Parking (~p,~p) is free: ~p~n", [X,Y, lists:member({X, Y, undefined}, Chessboard)]); %DEBUG + {park, PID, X, Y, Ref} -> io:fwrite("DEFAULT\n"); %Update parkings + %{X, Y, undefined } -> {X,Y,PID} Substitution to be done in the list + {leave, PID, Ref} -> io:fwrite("DEFAULT2\n"); %Update parkings + %{_,_, PID} -> {_,_, undefined} Substitution to be done in the list + _ -> io:fwrite("DEFAULT3\n") + end, + ambient(Chessboard). % Loop TODO: check if it's ok here or to be setted at the end of each receive block + + print_list([])-> ok; + print_list([H|T]) -> + io:format("printing: ~p~n", [H]), + print_list(T). + + main(H, W) -> + Chessboard = [{X, Y, undefined} || X <- lists:seq(1, H), Y <- lists:seq(1, W)], %define a chessboard + print_list(Chessboard), + PIDA = spawn(?MODULE, ambient, [Chessboard]), %spawn the ambient actor + io:format("Ambient PID: ~p~n", [PIDA]). %DEBUG + %PIDA ! {isFree, self(), 1, 1, 1}. %DEBUG \ No newline at end of file diff --git a/Actors/car.erl b/Actors/car.erl new file mode 100644 index 0000000..a9502c0 --- /dev/null +++ b/Actors/car.erl @@ -0,0 +1,19 @@ +-module(car). + -export([main/0]). + + %The main actor creates other actors and re-creates them if they fail + main() -> + F = spawn(). + + friendship() -> + io:fwrite("CIAO\n"). + + state() -> + io:fwrite("CIAO\n"). + + detect() -> + io:fwrite("CIAO\n"). + + + + diff --git a/Actors/render.erl b/Actors/render.erl new file mode 100644 index 0000000..e69de29 diff --git a/Actors/wellknown.erl b/Actors/wellknown.erl new file mode 100644 index 0000000..e69de29 From ff1fa9b941e31bb24bb8e6d40e259321094d9ccb Mon Sep 17 00:00:00 2001 From: MarcoTomasone Date: Wed, 26 Apr 2023 13:39:58 +0200 Subject: [PATCH 02/18] [FIX] Converted list to dict in ambient w/ @minosse99 @Lucajett99 --- Actors/ambient.erl | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Actors/ambient.erl b/Actors/ambient.erl index dfe8b02..b0dbc37 100644 --- a/Actors/ambient.erl +++ b/Actors/ambient.erl @@ -18,14 +18,16 @@ end, ambient(Chessboard). % Loop TODO: check if it's ok here or to be setted at the end of each receive block - print_list([])-> ok; - print_list([H|T]) -> - io:format("printing: ~p~n", [H]), - print_list(T). + %Function to print each element of dict + printDict(Dict) -> + io:fwrite("Dict:~n"), + dict:fold(fun(K, V, Acc) -> io:fwrite("Key ~p : Value: ~p~n", [K, V]), Acc end, [], Dict). + main(H, W) -> - Chessboard = [{X, Y, undefined} || X <- lists:seq(1, H), Y <- lists:seq(1, W)], %define a chessboard - print_list(Chessboard), + Chessboard = dict:from_list([{{X, Y}, undefined} || X <- lists:seq(1, H), Y <- lists:seq(1, W)]), + printDict(Chessboard), %DEBUG + io:format("Chessboard size ~p~n", [dict:size(Chessboard)]), PIDA = spawn(?MODULE, ambient, [Chessboard]), %spawn the ambient actor io:format("Ambient PID: ~p~n", [PIDA]). %DEBUG %PIDA ! {isFree, self(), 1, 1, 1}. %DEBUG \ No newline at end of file From ce69ac223d7cfabe8eabdad0f1638f07c3e814af Mon Sep 17 00:00:00 2001 From: MarcoTomasone Date: Wed, 26 Apr 2023 14:29:52 +0200 Subject: [PATCH 03/18] [ADD] Ended Ambient actor w/@minosse99 @Lucajett99 --- Actors/ambient.erl | 50 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/Actors/ambient.erl b/Actors/ambient.erl index b0dbc37..4eea19d 100644 --- a/Actors/ambient.erl +++ b/Actors/ambient.erl @@ -8,26 +8,52 @@ receive {isFree, PID, X, Y, Ref} -> %Request a car sends to the ambient io:format("Request from ~p for parking (~p,~p)~n",[PID,X,Y]), %DEBUG - PID ! {status, Ref, lists:member({X, Y, undefined}, Chessboard)}, %Reply to the car - io:format("Parking (~p,~p) is free: ~p~n", [X,Y, lists:member({X, Y, undefined}, Chessboard)]); %DEBUG - {park, PID, X, Y, Ref} -> io:fwrite("DEFAULT\n"); %Update parkings - %{X, Y, undefined } -> {X,Y,PID} Substitution to be done in the list - {leave, PID, Ref} -> io:fwrite("DEFAULT2\n"); %Update parkings - %{_,_, PID} -> {_,_, undefined} Substitution to be done in the list + PID ! {status, Ref, undefined =:= dict:fetch({X,Y}, Chessboard)}, %Reply to the car + io:format("Parking (~p,~p) is free: ~p~n", [X,Y, undefined =:= dict:fetch({X,Y}, Chessboard)]), %DEBUG + ambient(Chessboard); + {park, PID, X, Y, Ref} -> + io:fwrite("Update Value for park ~p occupied by ~p~n", [{X,Y}, PID]), %Update parkings + ambient(dict:store({X,Y}, PID, Chessboard)); + {leave, PID, Ref} -> + io:fwrite("PID ~p exit from parking ~n", [PID]), %Update parkings + case searchKey(Chessboard, PID) of + {X, Y} -> + io:fwrite("Update Value for leave ~p free~n", [{X,Y}]), %Update parkings + ambient(dict:store({X,Y}, undefined, Chessboard)); + [] -> + io:fwrite("PID: ~p not parked before ~n", [PID]), + ambient(Chessboard) + end; _ -> io:fwrite("DEFAULT3\n") - end, - ambient(Chessboard). % Loop TODO: check if it's ok here or to be setted at the end of each receive block + end. + %%%%%% + %@params Dict: dict to print %Function to print each element of dict + %@dev: the fold function is used to iterate over the dict, the order of the elements is not guaranteed + % fold function takes as parameters a function, an accumulator and a dict printDict(Dict) -> io:fwrite("Dict:~n"), dict:fold(fun(K, V, Acc) -> io:fwrite("Key ~p : Value: ~p~n", [K, V]), Acc end, [], Dict). - + %%%%%% + %@params Dict: dict to search + %@params Value: value used search the key + %@return Key: key of the dict that has the value passed as parameter + %@dev: this function can return a key {X,Y} if the value exist in the dict or [] if the value doesn't exist + searchKey(Dict, Value) -> + dict:fold(fun(K, V, Acc) -> + case V of + Value -> K; + _ -> Acc + end + end, [], Dict). + + main(H, W) -> Chessboard = dict:from_list([{{X, Y}, undefined} || X <- lists:seq(1, H), Y <- lists:seq(1, W)]), printDict(Chessboard), %DEBUG io:format("Chessboard size ~p~n", [dict:size(Chessboard)]), - PIDA = spawn(?MODULE, ambient, [Chessboard]), %spawn the ambient actor - io:format("Ambient PID: ~p~n", [PIDA]). %DEBUG - %PIDA ! {isFree, self(), 1, 1, 1}. %DEBUG \ No newline at end of file + PID_A = spawn(?MODULE, ambient, [Chessboard]), %spawn the ambient actor + io:format("Ambient PID: ~p~n", [PID_A]). %DEBUG + \ No newline at end of file From 6642d603189e24181cffc1c9229f589d4bbdb42a Mon Sep 17 00:00:00 2001 From: minosse99 Date: Wed, 26 Apr 2023 16:56:11 +0200 Subject: [PATCH 04/18] starting render.erl --- Actors/ambient.erl | 11 ++++++---- Actors/render.erl | 53 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/Actors/ambient.erl b/Actors/ambient.erl index b0dbc37..b135aba 100644 --- a/Actors/ambient.erl +++ b/Actors/ambient.erl @@ -26,8 +26,11 @@ main(H, W) -> Chessboard = dict:from_list([{{X, Y}, undefined} || X <- lists:seq(1, H), Y <- lists:seq(1, W)]), - printDict(Chessboard), %DEBUG - io:format("Chessboard size ~p~n", [dict:size(Chessboard)]), + %printDict(Chessboard), %DEBUG + %io:format("Chessboard size ~p~n", [dict:size(Chessboard)]), PIDA = spawn(?MODULE, ambient, [Chessboard]), %spawn the ambient actor - io:format("Ambient PID: ~p~n", [PIDA]). %DEBUG - %PIDA ! {isFree, self(), 1, 1, 1}. %DEBUG \ No newline at end of file + io:format("Ambient PID: ~p~n", [PIDA]), %DEBUG + R = spawn(render, main, []), + %register(render, R), + R ! {Chessboard}. %DEBUG + %PIDA ! {isFree, self(), 1, 1, 1}. %DEBUG \ No newline at end of file diff --git a/Actors/render.erl b/Actors/render.erl index e69de29..52aa3e7 100644 --- a/Actors/render.erl +++ b/Actors/render.erl @@ -0,0 +1,53 @@ +%Render actors rapresent the ambient at the moment of the request. They are used to show the current state of the ambient to the user. +%Show in ASCII ART the ambient + +% Path: Actors\render.erl +% Compare this snippet from Actors\ambient.erl: + +-module(render). +-export([main/0,order_chessboard/1]). + +print([{{X,Y}, STATUS} | Tail],N)-> + case X == N of + true -> + case STATUS == undefined of + true -> + io:fwrite("O "); + false -> + io:fwrite("X ") + end, + print(Tail,N); + false -> + io:format("~n"), + print(Tail,N+1) + end; + +print([],_)-> ok. + + + +order_chessboard(Chessboard) -> + lists:sort(fun({{X1,Y1},_}, {{X2,Y2},_}) -> + case X1 < X2 of + true -> true; + false -> + case X1 == X2 of + true -> Y1 < Y2; + false -> false + end + end + end, + dict:to_list(Chessboard)). + +main() -> + receive + {Chess} -> + %io:fwrite("Chessboard:~n"), + L = order_chessboard(Chess), + %io:format("~p ~n",[L]), + %io:format("Chessboard ~p~n", [list:sort(list:to_list(Chess))]), + %print([L],1), + print(L,1) + %io:fwrite("DIOCANE~n") + %main() + end. From 3acfa13b20079816b9350a8841e67c5865cfaf8f Mon Sep 17 00:00:00 2001 From: MarcoTomasone Date: Wed, 26 Apr 2023 16:58:06 +0200 Subject: [PATCH 05/18] [UPDATE] update car module --- Actors/ambient.erl | 6 ++- Actors/car.erl | 100 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 99 insertions(+), 7 deletions(-) diff --git a/Actors/ambient.erl b/Actors/ambient.erl index 4eea19d..66cf0e1 100644 --- a/Actors/ambient.erl +++ b/Actors/ambient.erl @@ -49,11 +49,13 @@ end end, [], Dict). - main(H, W) -> Chessboard = dict:from_list([{{X, Y}, undefined} || X <- lists:seq(1, H), Y <- lists:seq(1, W)]), printDict(Chessboard), %DEBUG io:format("Chessboard size ~p~n", [dict:size(Chessboard)]), PID_A = spawn(?MODULE, ambient, [Chessboard]), %spawn the ambient actor - io:format("Ambient PID: ~p~n", [PID_A]). %DEBUG + io:format("Ambient PID: ~p~n", [PID_A]), %DEBUG + register(ambient, PID_A), %register the ambient actor with the name ambient + io:format("Correctly registered ~p as 'ambient' ~n", [PID_A]). %DEBUG + \ No newline at end of file diff --git a/Actors/car.erl b/Actors/car.erl index a9502c0..0fcde3c 100644 --- a/Actors/car.erl +++ b/Actors/car.erl @@ -1,18 +1,108 @@ -module(car). - -export([main/0]). + -export([main/2]). %The main actor creates other actors and re-creates them if they fail - main() -> - F = spawn(). + main_car(H, W) -> + {X_Spawn, Y_Spawn} = generate_coordinates(H, W), + {X_Goal, Y_Goal} = generate_coordinates(H, W), + PID_S = spawn(?MODULE, state, []), + PID_D = spawn(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W]), + PID_F = spawn(?MODULE, friendship, []). + %TODO: handling respawn friendship() -> io:fwrite("CIAO\n"). state() -> + io:fwrite("CIAO\n"). - detect() -> - io:fwrite("CIAO\n"). + generate_coordinates(H, W) -> + X = random:uniform(H), + Y = random:uniform(W), + {X, Y}. + +%L'attore "detect" di un'automobile sceglie un posteggio obiettivo libero interagendo con l'attore "state". Dopodichè, ogni 2s, si avvicina di una cella verso tale obiettivo. Se deve muoversi lungo entrambi gli assi (x e y), lo fa scegliendo randomicamente l'asse e muovendosi nella direzione che minimizza la distanza percorsa. + + %%%% + % @param X: actual X coordinate of the car + % @param X_Goal: X coordinate of the goal + % @param H: height of the chessboard + % @return: 1 or -1 + % @dev: This function computes the movement along the X axis that minimizes the distance to the goal. + % If the distance is the same, the function returns 1. Since pacman effect is allowed (the car can move from the last cell to the + % first one and viceversa), the function must consider the modulo operation. + compute_X_movement(X, X_Goal, H) -> + D_pos = abs(X_Goal - ((X+1) rem H)), + D_neg = abs(X_Goal - ((X-1) rem H)), + case D_pos =< D_neg of + true -> 1; + false -> -1 + end. + + %%%% + % @param Y: actual Y coordinate of the car + % @param Y_Goal: Y coordinate of the goal + % @param W: width of the chessboard + % @return: 1 or -1 + % @dev: This function computes the movement along the Y axis that minimizes the distance to the goal. + % If the distance is the same, the function returns 1. Since pacman effect is allowed (the car can move from the last cell to the + % first one and viceversa), the function must consider the modulo operation. + compute_Y_movement(Y, Y_Goal, W) -> + D_pos = abs(Y_Goal - ((Y+1) rem W)), + D_neg = abs(Y_Goal - ((Y-1) rem W)), + case D_pos =< D_neg of + true -> 1; + false -> -1 + end. + + %%%% + % @param X: actual X coordinate of the car + % @param Y: actual Y coordinate of the car + % @param X_Goal: X coordinate of the goal + % @param Y_Goal: Y coordinate of the goal + % @param H: height of the chessboard + % @param W: width of the chessboard + % @return: {X,Y} coordinates of the next cell + % @dev: This function computes the next cell to reach the goal. + % If the car is already in the goal this function sends the message "park" to the ambient actor. + % If the car is not in the goal, the function computes the next cell to reach the goal. + % If the car is not in the goal and it must move along both the axes, the function chooses randomly the axis and the direction. + move(X, Y, {X_Goal, Y_Goal}, H, W) -> + case X =:= X_Goal andalso Y =:= Y_Goal of + true -> + Park_ref = make_ref(), + ambient ! {park, self(), X, Y, Park_ref}, %TODO: we must ask isFree before parking? + timer:sleep(random:uniform(5)*1000), + ambient ! {leave, self(), Park_ref}, + %TODO: ask new goal + {X, Y}; + false -> + case X =:= X_Goal of + true -> {X, (Y + compute_Y_movement(Y, Y_Goal, W)) rem W}; + false -> + case Y =:= Y_Goal of + true -> {(X + compute_X_movement(X, X_Goal, H)) rem H, Y}; + false -> + case random:uniform(2) of + 1 -> {(X + compute_X_movement(X, X_Goal, H)) rem H, Y}; + 2 -> {X, (Y + compute_Y_movement(Y, Y_Goal, W)) rem W} + end + end + end + end. + + %%%%%% + %@param X: actual X coordinate of the car + %@param Y: actual Y coordinate of the car + % + detect(X, Y, X_Goal, Y_Goal, H, W) -> + {X_New, Y_New} = move(X, Y, Obj_Park, H, W), %TODO: H and W must be passed as parameters? + ambient ! {isFree, self(), X_New, Y_New, make_ref()}, + timer:sleep(2000), + detect(X_New, Y_New, X_Goal, Y_Goal, H, W). + + From 9271cdd7cc8912b22992562e9f1c5c25a4a4b56f Mon Sep 17 00:00:00 2001 From: MarcoTomasone Date: Thu, 27 Apr 2023 12:15:13 +0200 Subject: [PATCH 06/18] [ADD] Minor update render & ambient --- Actors/ambient.erl | 23 ++++++++++++++++------ Actors/car.erl | 48 ++++++++++++++++++++++++++++++++++++++-------- Actors/render.erl | 40 +++++++++++++++++++------------------- 3 files changed, 77 insertions(+), 34 deletions(-) diff --git a/Actors/ambient.erl b/Actors/ambient.erl index b11f29c..bf7d525 100644 --- a/Actors/ambient.erl +++ b/Actors/ambient.erl @@ -2,7 +2,8 @@ % L'atomo ambient è registrato come PID dell'attore. % -module(ambient). - -export([main/2, ambient/1]). +-export([main/2, ambient/1]). +-define(W, 5). ambient(Chessboard) -> receive @@ -24,7 +25,11 @@ io:fwrite("PID: ~p not parked before ~n", [PID]), ambient(Chessboard) end; - _ -> io:fwrite("DEFAULT3\n") + draw -> + io:fwrite("Entered Draw ~n"), %DEBUG + render ! {dict:to_list(Chessboard)}, + ambient(Chessboard); %DEBUG + _ -> io:fwrite("No Pattern Matching Found!\n") end. %%%%%% @@ -50,13 +55,19 @@ end, [], Dict). main(H, W) -> + %Chessboard Definition Chessboard = dict:from_list([{{X, Y}, undefined} || X <- lists:seq(1, H), Y <- lists:seq(1, W)]), printDict(Chessboard), %DEBUG io:format("Chessboard size ~p~n", [dict:size(Chessboard)]), + + %Spawn the render actor + PID_R = spawn(render, main, []), + register(render, PID_R), + io:format("Correctly registered ~p as 'render' ~n", [PID_R]), %DEBUG + render ! {dict:to_list(Chessboard)}, %DEBUG + + %Spawn ambient actor PID_A = spawn(?MODULE, ambient, [Chessboard]), %spawn the ambient actor io:format("Ambient PID: ~p~n", [PID_A]), %DEBUG register(ambient, PID_A), %register the ambient actor with the name ambient - io:format("Correctly registered ~p as 'ambient' ~n", [PID_A]), %DEBUG - R = spawn(render, main, []), - %register(render, R), - R ! {Chessboard}. %DEBUG + io:format("Correctly registered ~p as 'ambient' ~n", [PID_A]). %DEBUG diff --git a/Actors/car.erl b/Actors/car.erl index ca59f04..76e69a9 100644 --- a/Actors/car.erl +++ b/Actors/car.erl @@ -5,17 +5,42 @@ main_car(H, W) -> {X_Spawn, Y_Spawn} = generate_coordinates(H, W), {X_Goal, Y_Goal} = generate_coordinates(H, W), - PID_S = spawn(?MODULE, state, []), - PID_D = spawn(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W]), + %PID_S receive a dict with all the free parking + PID_S = spawn(?MODULE, state, [dict:from_list([{{X, Y}, true} || X <- lists:seq(1, H), Y <- lists:seq(1, W)]), X_Goal, Y_Goal, H, W]), + PID_D = spawn(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W, PID_S]), PID_F = spawn(?MODULE, friendship, []). %TODO: handling respawn friendship() -> io:fwrite("CIAO\n"). - state() -> - - io:fwrite("CIAO\n"). + state(World_Knowledge, X_Goal, Y_Goal, H, W) -> + receive + {updateState, PID_D, X, Y, isFree} -> + io:fwrite("Update Value for park (~p,~p), new value: ~p~n", [{X,Y}, isFree]), %Update parkings + %TODO: send the new info to friends + case isFree of + %If a park becames free, the state actor updates the knowledge of the world + %It doesn't update the goal coordinates because this case doesn't affect s + true -> + state(dict:store({X,Y}, isFree, World_Knowledge), X_Goal, Y_Goal, H, W); + %If a park becames busy I have to check if it was the goal + false -> + case {X=:=X_Goal, Y =:= Y_Goal} of + %If the goal is busy, I have to generate a new goal + {true,true} -> + io:fwrite("New Goal: ~p~n", [{X,Y}]), + {X_Goal_New, Y_Goal_New} = generate_coordinates(H, W), + PID_D ! {updateGoal, X_Goal_New, Y_Goal_New}, + state(dict:store({X,Y}, isFree, World_Knowledge), X_Goal_New, Y_Goal_New, H, W); + %Else update the knowledge of the world + {_,_} -> + state(dict:store({X,Y}, isFree, World_Knowledge), X_Goal, Y_Goal, H, W) + end + end, + state(dict:store({X,Y}, isFree, World_Knowledge), X_Goal, Y_Goal, H, W) + end, + state(World_Knowledge, X_Goal, Y_Goal, H, W). generate_coordinates(H, W) -> X = random:uniform(H), @@ -96,11 +121,18 @@ %@param X: actual X coordinate of the car %@param Y: actual Y coordinate of the car % - detect(X, Y, X_Goal, Y_Goal, H, W) -> - {X_New, Y_New} = move(X, Y, Obj_Park, H, W), %TODO: H and W must be passed as parameters? + detect(X, Y, X_Goal, Y_Goal, H, W, PID_S) -> + {X_New, Y_New} = move(X, Y, {X_Goal, Y_Goal}, H, W), %TODO: H and W must be passed as parameters? ambient ! {isFree, self(), X_New, Y_New, make_ref()}, + receive + {status, Ref, isFree} -> + PID_S ! {updateState, self(), X_New, Y_New, isFree} + %TODO: If i'm in goal wait the status of the goal from the ambient else + %{updateGoal, X_Goal_New, Y_Goal_New} -> + %detect(X_New, Y_New, X_Goal_New, Y_Goal_New, H, W, PID_S); + end, timer:sleep(2000), - detect(X_New, Y_New, X_Goal, Y_Goal, H, W). + detect(X_New, Y_New, X_Goal, Y_Goal, H, W, PID_S). diff --git a/Actors/render.erl b/Actors/render.erl index 52aa3e7..06b9c69 100644 --- a/Actors/render.erl +++ b/Actors/render.erl @@ -1,29 +1,33 @@ -%Render actors rapresent the ambient at the moment of the request. They are used to show the current state of the ambient to the user. +%Render actors represent the ambient at the moment of the request. They are used to show the current state of the ambient to the user. %Show in ASCII ART the ambient % Path: Actors\render.erl -% Compare this snippet from Actors\ambient.erl: - -module(render). --export([main/0,order_chessboard/1]). +-export([main/0, order_chessboard/1]). -print([{{X,Y}, STATUS} | Tail],N)-> +print_chessboard([{{X,Y}, STATUS} | Tail],N)-> case X == N of true -> case STATUS == undefined of true -> - io:fwrite("O "); - false -> - io:fwrite("X ") + io:format("O\t"); + false -> + io:format("X\t") end, - print(Tail,N); + print_chessboard(Tail,N); false -> io:format("~n"), - print(Tail,N+1) + print_chessboard([{{X,Y}, STATUS} | Tail],N+1) end; -print([],_)-> ok. +print_chessboard([],_)-> ok. + +%Function to print a list +print_list([H|T]) -> + io:fwrite("~p~n", [H]), + print_list(T); +print_list([]) -> ok. order_chessboard(Chessboard) -> @@ -37,17 +41,13 @@ order_chessboard(Chessboard) -> end end end, - dict:to_list(Chessboard)). + Chessboard). main() -> receive - {Chess} -> - %io:fwrite("Chessboard:~n"), + {Chess} -> + timer:sleep(3000), %Just to wait the print of the Chess Parameter TODO: find a better solution to do thiss L = order_chessboard(Chess), - %io:format("~p ~n",[L]), - %io:format("Chessboard ~p~n", [list:sort(list:to_list(Chess))]), - %print([L],1), - print(L,1) - %io:fwrite("DIOCANE~n") - %main() + print_chessboard(L,1), + main() end. From bdba7a93309da07d46254f4f89129d74eaba5de0 Mon Sep 17 00:00:00 2001 From: MarcoTomasone Date: Fri, 5 May 2023 12:48:33 +0200 Subject: [PATCH 07/18] Changes to State and Detect car; Update render Coauthored: @minosse99 @Lucajett99 --- Actors/ambient.erl | 2 +- Actors/car.erl | 82 +++++++++++++++++++++++++--------------------- Actors/render.erl | 46 +++++++++++++------------- 3 files changed, 69 insertions(+), 61 deletions(-) diff --git a/Actors/ambient.erl b/Actors/ambient.erl index bf7d525..76ab9dc 100644 --- a/Actors/ambient.erl +++ b/Actors/ambient.erl @@ -61,7 +61,7 @@ io:format("Chessboard size ~p~n", [dict:size(Chessboard)]), %Spawn the render actor - PID_R = spawn(render, main, []), + PID_R = spawn(render, main, [[{X, Y} || X <- lists:seq(1, H), Y <- lists:seq(1, W)], dict:new()]), register(render, PID_R), io:format("Correctly registered ~p as 'render' ~n", [PID_R]), %DEBUG render ! {dict:to_list(Chessboard)}, %DEBUG diff --git a/Actors/car.erl b/Actors/car.erl index 76e69a9..f9c24db 100644 --- a/Actors/car.erl +++ b/Actors/car.erl @@ -5,8 +5,8 @@ main_car(H, W) -> {X_Spawn, Y_Spawn} = generate_coordinates(H, W), {X_Goal, Y_Goal} = generate_coordinates(H, W), - %PID_S receive a dict with all the free parking - PID_S = spawn(?MODULE, state, [dict:from_list([{{X, Y}, true} || X <- lists:seq(1, H), Y <- lists:seq(1, W)]), X_Goal, Y_Goal, H, W]), + %PID_S receive an empty dict() + PID_S = spawn(?MODULE, state, [dict:new(), X_Goal, Y_Goal, H, W]), PID_D = spawn(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W, PID_S]), PID_F = spawn(?MODULE, friendship, []). %TODO: handling respawn @@ -16,7 +16,7 @@ state(World_Knowledge, X_Goal, Y_Goal, H, W) -> receive - {updateState, PID_D, X, Y, isFree} -> + {updateState, PID_D, X, Y, isFree} -> io:fwrite("Update Value for park (~p,~p), new value: ~p~n", [{X,Y}, isFree]), %Update parkings %TODO: send the new info to friends case isFree of @@ -36,11 +36,15 @@ %Else update the knowledge of the world {_,_} -> state(dict:store({X,Y}, isFree, World_Knowledge), X_Goal, Y_Goal, H, W) - end - end, - state(dict:store({X,Y}, isFree, World_Knowledge), X_Goal, Y_Goal, H, W) - end, - state(World_Knowledge, X_Goal, Y_Goal, H, W). + end + end; + %Case Car Exit from the parking and needs new goal + {askNewGoal, PID_D, Ref} -> + {X_Goal_New, Y_Goal_New} = generate_coordinates(H, W), %TODO: check if new coordinates I generate should be free? + PID_D ! {responseNewGoal, X_Goal_New, Y_Goal_New, Ref}; + + _ -> state( World_Knowledge, X_Goal, Y_Goal, H, W) + end. generate_coordinates(H, W) -> X = random:uniform(H), @@ -94,45 +98,49 @@ % If the car is not in the goal, the function computes the next cell to reach the goal. % If the car is not in the goal and it must move along both the axes, the function chooses randomly the axis and the direction. move(X, Y, {X_Goal, Y_Goal}, H, W) -> - case X =:= X_Goal andalso Y =:= Y_Goal of - true -> - Park_ref = make_ref(), - ambient ! {park, self(), X, Y, Park_ref}, %TODO: we must ask isFree before parking? - timer:sleep(random:uniform(5)*1000), - ambient ! {leave, self(), Park_ref}, - %TODO: ask new goal + + case {X =:= X_Goal, Y =:= Y_Goal} of + {true, true} -> {X, Y}; - false -> - case X =:= X_Goal of - true -> {X, (Y + compute_Y_movement(Y, Y_Goal, W)) rem W}; - false -> - case Y =:= Y_Goal of - true -> {(X + compute_X_movement(X, X_Goal, H)) rem H, Y}; - false -> - case random:uniform(2) of - 1 -> {(X + compute_X_movement(X, X_Goal, H)) rem H, Y}; - 2 -> {X, (Y + compute_Y_movement(Y, Y_Goal, W)) rem W} - end - end + {true, false}-> + {X, (Y + compute_Y_movement(Y, Y_Goal, W)) rem W}; + {false, true} -> + {(X + compute_X_movement(X, X_Goal, H)) rem H, Y}; + {false, false} -> + case random:uniform(2) of + 1 -> {(X + compute_X_movement(X, X_Goal, H)) rem H, Y}; + 2 -> {X, (Y + compute_Y_movement(Y, Y_Goal, W)) rem W} end - end. - + end. %%%%%% %@param X: actual X coordinate of the car %@param Y: actual Y coordinate of the car % detect(X, Y, X_Goal, Y_Goal, H, W, PID_S) -> + %Check if we are on goal + timer:sleep(2000), {X_New, Y_New} = move(X, Y, {X_Goal, Y_Goal}, H, W), %TODO: H and W must be passed as parameters? - ambient ! {isFree, self(), X_New, Y_New, make_ref()}, + render ! + Ref = make_ref(), + ambient ! {isFree, self(), X_New, Y_New, Ref}, receive + {updateGoal, X_Goal_New, Y_Goal_New} -> detect(X_New, Y_New, X_Goal_New, Y_Goal_New, H, W, PID_S); {status, Ref, isFree} -> - PID_S ! {updateState, self(), X_New, Y_New, isFree} - %TODO: If i'm in goal wait the status of the goal from the ambient else - %{updateGoal, X_Goal_New, Y_Goal_New} -> - %detect(X_New, Y_New, X_Goal_New, Y_Goal_New, H, W, PID_S); - end, - timer:sleep(2000), - detect(X_New, Y_New, X_Goal, Y_Goal, H, W, PID_S). + PID_S ! {updateState, self(), X_New, Y_New, isFree}, + case {X_New =:= X_Goal, Y_New =:= Y_Goal} of + {true, true} -> + Park_Ref = make_ref(), + ambient ! {park, self(), X_New, Y_New, Park_Ref}, + timer:sleep(random:uniform(5)*1000), + ambient ! {leave, self(), Park_Ref}, + PID_S ! {askNewGoal, self(), Park_Ref}, + receive + {responseNewGoal, X_Goal_New, Y_Goal_New, Ref} -> + detect(X_New, Y_New, X_Goal_New, Y_Goal_New, H, W, PID_S) + end; + _ -> detect(X_New, Y_New, X_Goal, Y_Goal, H, W, PID_S) + end + end. diff --git a/Actors/render.erl b/Actors/render.erl index 06b9c69..bc3982e 100644 --- a/Actors/render.erl +++ b/Actors/render.erl @@ -3,22 +3,21 @@ % Path: Actors\render.erl -module(render). --export([main/0, order_chessboard/1]). - -print_chessboard([{{X,Y}, STATUS} | Tail],N)-> - case X == N of - true -> - case STATUS == undefined of - true -> - io:format("O\t"); - false -> - io:format("X\t") - end, - print_chessboard(Tail,N); - false -> - io:format("~n"), - print_chessboard([{{X,Y}, STATUS} | Tail],N+1) - end; +-export([main/2, order_chessboard/1]). + +print_chessboard([{X,Y}|T], Dict) -> + case Y == 1 of + true -> io:format("\n"); + _ -> ok + end, + A = lists:keyfind({X,Y}, 2, Dict), + case A of + false -> io:format("O\t"); + {_,{X,Y}} -> io:format("X\t") + end, + %io:format("A IS EQUAL TO ~p~n", [Dict]), + print_chessboard(T,Dict ); + print_chessboard([],_)-> ok. @@ -31,7 +30,7 @@ print_list([]) -> ok. order_chessboard(Chessboard) -> - lists:sort(fun({{X1,Y1},_}, {{X2,Y2},_}) -> + lists:sort(fun({_, {X1,Y1}}, { _, {X2,Y2}}) -> case X1 < X2 of true -> true; false -> @@ -43,11 +42,12 @@ order_chessboard(Chessboard) -> end, Chessboard). -main() -> +main(Chessboard, Dict) -> receive - {Chess} -> - timer:sleep(3000), %Just to wait the print of the Chess Parameter TODO: find a better solution to do thiss - L = order_chessboard(Chess), - print_chessboard(L,1), - main() + {position, PID, X, Y} -> + timer:sleep(3000), + Dict2 = dict:store(PID, {X,Y}, Dict), + List = order_chessboard(dict:to_list(Dict2)), + print_chessboard(Chessboard, List), + main(Chessboard, Dict2) end. From a7e6f8d72c11b7eee3060f662d7c27a92d1eac4f Mon Sep 17 00:00:00 2001 From: MarcoTomasone Date: Tue, 9 May 2023 13:59:08 +0200 Subject: [PATCH 08/18] [ADD] Added linking in car @minosse99 @Lucajett99 --- Actors/ambient.erl | 1 + Actors/car.erl | 45 +++++++++++++++++++++++++++++++-------------- Actors/render.erl | 2 +- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/Actors/ambient.erl b/Actors/ambient.erl index 76ab9dc..49e620c 100644 --- a/Actors/ambient.erl +++ b/Actors/ambient.erl @@ -10,6 +10,7 @@ {isFree, PID, X, Y, Ref} -> %Request a car sends to the ambient io:format("Request from ~p for parking (~p,~p)~n",[PID,X,Y]), %DEBUG PID ! {status, Ref, undefined =:= dict:fetch({X,Y}, Chessboard)}, %Reply to the car + io:format("Reply to ~p with Ref ~p~n", [PID, Ref]), %DEBUG io:format("Parking (~p,~p) is free: ~p~n", [X,Y, undefined =:= dict:fetch({X,Y}, Chessboard)]), %DEBUG ambient(Chessboard); {park, PID, X, Y, Ref} -> diff --git a/Actors/car.erl b/Actors/car.erl index f9c24db..982eec1 100644 --- a/Actors/car.erl +++ b/Actors/car.erl @@ -1,20 +1,11 @@ -module(car). - -export([main_car/2]). - - %The main actor creates other actors and re-creates them if they fail - main_car(H, W) -> - {X_Spawn, Y_Spawn} = generate_coordinates(H, W), - {X_Goal, Y_Goal} = generate_coordinates(H, W), - %PID_S receive an empty dict() - PID_S = spawn(?MODULE, state, [dict:new(), X_Goal, Y_Goal, H, W]), - PID_D = spawn(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W, PID_S]), - PID_F = spawn(?MODULE, friendship, []). - %TODO: handling respawn + -export([main_car/2, friendship/0, state/5, detect/7]). friendship() -> io:fwrite("CIAO\n"). state(World_Knowledge, X_Goal, Y_Goal, H, W) -> + io:format("Start State~n"), receive {updateState, PID_D, X, Y, isFree} -> io:fwrite("Update Value for park (~p,~p), new value: ~p~n", [{X,Y}, isFree]), %Update parkings @@ -117,13 +108,16 @@ %@param Y: actual Y coordinate of the car % detect(X, Y, X_Goal, Y_Goal, H, W, PID_S) -> - %Check if we are on goal + io:format("Start Detect~n"), + link(PID_S), timer:sleep(2000), {X_New, Y_New} = move(X, Y, {X_Goal, Y_Goal}, H, W), %TODO: H and W must be passed as parameters? - render ! + render ! {position, self(), X_New, Y_New}, Ref = make_ref(), ambient ! {isFree, self(), X_New, Y_New, Ref}, + io:format("I'm here~n"), receive + X -> io:format("X: ~p~n", [X]); {updateGoal, X_Goal_New, Y_Goal_New} -> detect(X_New, Y_New, X_Goal_New, Y_Goal_New, H, W, PID_S); {status, Ref, isFree} -> PID_S ! {updateState, self(), X_New, Y_New, isFree}, @@ -131,7 +125,7 @@ {true, true} -> Park_Ref = make_ref(), ambient ! {park, self(), X_New, Y_New, Park_Ref}, - timer:sleep(random:uniform(5)*1000), + timer:sleep(rand:uniform(5)*1000), ambient ! {leave, self(), Park_Ref}, PID_S ! {askNewGoal, self(), Park_Ref}, receive @@ -142,6 +136,29 @@ end end. + %The main actor creates other actors and re-creates them if they fail + main_car(H, W) -> + process_flag(trap_exit, true), + {X_Spawn, Y_Spawn} = generate_coordinates(H, W), + {X_Goal, Y_Goal} = generate_coordinates(H, W), + io:format("X_Spawn: ~p, Y_Spawn: ~p~n", [X_Spawn, Y_Spawn]), + io:format("X_Goal: ~p, Y_Goal: ~p~n", [X_Goal, Y_Goal]), + + Spawn_loop = fun Spawn_loop() -> + PID_S = spawn(?MODULE, state, [dict:new(), X_Goal, Y_Goal, H, W]), + {PID_D, Ref_monitor} = spawn_monitor(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W, PID_S]), + + receive + {'DOWN', Ref, _, PID, Reason } -> + io:format("PID: ~p, Reason: ~p~n", [PID, Reason]), + Spawn_loop(); + X -> io:format("X: ~p~n", [X]) + + end + end, + Spawn_loop(). + + diff --git a/Actors/render.erl b/Actors/render.erl index bc3982e..6a871cb 100644 --- a/Actors/render.erl +++ b/Actors/render.erl @@ -45,7 +45,7 @@ order_chessboard(Chessboard) -> main(Chessboard, Dict) -> receive {position, PID, X, Y} -> - timer:sleep(3000), + timer:sleep(3000), %Just for the print() Dict2 = dict:store(PID, {X,Y}, Dict), List = order_chessboard(dict:to_list(Dict2)), print_chessboard(Chessboard, List), From f7b79ef313817988258a70f4ca88878ffc3e42cb Mon Sep 17 00:00:00 2001 From: MarcoTomasone Date: Tue, 9 May 2023 16:19:59 +0200 Subject: [PATCH 09/18] [FIX] Fixed car movement, fixed interaction car-render --- Actors/ambient.erl | 22 ++++++++++----------- Actors/car.erl | 48 ++++++++++++++++++++++++++++------------------ Actors/render.erl | 3 +-- Actors/run.bat | 6 ++++++ 4 files changed, 47 insertions(+), 32 deletions(-) create mode 100644 Actors/run.bat diff --git a/Actors/ambient.erl b/Actors/ambient.erl index 49e620c..fbfd661 100644 --- a/Actors/ambient.erl +++ b/Actors/ambient.erl @@ -8,29 +8,29 @@ ambient(Chessboard) -> receive {isFree, PID, X, Y, Ref} -> %Request a car sends to the ambient - io:format("Request from ~p for parking (~p,~p)~n",[PID,X,Y]), %DEBUG + io:format("A: Request from ~p for parking (~p,~p)~n",[PID,X,Y]), %DEBUG + io:format("A: Parking (~p,~p) is free: ~p~n", [X,Y, undefined =:= dict:fetch({X,Y}, Chessboard)]), %DEBUG + io:format("A: Reply to ~p with Ref ~p~n", [PID, Ref]), %DEBUG PID ! {status, Ref, undefined =:= dict:fetch({X,Y}, Chessboard)}, %Reply to the car - io:format("Reply to ~p with Ref ~p~n", [PID, Ref]), %DEBUG - io:format("Parking (~p,~p) is free: ~p~n", [X,Y, undefined =:= dict:fetch({X,Y}, Chessboard)]), %DEBUG ambient(Chessboard); {park, PID, X, Y, Ref} -> - io:fwrite("Update Value for park ~p occupied by ~p~n", [{X,Y}, PID]), %Update parkings + io:fwrite("A: Update Value for park ~p occupied by ~p~n", [{X,Y}, PID]), %Update parkings ambient(dict:store({X,Y}, PID, Chessboard)); {leave, PID, Ref} -> - io:fwrite("PID ~p exit from parking ~n", [PID]), %Update parkings + io:fwrite("A: PID ~p exit from parking ~n", [PID]), %Update parkings case searchKey(Chessboard, PID) of {X, Y} -> - io:fwrite("Update Value for leave ~p free~n", [{X,Y}]), %Update parkings + io:fwrite("A: Update Value for leave ~p free~n", [{X,Y}]), %Update parkings ambient(dict:store({X,Y}, undefined, Chessboard)); [] -> - io:fwrite("PID: ~p not parked before ~n", [PID]), + io:fwrite("A: PID: ~p not parked before ~n", [PID]), ambient(Chessboard) end; draw -> - io:fwrite("Entered Draw ~n"), %DEBUG + io:fwrite("A: Entered Draw ~n"), %DEBUG render ! {dict:to_list(Chessboard)}, ambient(Chessboard); %DEBUG - _ -> io:fwrite("No Pattern Matching Found!\n") + _ -> io:fwrite("A: No Pattern Matching Found!\n") end. %%%%%% @@ -57,12 +57,12 @@ main(H, W) -> %Chessboard Definition - Chessboard = dict:from_list([{{X, Y}, undefined} || X <- lists:seq(1, H), Y <- lists:seq(1, W)]), + Chessboard = dict:from_list([{{X, Y}, undefined} || X <- lists:seq(0, H-1), Y <- lists:seq(0, W-1)]), printDict(Chessboard), %DEBUG io:format("Chessboard size ~p~n", [dict:size(Chessboard)]), %Spawn the render actor - PID_R = spawn(render, main, [[{X, Y} || X <- lists:seq(1, H), Y <- lists:seq(1, W)], dict:new()]), + PID_R = spawn(render, main, [[{X, Y} || X <- lists:seq(0, H-1), Y <- lists:seq(0, W-1)], dict:new()]), register(render, PID_R), io:format("Correctly registered ~p as 'render' ~n", [PID_R]), %DEBUG render ! {dict:to_list(Chessboard)}, %DEBUG diff --git a/Actors/car.erl b/Actors/car.erl index 982eec1..8a0494b 100644 --- a/Actors/car.erl +++ b/Actors/car.erl @@ -31,15 +31,17 @@ end; %Case Car Exit from the parking and needs new goal {askNewGoal, PID_D, Ref} -> - {X_Goal_New, Y_Goal_New} = generate_coordinates(H, W), %TODO: check if new coordinates I generate should be free? - PID_D ! {responseNewGoal, X_Goal_New, Y_Goal_New, Ref}; + io:format("Ask New Goal with Ref ~p~n",[Ref]), + {X_Goal_New, Y_Goal_New} = generate_coordinates(H, W), %TODO: check if new coordinates I generate should be free? + PID_D ! {responseNewGoal, X_Goal_New, Y_Goal_New, Ref}, + state(World_Knowledge, X_Goal_New, Y_Goal_New, H, W); _ -> state( World_Knowledge, X_Goal, Y_Goal, H, W) end. generate_coordinates(H, W) -> - X = random:uniform(H), - Y = random:uniform(W), + X = rand:uniform(H)-1, + Y = rand:uniform(W)-1, {X, Y}. %L'attore "detect" di un'automobile sceglie un posteggio obiettivo libero interagendo con l'attore "state". Dopodichè, ogni 2s, si avvicina di una cella verso tale obiettivo. Se deve muoversi lungo entrambi gli assi (x e y), lo fa scegliendo randomicamente l'asse e muovendosi nella direzione che minimizza la distanza percorsa. @@ -55,6 +57,7 @@ compute_X_movement(X, X_Goal, H) -> D_pos = abs(X_Goal - ((X+1) rem H)), D_neg = abs(X_Goal - ((X-1) rem H)), + io:format("X: D_pos: ~p, D_neg: ~p~n", [D_pos, D_neg]), case D_pos =< D_neg of true -> 1; false -> -1 @@ -71,6 +74,7 @@ compute_Y_movement(Y, Y_Goal, W) -> D_pos = abs(Y_Goal - ((Y+1) rem W)), D_neg = abs(Y_Goal - ((Y-1) rem W)), + io:format("Y: D_pos: ~p, D_neg: ~p~n", [D_pos, D_neg]), case D_pos =< D_neg of true -> 1; false -> -1 @@ -94,13 +98,13 @@ {true, true} -> {X, Y}; {true, false}-> - {X, (Y + compute_Y_movement(Y, Y_Goal, W)) rem W}; + {X, (Y + compute_Y_movement(Y, Y_Goal, W)) rem (W)}; {false, true} -> - {(X + compute_X_movement(X, X_Goal, H)) rem H, Y}; + {(X + compute_X_movement(X, X_Goal, H)) rem (H), Y}; {false, false} -> case random:uniform(2) of - 1 -> {(X + compute_X_movement(X, X_Goal, H)) rem H, Y}; - 2 -> {X, (Y + compute_Y_movement(Y, Y_Goal, W)) rem W} + 1 -> {(X + compute_X_movement(X, X_Goal, H+1)) rem (H), Y}; + 2 -> {X, (Y + compute_Y_movement(Y, Y_Goal, W+1)) rem (W)} end end. %%%%%% @@ -108,19 +112,21 @@ %@param Y: actual Y coordinate of the car % detect(X, Y, X_Goal, Y_Goal, H, W, PID_S) -> - io:format("Start Detect~n"), + io:format("Start Detect with goal (~p,~p)~n", [X_Goal, Y_Goal]), link(PID_S), timer:sleep(2000), {X_New, Y_New} = move(X, Y, {X_Goal, Y_Goal}, H, W), %TODO: H and W must be passed as parameters? render ! {position, self(), X_New, Y_New}, + timer:sleep(5000), %TODO: just for debug() Ref = make_ref(), + io:format("Ref ~p~n", [Ref]), ambient ! {isFree, self(), X_New, Y_New, Ref}, - io:format("I'm here~n"), + io:format("I'm here ~p~n",[self()]), receive - X -> io:format("X: ~p~n", [X]); {updateGoal, X_Goal_New, Y_Goal_New} -> detect(X_New, Y_New, X_Goal_New, Y_Goal_New, H, W, PID_S); - {status, Ref, isFree} -> - PID_S ! {updateState, self(), X_New, Y_New, isFree}, + {status, Ref, IsFree} -> + io:format("Received status ~p with Ref ~p~n", [IsFree, Ref]), + PID_S ! {updateState, self(), X_New, Y_New, IsFree}, case {X_New =:= X_Goal, Y_New =:= Y_Goal} of {true, true} -> Park_Ref = make_ref(), @@ -129,11 +135,15 @@ ambient ! {leave, self(), Park_Ref}, PID_S ! {askNewGoal, self(), Park_Ref}, receive - {responseNewGoal, X_Goal_New, Y_Goal_New, Ref} -> - detect(X_New, Y_New, X_Goal_New, Y_Goal_New, H, W, PID_S) + {responseNewGoal, X_Goal_New, Y_Goal_New, Park_Ref} -> + io:format("Received new goal (~p, ~p) with Ref: ~p~n", [X_Goal_New, Y_Goal_New, Park_Ref]), + detect(X_New, Y_New, X_Goal_New, Y_Goal_New, H, W, PID_S); + Msg -> io:fwrite("MSG: ~p~n",[Msg]) %TODO: Kill process? end; _ -> detect(X_New, Y_New, X_Goal, Y_Goal, H, W, PID_S) - end + + end; + _ -> io:fwrite("No Pattern Matching Found~n") %TODO: Kill process? end. %The main actor creates other actors and re-creates them if they fail @@ -147,10 +157,10 @@ Spawn_loop = fun Spawn_loop() -> PID_S = spawn(?MODULE, state, [dict:new(), X_Goal, Y_Goal, H, W]), {PID_D, Ref_monitor} = spawn_monitor(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W, PID_S]), - + render ! {position, PID_D, X_Spawn, Y_Spawn}, receive - {'DOWN', Ref, _, PID, Reason } -> - io:format("PID: ~p, Reason: ~p~n", [PID, Reason]), + {'DOWN', _, _, PID, Reason } -> + io:format("Died PID: ~p, Reason: ~p~n", [PID, Reason]), Spawn_loop(); X -> io:format("X: ~p~n", [X]) diff --git a/Actors/render.erl b/Actors/render.erl index 6a871cb..0a2e255 100644 --- a/Actors/render.erl +++ b/Actors/render.erl @@ -6,7 +6,7 @@ -export([main/2, order_chessboard/1]). print_chessboard([{X,Y}|T], Dict) -> - case Y == 1 of + case Y == 0 of true -> io:format("\n"); _ -> ok end, @@ -45,7 +45,6 @@ order_chessboard(Chessboard) -> main(Chessboard, Dict) -> receive {position, PID, X, Y} -> - timer:sleep(3000), %Just for the print() Dict2 = dict:store(PID, {X,Y}, Dict), List = order_chessboard(dict:to_list(Dict2)), print_chessboard(Chessboard, List), diff --git a/Actors/run.bat b/Actors/run.bat new file mode 100644 index 0000000..56eacd4 --- /dev/null +++ b/Actors/run.bat @@ -0,0 +1,6 @@ +#!/bin/bash +erlc -o ambient.erl +erlc -o render.erl +erlc -o car.erl + +erl -eval "ambient:main(3,3)" From 85960c2bcfd2b924ec2eae517a0c9cb3d5e50dd0 Mon Sep 17 00:00:00 2001 From: MarcoTomasone Date: Tue, 9 May 2023 20:45:13 +0200 Subject: [PATCH 10/18] [FIX] Fixed render, now receives target --- Actors/car.erl | 2 ++ Actors/render.erl | 51 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/Actors/car.erl b/Actors/car.erl index 8a0494b..4fa947e 100644 --- a/Actors/car.erl +++ b/Actors/car.erl @@ -137,6 +137,7 @@ receive {responseNewGoal, X_Goal_New, Y_Goal_New, Park_Ref} -> io:format("Received new goal (~p, ~p) with Ref: ~p~n", [X_Goal_New, Y_Goal_New, Park_Ref]), + render ! {target, self(), X_Goal_New, Y_Goal_New}, detect(X_New, Y_New, X_Goal_New, Y_Goal_New, H, W, PID_S); Msg -> io:fwrite("MSG: ~p~n",[Msg]) %TODO: Kill process? end; @@ -157,6 +158,7 @@ Spawn_loop = fun Spawn_loop() -> PID_S = spawn(?MODULE, state, [dict:new(), X_Goal, Y_Goal, H, W]), {PID_D, Ref_monitor} = spawn_monitor(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W, PID_S]), + render ! {target, PID_D, X_Goal, Y_Goal}, render ! {position, PID_D, X_Spawn, Y_Spawn}, receive {'DOWN', _, _, PID, Reason } -> diff --git a/Actors/render.erl b/Actors/render.erl index 0a2e255..bb50587 100644 --- a/Actors/render.erl +++ b/Actors/render.erl @@ -5,25 +5,30 @@ -module(render). -export([main/2, order_chessboard/1]). -print_chessboard([{X,Y}|T], Dict) -> +print_chessboard([{X,Y}|T], DictToList) -> case Y == 0 of true -> io:format("\n"); _ -> ok end, - A = lists:keyfind({X,Y}, 2, Dict), - case A of - false -> io:format("O\t"); - {_,{X,Y}} -> io:format("X\t") + A = lists:keyfind({X,Y}, 2, DictToList), + B = lists:keyfind({X,Y}, 3, DictToList), + case {A,B} of + {false, false} -> io:format("O\t"); + {{_,{X,Y},_}, {_,_,{X,Y}}} -> io:format("X*\t"); + {{_,{X,Y},_}, _} -> io:format("X\t"); + {_ , {_,_,{X,Y}}} -> io:format("*\t") end, + %io:format("A IS EQUAL TO ~p~n", [Dict]), - print_chessboard(T,Dict ); + print_chessboard(T, DictToList ); -print_chessboard([],_)-> ok. +print_chessboard([],_)-> io:format("\n"). %Function to print a list print_list([H|T]) -> + %map element of list {A, {B,C}} to {A, B, C} io:fwrite("~p~n", [H]), print_list(T); print_list([]) -> ok. @@ -43,10 +48,36 @@ order_chessboard(Chessboard) -> Chessboard). main(Chessboard, Dict) -> + % PID -> {{POS},{GOAL}} DICT STRUCTURE receive + % position of car sent by detect {position, PID, X, Y} -> - Dict2 = dict:store(PID, {X,Y}, Dict), - List = order_chessboard(dict:to_list(Dict2)), - print_chessboard(Chessboard, List), + case dict:find(PID, Dict) of + error -> + Dict2 = dict:store(PID, {{X,Y}, {undefined, undefined}}, Dict), + Dict2; + {ok, {{_,_},{X_Goal, Y_Goal}}} -> + Dict2 = dict:store(PID, {{X,Y},{X_Goal, Y_Goal}}, Dict), + Dict2 + end, + DictToList = dict:to_list(Dict2), + DictToList2 = lists:map(fun({A, {B,C}}) -> {A,B,C} end, DictToList), + print_list(DictToList2), + print_chessboard(Chessboard, DictToList2), + main(Chessboard, Dict2); + % target position of goal sent by detect + {target, PID, X, Y} -> + case dict:find(PID, Dict) of + error -> + Dict2 = dict:store(PID, {{undefined, undefined},{X,Y}}, Dict), + Dict2; + {ok, {{X_Pos, Y_Pos}, {_,_}}} -> + Dict2 = dict:store(PID, {{X_Pos, Y_Pos},{X,Y}}, Dict), + Dict2 + end, + DictToList = dict:to_list(Dict2), + DictToList2 = lists:map(fun({A, {B,C}}) -> {A,B,C} end, DictToList), + print_list(DictToList2), + print_chessboard(Chessboard, DictToList2), main(Chessboard, Dict2) end. From 4f58c2a7ccddadaecca0980a8b5964ea0f4f5693 Mon Sep 17 00:00:00 2001 From: MarcoTomasone Date: Wed, 10 May 2023 11:18:04 +0200 Subject: [PATCH 11/18] [ADD] Started Friendship @minosse99 @Lucajett99 --- Actors/ambient.erl | 30 +++++++++++++--------------- Actors/car.erl | 47 ++++++++++++++++++++++++++++++++++++-------- Actors/render.erl | 17 +++++++++++----- Actors/wellknown.erl | 30 ++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 29 deletions(-) diff --git a/Actors/ambient.erl b/Actors/ambient.erl index fbfd661..50dfdb2 100644 --- a/Actors/ambient.erl +++ b/Actors/ambient.erl @@ -8,29 +8,27 @@ ambient(Chessboard) -> receive {isFree, PID, X, Y, Ref} -> %Request a car sends to the ambient - io:format("A: Request from ~p for parking (~p,~p)~n",[PID,X,Y]), %DEBUG - io:format("A: Parking (~p,~p) is free: ~p~n", [X,Y, undefined =:= dict:fetch({X,Y}, Chessboard)]), %DEBUG - io:format("A: Reply to ~p with Ref ~p~n", [PID, Ref]), %DEBUG + io:format("AMB: Request from ~p for parking (~p,~p)~n",[PID,X,Y]), %DEBUG + io:format("AMB: Parking (~p,~p) is free: ~p~n", [X,Y, undefined =:= dict:fetch({X,Y}, Chessboard)]), %DEBUG + io:format("AMB: Reply to ~p with Ref ~p~n", [PID, Ref]), %DEBUG PID ! {status, Ref, undefined =:= dict:fetch({X,Y}, Chessboard)}, %Reply to the car ambient(Chessboard); {park, PID, X, Y, Ref} -> - io:fwrite("A: Update Value for park ~p occupied by ~p~n", [{X,Y}, PID]), %Update parkings + io:fwrite("AMB: Update Value for park ~p occupied by ~p~n", [{X,Y}, PID]), %Update parkings + render ! {parked, PID, X, Y, true}, %DEBUG ambient(dict:store({X,Y}, PID, Chessboard)); {leave, PID, Ref} -> - io:fwrite("A: PID ~p exit from parking ~n", [PID]), %Update parkings + io:fwrite("AMB: PID ~p exit from parking ~n", [PID]), %Update parkings case searchKey(Chessboard, PID) of {X, Y} -> - io:fwrite("A: Update Value for leave ~p free~n", [{X,Y}]), %Update parkings + io:fwrite("AMB: Update Value for leave ~p free~n", [{X,Y}]), %Update parkings + render ! {parked, PID, X, Y, false}, ambient(dict:store({X,Y}, undefined, Chessboard)); [] -> - io:fwrite("A: PID: ~p not parked before ~n", [PID]), + io:fwrite("AMB: PID: ~p not parked before ~n", [PID]), ambient(Chessboard) end; - draw -> - io:fwrite("A: Entered Draw ~n"), %DEBUG - render ! {dict:to_list(Chessboard)}, - ambient(Chessboard); %DEBUG - _ -> io:fwrite("A: No Pattern Matching Found!\n") + _ -> io:fwrite("AMB: No Pattern Matching Found!\n") end. %%%%%% @@ -59,16 +57,16 @@ %Chessboard Definition Chessboard = dict:from_list([{{X, Y}, undefined} || X <- lists:seq(0, H-1), Y <- lists:seq(0, W-1)]), printDict(Chessboard), %DEBUG - io:format("Chessboard size ~p~n", [dict:size(Chessboard)]), + io:format("AMB: Chessboard size ~p~n", [dict:size(Chessboard)]), %Spawn the render actor PID_R = spawn(render, main, [[{X, Y} || X <- lists:seq(0, H-1), Y <- lists:seq(0, W-1)], dict:new()]), register(render, PID_R), - io:format("Correctly registered ~p as 'render' ~n", [PID_R]), %DEBUG + io:format("AMB: Correctly registered ~p as 'render' ~n", [PID_R]), %DEBUG render ! {dict:to_list(Chessboard)}, %DEBUG %Spawn ambient actor PID_A = spawn(?MODULE, ambient, [Chessboard]), %spawn the ambient actor - io:format("Ambient PID: ~p~n", [PID_A]), %DEBUG + io:format("AMB: Ambient PID: ~p~n", [PID_A]), %DEBUG register(ambient, PID_A), %register the ambient actor with the name ambient - io:format("Correctly registered ~p as 'ambient' ~n", [PID_A]). %DEBUG + io:format("AMB: Correctly registered ~p as 'ambient' ~n", [PID_A]). %DEBUG diff --git a/Actors/car.erl b/Actors/car.erl index 4fa947e..76c07c4 100644 --- a/Actors/car.erl +++ b/Actors/car.erl @@ -1,8 +1,39 @@ -module(car). - -export([main_car/2, friendship/0, state/5, detect/7]). + -export([main_car/2, friendship/3, state/5, detect/7, getFriends/2]). - friendship() -> - io:fwrite("CIAO\n"). + + + friendship(FriendsList, RefList, PID_S) when lenght(FriendsList) < 5 -> + L = length(FriendsList), + Ref = make_ref(), + case L of + 0 -> wellknown ! {getFriends, self(), PID_S ,Ref}; + _ -> getFriends(FriendList, RefList) + end + receive + {myFriends, PIDSLIST, Ref} -> + %Demonitor the old friends from refList + lists:foreach(fun(X) -> demonitor(X) end, RefList), + TotalFriends = PIDSLIST ++ FriendsList, + %Create a list choosing 5 random friends from TotalFriends + FriendList2 = lists:sublist([Y||{_,Y} <- lists:sort([ {rand:uniform(), N} || N <- TotalFriends])], 5), + %Monitor all the friends in the list and save the ref in RefList + RefList2 = lists:map(fun({PIDF, _}) -> monitor(process, PIDF) end, FriendList2), + friendship(FriendList2, RefList2, PID_S) + end. + + getFriends(FriendsList, RefList) -> + receive + {myFriends, PIDSLIST, Ref} -> + %Demonitor the old friends from refList + lists:foreach(fun(X) -> demonitor(X) end, RefList), + TotalFriends = PIDSLIST ++ FriendsList, + %Create a list choosing 5 random friends from TotalFriends + FriendList2 = lists:sublist([Y||{_,Y} <- lists:sort([ {rand:uniform(), N} || N <- TotalFriends])], 5), + %Monitor all the friends in the list and save the ref in RefList + RefList2 = lists:map(fun({PIDF, _}) -> monitor(process, PIDF) end, FriendList2), + end. + state(World_Knowledge, X_Goal, Y_Goal, H, W) -> io:format("Start State~n"), @@ -57,7 +88,7 @@ compute_X_movement(X, X_Goal, H) -> D_pos = abs(X_Goal - ((X+1) rem H)), D_neg = abs(X_Goal - ((X-1) rem H)), - io:format("X: D_pos: ~p, D_neg: ~p~n", [D_pos, D_neg]), + %io:format("X: D_pos: ~p, D_neg: ~p~n", [D_pos, D_neg]), case D_pos =< D_neg of true -> 1; false -> -1 @@ -74,7 +105,7 @@ compute_Y_movement(Y, Y_Goal, W) -> D_pos = abs(Y_Goal - ((Y+1) rem W)), D_neg = abs(Y_Goal - ((Y-1) rem W)), - io:format("Y: D_pos: ~p, D_neg: ~p~n", [D_pos, D_neg]), + %io:format("Y: D_pos: ~p, D_neg: ~p~n", [D_pos, D_neg]), case D_pos =< D_neg of true -> 1; false -> -1 @@ -119,13 +150,13 @@ render ! {position, self(), X_New, Y_New}, timer:sleep(5000), %TODO: just for debug() Ref = make_ref(), - io:format("Ref ~p~n", [Ref]), + %io:format("Ref ~p~n", [Ref]), ambient ! {isFree, self(), X_New, Y_New, Ref}, - io:format("I'm here ~p~n",[self()]), + %io:format("I'm here ~p~n",[self()]), receive {updateGoal, X_Goal_New, Y_Goal_New} -> detect(X_New, Y_New, X_Goal_New, Y_Goal_New, H, W, PID_S); {status, Ref, IsFree} -> - io:format("Received status ~p with Ref ~p~n", [IsFree, Ref]), + %io:format("Received status ~p with Ref ~p~n", [IsFree, Ref]), PID_S ! {updateState, self(), X_New, Y_New, IsFree}, case {X_New =:= X_Goal, Y_New =:= Y_Goal} of {true, true} -> diff --git a/Actors/render.erl b/Actors/render.erl index bb50587..4f6d92a 100644 --- a/Actors/render.erl +++ b/Actors/render.erl @@ -21,8 +21,6 @@ print_chessboard([{X,Y}|T], DictToList) -> %io:format("A IS EQUAL TO ~p~n", [Dict]), print_chessboard(T, DictToList ); - - print_chessboard([],_)-> io:format("\n"). @@ -62,7 +60,7 @@ main(Chessboard, Dict) -> end, DictToList = dict:to_list(Dict2), DictToList2 = lists:map(fun({A, {B,C}}) -> {A,B,C} end, DictToList), - print_list(DictToList2), + %print_list(DictToList2), print_chessboard(Chessboard, DictToList2), main(Chessboard, Dict2); % target position of goal sent by detect @@ -77,7 +75,16 @@ main(Chessboard, Dict) -> end, DictToList = dict:to_list(Dict2), DictToList2 = lists:map(fun({A, {B,C}}) -> {A,B,C} end, DictToList), - print_list(DictToList2), + %print_list(DictToList2), print_chessboard(Chessboard, DictToList2), - main(Chessboard, Dict2) + main(Chessboard, Dict2); + %sent by ambient when car park or restart + {parked, PID, X, Y, IsParked} -> + io:format("RENDER: Car ~p is parked at (~p, ~p): ~p~n", [PID, X, Y, IsParked]), + main(Chessboard, Dict); + %sent by friendship actor TODO: implement this + {friendship, PID, PIDLIST} -> + io:format("RENDER: Car ~p is friend with ~p~n", [PID, PIDLIST]), + main(Chessboard, Dict) + end. diff --git a/Actors/wellknown.erl b/Actors/wellknown.erl index e69de29..3e31ee1 100644 --- a/Actors/wellknown.erl +++ b/Actors/wellknown.erl @@ -0,0 +1,30 @@ +% +-module(wellknown). +-export([main/0, wellknown/1]). + + +wellknown(PIDSLIST) -> + receive + %PID1 is the PID of friendship actor, PID2 is the PID of state actor + {getFriends, PID1, PID2, Ref} -> + PID1 ! {myFriends, PIDSLIST, Ref}, + case lists:member({PID1, PID2}, PIDSLIST) of + true -> wellknown(PIDSLIST); + false -> + %Monitor the friendship actor of the Car I added to my list so I can remove it if he dies + monitor(process, PID1), + %Add the new actor to the list + wellknown([{PID1, PID2}|PIDSLIST]) + end; + %case a PID I monitor dies + {'DOWN', _, _, PID_Friendship, _Reason} -> + io:format("WK: Delete PID: ~p for reason: ~p~n", [PID_Friendship, _Reason]), + %Create a new list that contains all elements form PIDSLIST except the one that died + UpdatedList = [ {PIDF, PIDS} || {PIDF, PIDS} <- PIDSLIST, PIDF =/= PID_Friendship], + wellknown(UpdatedList) + end. + +main() -> + PID_W = spawn(?MODULE, wellknown, [[]]), + register(wellknown, PID_W), + io:format("WN: Wellknown started with PID ~p registered with wellknown~n", [PID_W]). From 645ae91e8ae8ac42aee649c94b198c0a20b7b4eb Mon Sep 17 00:00:00 2001 From: Lucajett99 Date: Wed, 10 May 2023 12:07:39 +0200 Subject: [PATCH 12/18] added get friends @MarcoTomasone @minosse99 --- Actors/car.erl | 65 +++++++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/Actors/car.erl b/Actors/car.erl index 76c07c4..0c1c597 100644 --- a/Actors/car.erl +++ b/Actors/car.erl @@ -1,40 +1,50 @@ -module(car). -export([main_car/2, friendship/3, state/5, detect/7, getFriends/2]). - - - friendship(FriendsList, RefList, PID_S) when lenght(FriendsList) < 5 -> - L = length(FriendsList), - Ref = make_ref(), - case L of - 0 -> wellknown ! {getFriends, self(), PID_S ,Ref}; - _ -> getFriends(FriendList, RefList) - end + receive_friends(FriendsList, RefList, L) -> receive - {myFriends, PIDSLIST, Ref} -> + {myFriends, PIDSLIST, Ref} -> %Demonitor the old friends from refList lists:foreach(fun(X) -> demonitor(X) end, RefList), - TotalFriends = PIDSLIST ++ FriendsList, + %Add the new friends to the list + TotalFriends = lists:usort(PIDSLIST ++ FriendsList), %Create a list choosing 5 random friends from TotalFriends FriendList2 = lists:sublist([Y||{_,Y} <- lists:sort([ {rand:uniform(), N} || N <- TotalFriends])], 5), %Monitor all the friends in the list and save the ref in RefList RefList2 = lists:map(fun({PIDF, _}) -> monitor(process, PIDF) end, FriendList2), - friendship(FriendList2, RefList2, PID_S) + case lenght(FriendList2) < 5 of + true -> getFriends(FriendList2, RefList2, L); + false -> {FriendList2, RefList2} + end end. - getFriends(FriendsList, RefList) -> - receive - {myFriends, PIDSLIST, Ref} -> - %Demonitor the old friends from refList - lists:foreach(fun(X) -> demonitor(X) end, RefList), - TotalFriends = PIDSLIST ++ FriendsList, - %Create a list choosing 5 random friends from TotalFriends - FriendList2 = lists:sublist([Y||{_,Y} <- lists:sort([ {rand:uniform(), N} || N <- TotalFriends])], 5), - %Monitor all the friends in the list and save the ref in RefList - RefList2 = lists:map(fun({PIDF, _}) -> monitor(process, PIDF) end, FriendList2), + + getFriends(FriendsList, RefList, L) -> + Lenght = lenght(L), + case Lenght of + 0 -> + Ref = make_ref(), + wellknown ! {getFriends, self(), PID_S, Ref}, + receive_friends(FriendsList, RefList); + 5 -> + {FriendsList, RefList}; + _ -> + %pick a random friend from the list + {PIDF, _} = lists:nth(rand:uniform(Lenght), L), + %delete the friend from the list + L2 = lists:delete({PIDF, _}, L), + Ref = make_ref(), + PIDF ! {getFriends, self(), PID_S, Ref}, + receive_friends(FriendsList, RefList, L2) end. - + + + friendship(FriendsList, RefList, PID_S) -> + {FriendList2, RefList2} = getFriends(FriendsList, RefList, FriendsList), + friendship(FriendList2, RefList2, PID_S). + + state(World_Knowledge, X_Goal, Y_Goal, H, W) -> io:format("Start State~n"), receive @@ -187,10 +197,11 @@ io:format("X_Goal: ~p, Y_Goal: ~p~n", [X_Goal, Y_Goal]), Spawn_loop = fun Spawn_loop() -> - PID_S = spawn(?MODULE, state, [dict:new(), X_Goal, Y_Goal, H, W]), - {PID_D, Ref_monitor} = spawn_monitor(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W, PID_S]), - render ! {target, PID_D, X_Goal, Y_Goal}, - render ! {position, PID_D, X_Spawn, Y_Spawn}, + %PID_S = spawn(?MODULE, state, [dict:new(), X_Goal, Y_Goal, H, W]), + %{PID_D, Ref_monitor} = spawn_monitor(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W, PID_S]), + {PID_F, Ref_monitor} = spawn_monitor(?MODULE, friendship, [[],[], rand:uniform(100)]), + %render ! {target, PID_D, X_Goal, Y_Goal}, + %render ! {position, PID_D, X_Spawn, Y_Spawn}, receive {'DOWN', _, _, PID, Reason } -> io:format("Died PID: ~p, Reason: ~p~n", [PID, Reason]), From c20b05b74692049512ccfe25bed56749095682a6 Mon Sep 17 00:00:00 2001 From: MarcoTomasone Date: Wed, 10 May 2023 12:19:13 +0200 Subject: [PATCH 13/18] [FIX] Minor sintax fix @minosse99 @Lucajett99 --- Actors/car.erl | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/Actors/car.erl b/Actors/car.erl index 0c1c597..085481c 100644 --- a/Actors/car.erl +++ b/Actors/car.erl @@ -1,7 +1,7 @@ -module(car). - -export([main_car/2, friendship/3, state/5, detect/7, getFriends/2]). + -export([main_car/2, friendship/3, state/5, detect/7, getFriends/4]). - receive_friends(FriendsList, RefList, L) -> + receive_friends(FriendsList, RefList, L, PID_S) -> receive {myFriends, PIDSLIST, Ref} -> %Demonitor the old friends from refList @@ -12,36 +12,34 @@ FriendList2 = lists:sublist([Y||{_,Y} <- lists:sort([ {rand:uniform(), N} || N <- TotalFriends])], 5), %Monitor all the friends in the list and save the ref in RefList RefList2 = lists:map(fun({PIDF, _}) -> monitor(process, PIDF) end, FriendList2), - case lenght(FriendList2) < 5 of - true -> getFriends(FriendList2, RefList2, L); + case length(FriendList2) < 5 of + true -> getFriends(FriendList2, RefList2, L, PID_S); false -> {FriendList2, RefList2} end end. - getFriends(FriendsList, RefList, L) -> - Lenght = lenght(L), + getFriends(FriendsList, RefList, L, PID_S) -> + Lenght = length(L), case Lenght of 0 -> Ref = make_ref(), wellknown ! {getFriends, self(), PID_S, Ref}, - receive_friends(FriendsList, RefList); + receive_friends(FriendsList, RefList, L, PID_S); 5 -> {FriendsList, RefList}; _ -> %pick a random friend from the list {PIDF, _} = lists:nth(rand:uniform(Lenght), L), %delete the friend from the list - L2 = lists:delete({PIDF, _}, L), + L2 = [ {PIDFR, PIDSTATE} || {PIDFR, PIDSTATE} <- L, PIDFR =/= PIDF], Ref = make_ref(), PIDF ! {getFriends, self(), PID_S, Ref}, - receive_friends(FriendsList, RefList, L2) + receive_friends(FriendsList, RefList, L2, PID_S) end. - - friendship(FriendsList, RefList, PID_S) -> - {FriendList2, RefList2} = getFriends(FriendsList, RefList, FriendsList), + {FriendList2, RefList2} = getFriends(FriendsList, RefList, FriendsList, PID_S), friendship(FriendList2, RefList2, PID_S). @@ -197,11 +195,11 @@ io:format("X_Goal: ~p, Y_Goal: ~p~n", [X_Goal, Y_Goal]), Spawn_loop = fun Spawn_loop() -> - %PID_S = spawn(?MODULE, state, [dict:new(), X_Goal, Y_Goal, H, W]), - %{PID_D, Ref_monitor} = spawn_monitor(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W, PID_S]), + PID_S = spawn(?MODULE, state, [dict:new(), X_Goal, Y_Goal, H, W]), + {PID_D, Ref_monitor} = spawn_monitor(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W, PID_S]), {PID_F, Ref_monitor} = spawn_monitor(?MODULE, friendship, [[],[], rand:uniform(100)]), - %render ! {target, PID_D, X_Goal, Y_Goal}, - %render ! {position, PID_D, X_Spawn, Y_Spawn}, + render ! {target, PID_D, X_Goal, Y_Goal}, + render ! {position, PID_D, X_Spawn, Y_Spawn}, receive {'DOWN', _, _, PID, Reason } -> io:format("Died PID: ~p, Reason: ~p~n", [PID, Reason]), From e0de0cc8a827faf387c0f3e4229202cb12121c4e Mon Sep 17 00:00:00 2001 From: MarcoTomasone Date: Fri, 12 May 2023 15:32:58 +0200 Subject: [PATCH 14/18] [ADD] Completed getFriends & myFriends friends protocols @minosse99 @Lucajett99 --- Actors/car.erl | 8 ++++++-- Actors/wellknown.erl | 24 +++++++++++++++++++++--- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/Actors/car.erl b/Actors/car.erl index 085481c..d0f30aa 100644 --- a/Actors/car.erl +++ b/Actors/car.erl @@ -12,11 +12,13 @@ FriendList2 = lists:sublist([Y||{_,Y} <- lists:sort([ {rand:uniform(), N} || N <- TotalFriends])], 5), %Monitor all the friends in the list and save the ref in RefList RefList2 = lists:map(fun({PIDF, _}) -> monitor(process, PIDF) end, FriendList2), + io:format("FRI: I'm ~p my friends are:~p~n ", [self(), FriendList2]), case length(FriendList2) < 5 of true -> getFriends(FriendList2, RefList2, L, PID_S); false -> {FriendList2, RefList2} end - end. + end, + timer:sleep(5000). getFriends(FriendsList, RefList, L, PID_S) -> @@ -39,6 +41,8 @@ end. friendship(FriendsList, RefList, PID_S) -> + %io:format("FRI: start friendship with PID: ~p~n", [self()]), + link(PID_S), {FriendList2, RefList2} = getFriends(FriendsList, RefList, FriendsList, PID_S), friendship(FriendList2, RefList2, PID_S). @@ -197,7 +201,7 @@ Spawn_loop = fun Spawn_loop() -> PID_S = spawn(?MODULE, state, [dict:new(), X_Goal, Y_Goal, H, W]), {PID_D, Ref_monitor} = spawn_monitor(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W, PID_S]), - {PID_F, Ref_monitor} = spawn_monitor(?MODULE, friendship, [[],[], rand:uniform(100)]), + PID_F = spawn(?MODULE, friendship, [[],[], PID_S]), render ! {target, PID_D, X_Goal, Y_Goal}, render ! {position, PID_D, X_Spawn, Y_Spawn}, receive diff --git a/Actors/wellknown.erl b/Actors/wellknown.erl index 3e31ee1..416f177 100644 --- a/Actors/wellknown.erl +++ b/Actors/wellknown.erl @@ -7,7 +7,10 @@ wellknown(PIDSLIST) -> receive %PID1 is the PID of friendship actor, PID2 is the PID of state actor {getFriends, PID1, PID2, Ref} -> - PID1 ! {myFriends, PIDSLIST, Ref}, + io:format("WK: getFriends received from PID: ~p~n", [PID1]), + PIDSLIST2 = [ {PIDF, PIDS} || {PIDF, PIDS} <- PIDSLIST, PIDF =/= PID1, PIDS=/=PID2], + PID1 ! {myFriends, PIDSLIST2, Ref}, + io:format("WK: Sent myFriends to PID: ~p, myFriends:~p~n", [PID1, PIDSLIST]), case lists:member({PID1, PID2}, PIDSLIST) of true -> wellknown(PIDSLIST); false -> @@ -18,13 +21,28 @@ wellknown(PIDSLIST) -> end; %case a PID I monitor dies {'DOWN', _, _, PID_Friendship, _Reason} -> - io:format("WK: Delete PID: ~p for reason: ~p~n", [PID_Friendship, _Reason]), %Create a new list that contains all elements form PIDSLIST except the one that died UpdatedList = [ {PIDF, PIDS} || {PIDF, PIDS} <- PIDSLIST, PIDF =/= PID_Friendship], + io:format("WK: Delete PID: ~p for reason: ~p~n", [PID_Friendship, _Reason]), wellknown(UpdatedList) end. main() -> PID_W = spawn(?MODULE, wellknown, [[]]), register(wellknown, PID_W), - io:format("WN: Wellknown started with PID ~p registered with wellknown~n", [PID_W]). + io:format("WN: Wellknown started with PID ~p registered with wellknown~n", [PID_W]), + Spawn_loop = fun Spawn_loop(N) -> + io:format("WN: Spawned car~n"), + {PID_F, Ref_monitor} = spawn_monitor(car, main_car, [5,5]), + timer:sleep(5000), + case n > 0 of + true -> Spawn_loop(N-1); + false -> receive + {'DOWN', _, _, PID, Reason } -> + io:format("Died PID: ~p, Reason: ~p~n", [PID, Reason]), + Spawn_loop(1); + X -> io:format("X: ~p~n", [X]) + end %end of receive + end %end of case + end, % end of fun + Spawn_loop(10). From b96b26dcaca10fdc0ad7f4dd7250b8cf32c9268b Mon Sep 17 00:00:00 2001 From: MarcoTomasone Date: Mon, 15 May 2023 12:44:20 +0200 Subject: [PATCH 15/18] [FIX] Fixed friendship w/@Lucajett99 @minosse99 --- Actors/car.erl | 65 ++++++++++++++++++++++++++++---------------- Actors/wellknown.erl | 38 +++++++++++++++++--------- 2 files changed, 67 insertions(+), 36 deletions(-) diff --git a/Actors/car.erl b/Actors/car.erl index d0f30aa..4b10a79 100644 --- a/Actors/car.erl +++ b/Actors/car.erl @@ -12,13 +12,14 @@ FriendList2 = lists:sublist([Y||{_,Y} <- lists:sort([ {rand:uniform(), N} || N <- TotalFriends])], 5), %Monitor all the friends in the list and save the ref in RefList RefList2 = lists:map(fun({PIDF, _}) -> monitor(process, PIDF) end, FriendList2), - io:format("FRI: I'm ~p my friends are:~p~n ", [self(), FriendList2]), + %io:format("FRI: I'm ~p my friends are:~p~n ", [self(), FriendList2]), + timer:sleep(5000), case length(FriendList2) < 5 of true -> getFriends(FriendList2, RefList2, L, PID_S); false -> {FriendList2, RefList2} end - end, - timer:sleep(5000). + end. + getFriends(FriendsList, RefList, L, PID_S) -> @@ -34,6 +35,7 @@ %pick a random friend from the list {PIDF, _} = lists:nth(rand:uniform(Lenght), L), %delete the friend from the list + io:format("FRI: I'm ~p I'm sending getFriends to ~p~n", [self(), PIDF]), L2 = [ {PIDFR, PIDSTATE} || {PIDFR, PIDSTATE} <- L, PIDFR =/= PIDF], Ref = make_ref(), PIDF ! {getFriends, self(), PID_S, Ref}, @@ -42,9 +44,26 @@ friendship(FriendsList, RefList, PID_S) -> %io:format("FRI: start friendship with PID: ~p~n", [self()]), - link(PID_S), - {FriendList2, RefList2} = getFriends(FriendsList, RefList, FriendsList, PID_S), - friendship(FriendList2, RefList2, PID_S). + %link(PID_S), + case length(FriendsList) of + 5 -> + io:format("FRI: I'm ~p I have 5 friends:~p~n ", [self(), FriendsList]), + receive + {getFriends, PIDF, PIDS, Ref} -> + io:format("FRI: I'm ~p receiving get friends from ~p~n", [self(), PIDF]), + PIDF ! {myFriends, FriendsList, Ref}, + friendship(FriendsList, RefList, PID_S); + %case a friend dies + {'DOWN', _, _, PID, Reason } -> + io:format("FRI: Died PID: ~p, Reason: ~p~n", [PID, Reason]), + %delete the friend from the list + L2 = [ {PIDFR, PIDSTATE} || {PIDFR, PIDSTATE} <- FriendsList, PIDFR =/= PID], + friendship(L2, RefList, PID_S) + end; + _ -> + {FriendList2, RefList2} = getFriends(FriendsList, RefList, FriendsList, PID_S), + friendship(FriendList2, RefList2, PID_S) + end. state(World_Knowledge, X_Goal, Y_Goal, H, W) -> @@ -195,24 +214,24 @@ process_flag(trap_exit, true), {X_Spawn, Y_Spawn} = generate_coordinates(H, W), {X_Goal, Y_Goal} = generate_coordinates(H, W), - io:format("X_Spawn: ~p, Y_Spawn: ~p~n", [X_Spawn, Y_Spawn]), - io:format("X_Goal: ~p, Y_Goal: ~p~n", [X_Goal, Y_Goal]), - - Spawn_loop = fun Spawn_loop() -> - PID_S = spawn(?MODULE, state, [dict:new(), X_Goal, Y_Goal, H, W]), - {PID_D, Ref_monitor} = spawn_monitor(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W, PID_S]), - PID_F = spawn(?MODULE, friendship, [[],[], PID_S]), - render ! {target, PID_D, X_Goal, Y_Goal}, - render ! {position, PID_D, X_Spawn, Y_Spawn}, - receive - {'DOWN', _, _, PID, Reason } -> - io:format("Died PID: ~p, Reason: ~p~n", [PID, Reason]), - Spawn_loop(); - X -> io:format("X: ~p~n", [X]) + %io:format("X_Spawn: ~p, Y_Spawn: ~p~n", [X_Spawn, Y_Spawn]), + %io:format("X_Goal: ~p, Y_Goal: ~p~n", [X_Goal, Y_Goal]), + + %Spawn_loop = fun Spawn_loop() -> + %PID_S = spawn(?MODULE, state, [dict:new(), X_Goal, Y_Goal, H, W]), + %{PID_D, Ref_monitor} = spawn_monitor(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W, PID_S]), + PID_F = spawn(?MODULE, friendship, [[],[], 10]). + %render ! {target, PID_D, X_Goal, Y_Goal}, + %render ! {position, PID_D, X_Spawn, Y_Spawn}, + %receive + % {'DOWN', _, _, PID, Reason } -> + % io:format("Died PID: ~p, Reason: ~p~n", [PID, Reason]), + % Spawn_loop(); + % X -> io:format("X: ~p~n", [X]) - end - end, - Spawn_loop(). + % end + %end, + %Spawn_loop(). diff --git a/Actors/wellknown.erl b/Actors/wellknown.erl index 416f177..466ba09 100644 --- a/Actors/wellknown.erl +++ b/Actors/wellknown.erl @@ -8,9 +8,9 @@ wellknown(PIDSLIST) -> %PID1 is the PID of friendship actor, PID2 is the PID of state actor {getFriends, PID1, PID2, Ref} -> io:format("WK: getFriends received from PID: ~p~n", [PID1]), - PIDSLIST2 = [ {PIDF, PIDS} || {PIDF, PIDS} <- PIDSLIST, PIDF =/= PID1, PIDS=/=PID2], + PIDSLIST2 = [ {PIDF, PIDS} || {PIDF, PIDS} <- PIDSLIST, PIDF =/= PID1], PID1 ! {myFriends, PIDSLIST2, Ref}, - io:format("WK: Sent myFriends to PID: ~p, myFriends:~p~n", [PID1, PIDSLIST]), + %io:format("WK: Sent myFriends to PID: ~p, myFriends:~p~n", [PID1, PIDSLIST]), case lists:member({PID1, PID2}, PIDSLIST) of true -> wellknown(PIDSLIST); false -> @@ -31,18 +31,30 @@ main() -> PID_W = spawn(?MODULE, wellknown, [[]]), register(wellknown, PID_W), io:format("WN: Wellknown started with PID ~p registered with wellknown~n", [PID_W]), - Spawn_loop = fun Spawn_loop(N) -> - io:format("WN: Spawned car~n"), - {PID_F, Ref_monitor} = spawn_monitor(car, main_car, [5,5]), - timer:sleep(5000), - case n > 0 of - true -> Spawn_loop(N-1); - false -> receive + Spawn_loop = fun Spawn_loop(N, List) -> + + case N > 0 of + true -> + {PID_F, Ref_monitor} = spawn_monitor(car, friendship, [[],[],10]), + io:format("WN: Spawned car with PID: ~p~n", [PID_F]), + List2 = lists:append(List, [PID_F]), + timer:sleep(5000), + Spawn_loop(N-1, List2); + false -> + %choose the first car from the list, kill and remove it + case length(List) of + 12 -> + PID_F2 = lists:nth(7, List), + exit(PID_F2, kill), + List3 = [ {PIDF, PIDS} || {PIDF, PIDS} <- List, PIDF =/= PID_F2], + Spawn_loop(0, List3); + _-> ok + end, + receive {'DOWN', _, _, PID, Reason } -> - io:format("Died PID: ~p, Reason: ~p~n", [PID, Reason]), - Spawn_loop(1); - X -> io:format("X: ~p~n", [X]) + io:format("WN: Died PID: ~p, Reason: ~p~n", [PID, Reason]), + Spawn_loop(0, List) end %end of receive end %end of case end, % end of fun - Spawn_loop(10). + Spawn_loop(12, []). From 9364f8ec28301135df7a13db18f0057ff0153eb7 Mon Sep 17 00:00:00 2001 From: Lucajett99 Date: Tue, 16 May 2023 15:50:47 +0200 Subject: [PATCH 16/18] added gossiping --- Actors/ambient.erl | 1 + Actors/car.erl | 88 +++++++++++++++++++++++++++++--------------- Actors/main.erl | 47 +++++++++++++++++++++++ Actors/wellknown.erl | 1 - 4 files changed, 107 insertions(+), 30 deletions(-) create mode 100644 Actors/main.erl diff --git a/Actors/ambient.erl b/Actors/ambient.erl index 50dfdb2..0848316 100644 --- a/Actors/ambient.erl +++ b/Actors/ambient.erl @@ -70,3 +70,4 @@ io:format("AMB: Ambient PID: ~p~n", [PID_A]), %DEBUG register(ambient, PID_A), %register the ambient actor with the name ambient io:format("AMB: Correctly registered ~p as 'ambient' ~n", [PID_A]). %DEBUG + \ No newline at end of file diff --git a/Actors/car.erl b/Actors/car.erl index 4b10a79..4441e76 100644 --- a/Actors/car.erl +++ b/Actors/car.erl @@ -1,5 +1,5 @@ -module(car). - -export([main_car/2, friendship/3, state/5, detect/7, getFriends/4]). +-export([main/2, friendship/3, state/6, detect/7, getFriends/4]). receive_friends(FriendsList, RefList, L, PID_S) -> receive @@ -62,43 +62,72 @@ end; _ -> {FriendList2, RefList2} = getFriends(FriendsList, RefList, FriendsList, PID_S), + io:format("FRI: Boldro:~p~n ", [FriendList2]), + PID_S ! {listModified, FriendList2}, %Send to state the new list of friends friendship(FriendList2, RefList2, PID_S) + end. - state(World_Knowledge, X_Goal, Y_Goal, H, W) -> + state(World_Knowledge, X_Goal, Y_Goal, H, W, FriendList) -> io:format("Start State~n"), receive - {updateState, PID_D, X, Y, isFree} -> - io:fwrite("Update Value for park (~p,~p), new value: ~p~n", [{X,Y}, isFree]), %Update parkings + {updateState, PID_D, X, Y, IsFree} -> + io:fwrite("Update Value for park (~p,~p), new value: ~p~n", [X,Y, IsFree]), %Update parkings %TODO: send the new info to friends - case isFree of + io:format("CAR: List: ~p~n", [FriendList]), + case {IsFree, dict:fetch({X,Y}, World_Knowledge)==IsFree} of %If a park becames free, the state actor updates the knowledge of the world %It doesn't update the goal coordinates because this case doesn't affect s - true -> - state(dict:store({X,Y}, isFree, World_Knowledge), X_Goal, Y_Goal, H, W); + {_,true} -> state(World_Knowledge, X_Goal, Y_Goal, H, W, FriendList); + {true, false}-> + World_Knowledge2 = dict:store({X,Y}, IsFree, World_Knowledge), + lists:foreach(fun({_, PIDSTATE}) -> PIDSTATE ! {notifyStatus, X, Y, IsFree} end, FriendList), + state(World_Knowledge2, X_Goal, Y_Goal, H, W, FriendList); %If a park becames busy I have to check if it was the goal - false -> + {false,false} -> + World_Knowledge2 = dict:store({X,Y}, IsFree, World_Knowledge), + lists:foreach(fun({_, PIDSTATE}) -> PIDSTATE ! {notifyStatus, X, Y, IsFree} end, FriendList), case {X=:=X_Goal, Y =:= Y_Goal} of - %If the goal is busy, I have to generate a new goal + %If the goal is busy, I have to generate a new goal {true,true} -> io:fwrite("New Goal: ~p~n", [{X,Y}]), {X_Goal_New, Y_Goal_New} = generate_coordinates(H, W), PID_D ! {updateGoal, X_Goal_New, Y_Goal_New}, - state(dict:store({X,Y}, isFree, World_Knowledge), X_Goal_New, Y_Goal_New, H, W); + state(World_Knowledge2, X_Goal_New, Y_Goal_New, H, W,FriendList); %Else update the knowledge of the world {_,_} -> - state(dict:store({X,Y}, isFree, World_Knowledge), X_Goal, Y_Goal, H, W) + state(World_Knowledge2, X_Goal, Y_Goal, H, W,FriendList) end end; + %Case Car Exit from the parking and needs new goal {askNewGoal, PID_D, Ref} -> io:format("Ask New Goal with Ref ~p~n",[Ref]), {X_Goal_New, Y_Goal_New} = generate_coordinates(H, W), %TODO: check if new coordinates I generate should be free? PID_D ! {responseNewGoal, X_Goal_New, Y_Goal_New, Ref}, - state(World_Knowledge, X_Goal_New, Y_Goal_New, H, W); + state(World_Knowledge, X_Goal_New, Y_Goal_New, H, W,FriendList); + + {notifyStatus, X,Y, IsFree} -> + io:format("CAR: Notify Status {~p,~p} : ~p ~n", [X,Y,IsFree]), + case dict:fetch({X,Y}, World_Knowledge)==IsFree of + true -> + %Do nothing + state(World_Knowledge, X_Goal, Y_Goal, H, W,FriendList); + false -> + %World changes, notify to friends + World_Knowledge2 = dict:store({X,Y}, IsFree, World_Knowledge), + lists:foreach(fun({_, PIDSTATE}) -> PIDSTATE ! {notifyStatus, X, Y, IsFree} end, FriendList), + state(World_Knowledge2, X_Goal, Y_Goal, H, W,FriendList) + end; + + %TODO: case a friend sends me a new list of friends + {listModified, NewFriendList} -> + io:format("Received new list of friends: ~p~n", [NewFriendList]), + state(World_Knowledge, X_Goal, Y_Goal, H, W , NewFriendList); - _ -> state( World_Knowledge, X_Goal, Y_Goal, H, W) + %Default + _ -> state( World_Knowledge, X_Goal, Y_Goal, H, W,FriendList) end. generate_coordinates(H, W) -> @@ -174,7 +203,7 @@ %@param Y: actual Y coordinate of the car % detect(X, Y, X_Goal, Y_Goal, H, W, PID_S) -> - io:format("Start Detect with goal (~p,~p)~n", [X_Goal, Y_Goal]), + %io:format("Start Detect with goal (~p,~p)~n", [X_Goal, Y_Goal]), link(PID_S), timer:sleep(2000), {X_New, Y_New} = move(X, Y, {X_Goal, Y_Goal}, H, W), %TODO: H and W must be passed as parameters? @@ -210,28 +239,29 @@ end. %The main actor creates other actors and re-creates them if they fail - main_car(H, W) -> + main(H, W) -> process_flag(trap_exit, true), {X_Spawn, Y_Spawn} = generate_coordinates(H, W), {X_Goal, Y_Goal} = generate_coordinates(H, W), %io:format("X_Spawn: ~p, Y_Spawn: ~p~n", [X_Spawn, Y_Spawn]), %io:format("X_Goal: ~p, Y_Goal: ~p~n", [X_Goal, Y_Goal]), - %Spawn_loop = fun Spawn_loop() -> - %PID_S = spawn(?MODULE, state, [dict:new(), X_Goal, Y_Goal, H, W]), - %{PID_D, Ref_monitor} = spawn_monitor(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W, PID_S]), - PID_F = spawn(?MODULE, friendship, [[],[], 10]). - %render ! {target, PID_D, X_Goal, Y_Goal}, - %render ! {position, PID_D, X_Spawn, Y_Spawn}, - %receive - % {'DOWN', _, _, PID, Reason } -> - % io:format("Died PID: ~p, Reason: ~p~n", [PID, Reason]), - % Spawn_loop(); - % X -> io:format("X: ~p~n", [X]) + Spawn_loop = fun Spawn_loop() -> + World_Knowledge = dict:from_list([{{X, Y}, undefined} || X <- lists:seq(0, H-1), Y <- lists:seq(0, W-1)]), + PID_S = spawn(?MODULE, state, [World_Knowledge, X_Goal, Y_Goal, H, W, []]), + {PID_D, Ref_monitor} = spawn_monitor(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W, PID_S]), + PID_F = spawn(?MODULE, friendship, [[],[], PID_S]), + render ! {target, PID_D, X_Goal, Y_Goal}, + render ! {position, PID_D, X_Spawn, Y_Spawn}, + receive + {'DOWN', _, _, PID, Reason } -> + io:format("Died PID: ~p, Reason: ~p~n", [PID, Reason]), + Spawn_loop(); + X -> io:format("X: ~p~n", [X]) - % end - %end, - %Spawn_loop(). + end + end, + Spawn_loop(). diff --git a/Actors/main.erl b/Actors/main.erl new file mode 100644 index 0000000..5895168 --- /dev/null +++ b/Actors/main.erl @@ -0,0 +1,47 @@ +-module(main). +-export([main/0]). + +main() -> + H = 5, + W = 5, + Chessboard = dict:from_list([{{X, Y}, undefined} || X <- lists:seq(0, H-1), Y <- lists:seq(0, W-1)]), + + PID_R = spawn(render, main, [[{X, Y} || X <- lists:seq(0, H-1), Y <- lists:seq(0, W-1)], dict:new()]), + register(render, PID_R), + io:format("MAIN: Correctly registered ~p as 'render' ~n", [PID_R]), %DEBUG + render ! {dict:to_list(Chessboard)}, %DEBUG + + PID_A = spawn(ambient, ambient, [Chessboard]), %spawn the ambient actor + register(ambient, PID_A), %register the ambient actor with the name ambient + io:format("MAIN: Correctly registered ~p as 'ambient' ~n", [PID_A]), %DEBUG + + PID_W = spawn(wellknown, wellknown, [[]]), + register(wellknown, PID_W), + io:format("MAIN: Wellknown started with PID ~p registered with wellknown~n", [PID_W]), + + Spawn_loop = fun Spawn_loop(N, List) -> + case N > 0 of + true -> + {PID_M, Ref_monitor} = spawn_monitor(car, main, [H,W]), + io:format("WN: Spawned car with PID: ~p~n", [PID_M]), + List2 = lists:append(List, [PID_M]), + timer:sleep(5000), + Spawn_loop(N-1, List2); + false -> + %choose the first car from the list, kill and remove it + case length(List) of + 12 -> + PID_M2 = lists:nth(7, List), + exit(PID_M2, kill), + List3 = [ {PIDF, PIDS} || {PIDF, PIDS} <- List, PIDF =/= PID_M2], + Spawn_loop(0, List3); + _-> ok + end, + receive + {'DOWN', _, _, PID, Reason } -> + io:format("WN: Died PID: ~p, Reason: ~p~n", [PID, Reason]), + Spawn_loop(0, List) + end %end of receive + end %end of case + end, % end of fun + Spawn_loop(12, []). diff --git a/Actors/wellknown.erl b/Actors/wellknown.erl index 466ba09..63c8276 100644 --- a/Actors/wellknown.erl +++ b/Actors/wellknown.erl @@ -32,7 +32,6 @@ main() -> register(wellknown, PID_W), io:format("WN: Wellknown started with PID ~p registered with wellknown~n", [PID_W]), Spawn_loop = fun Spawn_loop(N, List) -> - case N > 0 of true -> {PID_F, Ref_monitor} = spawn_monitor(car, friendship, [[],[],10]), From 6c6afbc1b779c44bcc9096cd89c2c313c86c672f Mon Sep 17 00:00:00 2001 From: MarcoTomasone Date: Tue, 16 May 2023 19:39:46 +0200 Subject: [PATCH 17/18] [ADD] Ended gossip, FIXED render using IDs w/ @minosse99 @Lucajett99 --- Actors/ambient.erl | 57 +++++++++--------------- Actors/car.erl | 100 +++++++++++++++++++++++++++---------------- Actors/main.erl | 87 +++++++++++++++++++++++-------------- Actors/render.erl | 85 +++++++++++++++--------------------- Actors/wellknown.erl | 46 +++++++------------- 5 files changed, 189 insertions(+), 186 deletions(-) diff --git a/Actors/ambient.erl b/Actors/ambient.erl index 0848316..b7bf1bb 100644 --- a/Actors/ambient.erl +++ b/Actors/ambient.erl @@ -1,45 +1,36 @@ -%Un attore ambiente omniscente che rappresenta lo stato reale del mondo. In particolare l'ambiente conosce per ogni cella/posteggio il suo stato (libero o occupato). -% L'atomo ambient è registrato come PID dell'attore. -% -module(ambient). --export([main/2, ambient/1]). --define(W, 5). +-export([main/1, ambient/1]). + %%%%% + % Ambient actor, an omniscient actor that represents the real state of the world. In particular, + % the ambient knows for each cell/parking its state (free or occupied). + % @param Chessboard: dict that represents the state of the world. The key is a tuple {X,Y} that represents the position of the parking ambient(Chessboard) -> receive {isFree, PID, X, Y, Ref} -> %Request a car sends to the ambient - io:format("AMB: Request from ~p for parking (~p,~p)~n",[PID,X,Y]), %DEBUG - io:format("AMB: Parking (~p,~p) is free: ~p~n", [X,Y, undefined =:= dict:fetch({X,Y}, Chessboard)]), %DEBUG - io:format("AMB: Reply to ~p with Ref ~p~n", [PID, Ref]), %DEBUG + %io:format("AMB: Request from ~p for parking (~p,~p)~n",[PID,X,Y]), %DEBUG + %io:format("AMB: Parking (~p,~p) is free: ~p~n", [X,Y, undefined =:= dict:fetch({X,Y}, Chessboard)]), %DEBUG + %io:format("AMB: Reply to ~p with Ref ~p~n", [PID, Ref]), %DEBUG PID ! {status, Ref, undefined =:= dict:fetch({X,Y}, Chessboard)}, %Reply to the car ambient(Chessboard); {park, PID, X, Y, Ref} -> - io:fwrite("AMB: Update Value for park ~p occupied by ~p~n", [{X,Y}, PID]), %Update parkings + %io:fwrite("AMB: Update Value for park ~p occupied by ~p~n", [{X,Y}, PID]), %Update parkings render ! {parked, PID, X, Y, true}, %DEBUG ambient(dict:store({X,Y}, PID, Chessboard)); {leave, PID, Ref} -> - io:fwrite("AMB: PID ~p exit from parking ~n", [PID]), %Update parkings + %io:fwrite("AMB: PID ~p exit from parking ~n", [PID]), %Update parkings case searchKey(Chessboard, PID) of {X, Y} -> - io:fwrite("AMB: Update Value for leave ~p free~n", [{X,Y}]), %Update parkings + %io:fwrite("AMB: Update Value for leave ~p free~n", [{X,Y}]), %Update parkings render ! {parked, PID, X, Y, false}, ambient(dict:store({X,Y}, undefined, Chessboard)); [] -> - io:fwrite("AMB: PID: ~p not parked before ~n", [PID]), + %io:fwrite("AMB: PID: ~p not parked before ~n", [PID]), ambient(Chessboard) end; _ -> io:fwrite("AMB: No Pattern Matching Found!\n") end. - %%%%%% - %@params Dict: dict to print - %Function to print each element of dict - %@dev: the fold function is used to iterate over the dict, the order of the elements is not guaranteed - % fold function takes as parameters a function, an accumulator and a dict - printDict(Dict) -> - io:fwrite("Dict:~n"), - dict:fold(fun(K, V, Acc) -> io:fwrite("Key ~p : Value: ~p~n", [K, V]), Acc end, [], Dict). - %%%%%% %@params Dict: dict to search %@params Value: value used search the key @@ -53,21 +44,13 @@ end end, [], Dict). - main(H, W) -> - %Chessboard Definition - Chessboard = dict:from_list([{{X, Y}, undefined} || X <- lists:seq(0, H-1), Y <- lists:seq(0, W-1)]), - printDict(Chessboard), %DEBUG - io:format("AMB: Chessboard size ~p~n", [dict:size(Chessboard)]), - - %Spawn the render actor - PID_R = spawn(render, main, [[{X, Y} || X <- lists:seq(0, H-1), Y <- lists:seq(0, W-1)], dict:new()]), - register(render, PID_R), - io:format("AMB: Correctly registered ~p as 'render' ~n", [PID_R]), %DEBUG - render ! {dict:to_list(Chessboard)}, %DEBUG - - %Spawn ambient actor + %%%%% + % Main of ambient actor it spawns the ambient actor and registers it with the name ambient + % @return PID_A : PID of ambient actor + main(Chessboard) -> PID_A = spawn(?MODULE, ambient, [Chessboard]), %spawn the ambient actor - io:format("AMB: Ambient PID: ~p~n", [PID_A]), %DEBUG - register(ambient, PID_A), %register the ambient actor with the name ambient - io:format("AMB: Correctly registered ~p as 'ambient' ~n", [PID_A]). %DEBUG + register(ambient, PID_A), %register the ambient actor with the name ambient + io:format("AMBIENT: Correctly registered ~p as 'ambient' ~n", [PID_A]), %DEBUG + PID_A. + \ No newline at end of file diff --git a/Actors/car.erl b/Actors/car.erl index 4441e76..6e6480e 100644 --- a/Actors/car.erl +++ b/Actors/car.erl @@ -1,5 +1,5 @@ -module(car). --export([main/2, friendship/3, state/6, detect/7, getFriends/4]). +-export([main/2,friendship/2, friendship/3, state/4, state/7, detect/7, getFriends/4]). receive_friends(FriendsList, RefList, L, PID_S) -> receive @@ -13,6 +13,7 @@ %Monitor all the friends in the list and save the ref in RefList RefList2 = lists:map(fun({PIDF, _}) -> monitor(process, PIDF) end, FriendList2), %io:format("FRI: I'm ~p my friends are:~p~n ", [self(), FriendList2]), + PID_S ! {listModified, FriendList2}, timer:sleep(5000), case length(FriendList2) < 5 of true -> getFriends(FriendList2, RefList2, L, PID_S); @@ -44,7 +45,7 @@ friendship(FriendsList, RefList, PID_S) -> %io:format("FRI: start friendship with PID: ~p~n", [self()]), - %link(PID_S), + case length(FriendsList) of 5 -> io:format("FRI: I'm ~p I have 5 friends:~p~n ", [self(), FriendsList]), @@ -62,43 +63,51 @@ end; _ -> {FriendList2, RefList2} = getFriends(FriendsList, RefList, FriendsList, PID_S), - io:format("FRI: Boldro:~p~n ", [FriendList2]), PID_S ! {listModified, FriendList2}, %Send to state the new list of friends friendship(FriendList2, RefList2, PID_S) end. - - state(World_Knowledge, X_Goal, Y_Goal, H, W, FriendList) -> - io:format("Start State~n"), + + %%%% + % @param: PID_S: PID of the state actor + % @dev: This function is used to link friendship actor to the state actor and to the detect actor. + % Now, F is linked to S and F is linked to D. Given that F and D are linked, S is linked to D. + % After that it calls friendship/3 that is the main function of the friendship actor + friendship(PID_S, PID_D) -> + link(PID_S), + link(PID_D), + friendship([], [], PID_S). + + + state(PID_D, World_Knowledge, X_Goal, Y_Goal, H, W, FriendList) -> + %io:format("Start State~n"), receive {updateState, PID_D, X, Y, IsFree} -> - io:fwrite("Update Value for park (~p,~p), new value: ~p~n", [X,Y, IsFree]), %Update parkings - %TODO: send the new info to friends - io:format("CAR: List: ~p~n", [FriendList]), + %io:fwrite("Update Value for park (~p,~p), new value: ~p~n", [X,Y, IsFree]), %Update parkings case {IsFree, dict:fetch({X,Y}, World_Knowledge)==IsFree} of %If a park becames free, the state actor updates the knowledge of the world %It doesn't update the goal coordinates because this case doesn't affect s - {_,true} -> state(World_Knowledge, X_Goal, Y_Goal, H, W, FriendList); + {_,true} -> state(PID_D, World_Knowledge, X_Goal, Y_Goal, H, W, FriendList); {true, false}-> World_Knowledge2 = dict:store({X,Y}, IsFree, World_Knowledge), lists:foreach(fun({_, PIDSTATE}) -> PIDSTATE ! {notifyStatus, X, Y, IsFree} end, FriendList), - state(World_Knowledge2, X_Goal, Y_Goal, H, W, FriendList); + state(PID_D, World_Knowledge2, X_Goal, Y_Goal, H, W, FriendList); %If a park becames busy I have to check if it was the goal {false,false} -> World_Knowledge2 = dict:store({X,Y}, IsFree, World_Knowledge), lists:foreach(fun({_, PIDSTATE}) -> PIDSTATE ! {notifyStatus, X, Y, IsFree} end, FriendList), - case {X=:=X_Goal, Y =:= Y_Goal} of - %If the goal is busy, I have to generate a new goal - {true,true} -> - io:fwrite("New Goal: ~p~n", [{X,Y}]), - {X_Goal_New, Y_Goal_New} = generate_coordinates(H, W), - PID_D ! {updateGoal, X_Goal_New, Y_Goal_New}, - state(World_Knowledge2, X_Goal_New, Y_Goal_New, H, W,FriendList); - %Else update the knowledge of the world - {_,_} -> - state(World_Knowledge2, X_Goal, Y_Goal, H, W,FriendList) - end + case {X=:=X_Goal, Y =:= Y_Goal} of + %If the goal is busy, I have to generate a new goal + {true,true} -> + io:fwrite("DISCOVER I HAVE TO CREATE A NEW: ~p~n", [{X,Y}]), + {X_Goal_New, Y_Goal_New} = generate_coordinates(H, W), + PID_D ! {updateGoal, X_Goal_New, Y_Goal_New}, + state(PID_D, World_Knowledge2, X_Goal_New, Y_Goal_New, H, W,FriendList); + %Else update the knowledge of the world + {_,_} -> + state(PID_D, World_Knowledge2, X_Goal, Y_Goal, H, W,FriendList) + end end; %Case Car Exit from the parking and needs new goal @@ -106,30 +115,49 @@ io:format("Ask New Goal with Ref ~p~n",[Ref]), {X_Goal_New, Y_Goal_New} = generate_coordinates(H, W), %TODO: check if new coordinates I generate should be free? PID_D ! {responseNewGoal, X_Goal_New, Y_Goal_New, Ref}, - state(World_Knowledge, X_Goal_New, Y_Goal_New, H, W,FriendList); + state(PID_D, World_Knowledge, X_Goal_New, Y_Goal_New, H, W,FriendList); {notifyStatus, X,Y, IsFree} -> - io:format("CAR: Notify Status {~p,~p} : ~p ~n", [X,Y,IsFree]), + %io:format("CAR: Notify Status {~p,~p} : ~p ~n", [X,Y,IsFree]), case dict:fetch({X,Y}, World_Knowledge)==IsFree of true -> %Do nothing - state(World_Knowledge, X_Goal, Y_Goal, H, W,FriendList); + state(PID_D, World_Knowledge, X_Goal, Y_Goal, H, W,FriendList); false -> - %World changes, notify to friends + %World changed, notify to friends World_Knowledge2 = dict:store({X,Y}, IsFree, World_Knowledge), lists:foreach(fun({_, PIDSTATE}) -> PIDSTATE ! {notifyStatus, X, Y, IsFree} end, FriendList), - state(World_Knowledge2, X_Goal, Y_Goal, H, W,FriendList) + case {X=:=X_Goal, Y =:= Y_Goal} of + %If the goal is busy, I have to generate a new goal + {true,true} -> + io:fwrite("NOTIFIED I HAVE TO CREATE A NEW: ~p~n", [{X,Y}]), + {X_Goal_New, Y_Goal_New} = generate_coordinates(H, W), + PID_D ! {updateGoal, X_Goal_New, Y_Goal_New}, + state(PID_D, World_Knowledge2, X_Goal_New, Y_Goal_New, H, W,FriendList); + %Else update the knowledge of the world + {_,_} -> + state(PID_D, World_Knowledge2, X_Goal, Y_Goal, H, W,FriendList) + end end; %TODO: case a friend sends me a new list of friends {listModified, NewFriendList} -> - io:format("Received new list of friends: ~p~n", [NewFriendList]), - state(World_Knowledge, X_Goal, Y_Goal, H, W , NewFriendList); + %io:format("Received new list of friends: ~p~n", [NewFriendList]), + state(PID_D, World_Knowledge, X_Goal, Y_Goal, H, W , NewFriendList); %Default - _ -> state( World_Knowledge, X_Goal, Y_Goal, H, W,FriendList) + _ -> state(PID_D, World_Knowledge, X_Goal, Y_Goal, H, W,FriendList) end. + + state(X_Goal, Y_Goal, H, W) -> + World_Knowledge = dict:from_list([{{X, Y}, undefined} || X <- lists:seq(0, H-1), Y <- lists:seq(0, W-1)]), + receive + {pidDetect, PID_D} -> + state(PID_D, World_Knowledge, X_Goal, Y_Goal, H, W, []) + end. + + generate_coordinates(H, W) -> X = rand:uniform(H)-1, Y = rand:uniform(W)-1, @@ -204,7 +232,6 @@ % detect(X, Y, X_Goal, Y_Goal, H, W, PID_S) -> %io:format("Start Detect with goal (~p,~p)~n", [X_Goal, Y_Goal]), - link(PID_S), timer:sleep(2000), {X_New, Y_New} = move(X, Y, {X_Goal, Y_Goal}, H, W), %TODO: H and W must be passed as parameters? render ! {position, self(), X_New, Y_New}, @@ -241,22 +268,23 @@ %The main actor creates other actors and re-creates them if they fail main(H, W) -> process_flag(trap_exit, true), - {X_Spawn, Y_Spawn} = generate_coordinates(H, W), - {X_Goal, Y_Goal} = generate_coordinates(H, W), %io:format("X_Spawn: ~p, Y_Spawn: ~p~n", [X_Spawn, Y_Spawn]), %io:format("X_Goal: ~p, Y_Goal: ~p~n", [X_Goal, Y_Goal]), Spawn_loop = fun Spawn_loop() -> - World_Knowledge = dict:from_list([{{X, Y}, undefined} || X <- lists:seq(0, H-1), Y <- lists:seq(0, W-1)]), - PID_S = spawn(?MODULE, state, [World_Knowledge, X_Goal, Y_Goal, H, W, []]), + {X_Spawn, Y_Spawn} = generate_coordinates(H, W), + {X_Goal, Y_Goal} = generate_coordinates(H, W), + PID_S = spawn(?MODULE, state, [X_Goal, Y_Goal, H, W]), {PID_D, Ref_monitor} = spawn_monitor(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W, PID_S]), - PID_F = spawn(?MODULE, friendship, [[],[], PID_S]), + PID_S ! {pidDetect, PID_D}, + PID_F = spawn(?MODULE, friendship, [PID_S, PID_D]), render ! {target, PID_D, X_Goal, Y_Goal}, render ! {position, PID_D, X_Spawn, Y_Spawn}, receive {'DOWN', _, _, PID, Reason } -> io:format("Died PID: ~p, Reason: ~p~n", [PID, Reason]), Spawn_loop(); + %Print all other messages X -> io:format("X: ~p~n", [X]) end diff --git a/Actors/main.erl b/Actors/main.erl index 5895168..0f14bd1 100644 --- a/Actors/main.erl +++ b/Actors/main.erl @@ -2,46 +2,69 @@ -export([main/0]). main() -> - H = 5, - W = 5, + H = 10, + W = 10, Chessboard = dict:from_list([{{X, Y}, undefined} || X <- lists:seq(0, H-1), Y <- lists:seq(0, W-1)]), - PID_R = spawn(render, main, [[{X, Y} || X <- lists:seq(0, H-1), Y <- lists:seq(0, W-1)], dict:new()]), - register(render, PID_R), - io:format("MAIN: Correctly registered ~p as 'render' ~n", [PID_R]), %DEBUG - render ! {dict:to_list(Chessboard)}, %DEBUG - PID_A = spawn(ambient, ambient, [Chessboard]), %spawn the ambient actor - register(ambient, PID_A), %register the ambient actor with the name ambient - io:format("MAIN: Correctly registered ~p as 'ambient' ~n", [PID_A]), %DEBUG - - PID_W = spawn(wellknown, wellknown, [[]]), - register(wellknown, PID_W), - io:format("MAIN: Wellknown started with PID ~p registered with wellknown~n", [PID_W]), - + PID_A = ambient:main(Chessboard), %spawn the ambient actor + PID_W = wellknown:main(), + PID_R = render:main([{X, Y} || X <- lists:seq(0, H-1), Y <- lists:seq(0, W-1)], dict:new()), + Spawn_loop = fun Spawn_loop(N, List) -> case N > 0 of true -> {PID_M, Ref_monitor} = spawn_monitor(car, main, [H,W]), - io:format("WN: Spawned car with PID: ~p~n", [PID_M]), + io:format("MAIN: Spawned car with PID: ~p~n", [PID_M]), List2 = lists:append(List, [PID_M]), timer:sleep(5000), Spawn_loop(N-1, List2); false -> - %choose the first car from the list, kill and remove it - case length(List) of - 12 -> - PID_M2 = lists:nth(7, List), - exit(PID_M2, kill), - List3 = [ {PIDF, PIDS} || {PIDF, PIDS} <- List, PIDF =/= PID_M2], - Spawn_loop(0, List3); - _-> ok - end, - receive - {'DOWN', _, _, PID, Reason } -> - io:format("WN: Died PID: ~p, Reason: ~p~n", [PID, Reason]), - Spawn_loop(0, List) - end %end of receive - end %end of case - end, % end of fun - Spawn_loop(12, []). + List + end + end, + List = Spawn_loop(6, []), + + Kill_spawn_loop = fun Kill_spawn_loop(CarList) -> + %choose the first car from the list, kill and remove it + %N_Cars = rand:uniform(4), + N_Cars = 1, + + Kill_Loop = fun Kill_Loop(N_Cars_to_Kill, CarList2) -> + case N_Cars_to_Kill > 0 of + true -> + %Choose randomly a car to kill + PID_M2 = lists:nth(rand:uniform(length(CarList2)), CarList2), + exit(PID_M2, kill), + io:format("MAIN: Killed car with PID: ~p~n", [PID_M2]), + CarList3 = [ {PIDF, PIDS} || {PIDF, PIDS} <- CarList2, PIDF =/= PID_M2], + Kill_Loop(N_Cars_to_Kill-1, CarList3); + false -> + CarList2 + end + end, + + NewList = Kill_Loop(N_Cars, CarList), + Spawn_Loop = fun Spawn_Loop(N_Cars_to_Spawn, CarList2) -> + case N_Cars_to_Spawn > 0 of + true -> + {PID_M, Ref_monitor} = spawn_monitor(car, main, [H,W]), + io:format("MAIN: Spawned car with PID: ~p~n", [PID_M]), + CarList3 = lists:append(CarList2, [PID_M]), + timer:sleep(5000), + Spawn_loop(N_Cars_to_Spawn-1, CarList3); + false -> + CarList2 + end + end, + NewList2 = Spawn_Loop(N_Cars, NewList), + timer:sleep(10000), + Kill_spawn_loop(NewList2) + end, + Kill_spawn_loop(List). + + + + + + \ No newline at end of file diff --git a/Actors/render.erl b/Actors/render.erl index 4f6d92a..5589fac 100644 --- a/Actors/render.erl +++ b/Actors/render.erl @@ -3,7 +3,7 @@ % Path: Actors\render.erl -module(render). --export([main/2, order_chessboard/1]). +-export([main/2, render/3]). print_chessboard([{X,Y}|T], DictToList) -> case Y == 0 of @@ -14,9 +14,9 @@ print_chessboard([{X,Y}|T], DictToList) -> B = lists:keyfind({X,Y}, 3, DictToList), case {A,B} of {false, false} -> io:format("O\t"); - {{_,{X,Y},_}, {_,_,{X,Y}}} -> io:format("X*\t"); - {{_,{X,Y},_}, _} -> io:format("X\t"); - {_ , {_,_,{X,Y}}} -> io:format("*\t") + {{_,{X,Y},_, ID}, {_,_,{X,Y}, ID}} -> io:format("*~p*\t", [ID]); + {{_,{X,Y},_, ID}, _} -> io:format("~p\t", [ID]); + {_ , {_,_,{X,Y}, ID}} -> io:format("~p*\t", [ID]) end, %io:format("A IS EQUAL TO ~p~n", [Dict]), @@ -24,67 +24,52 @@ print_chessboard([{X,Y}|T], DictToList) -> print_chessboard([],_)-> io:format("\n"). -%Function to print a list -print_list([H|T]) -> - %map element of list {A, {B,C}} to {A, B, C} - io:fwrite("~p~n", [H]), - print_list(T); -print_list([]) -> ok. +transform_print(Chessboard, NewDict) -> + DictToList = dict:to_list(NewDict), + DictToList2 = lists:map(fun({A, {B,C,D}}) -> {A,B,C,D} end, DictToList), + print_chessboard(Chessboard, DictToList2). -order_chessboard(Chessboard) -> - lists:sort(fun({_, {X1,Y1}}, { _, {X2,Y2}}) -> - case X1 < X2 of - true -> true; - false -> - case X1 == X2 of - true -> Y1 < Y2; - false -> false - end - end - end, - Chessboard). - -main(Chessboard, Dict) -> - % PID -> {{POS},{GOAL}} DICT STRUCTURE +render(Chessboard, Dict, N) -> + % PID -> {{POS},{GOAL}, int} DICT STRUCTURE receive % position of car sent by detect {position, PID, X, Y} -> case dict:find(PID, Dict) of error -> - Dict2 = dict:store(PID, {{X,Y}, {undefined, undefined}}, Dict), - Dict2; - {ok, {{_,_},{X_Goal, Y_Goal}}} -> - Dict2 = dict:store(PID, {{X,Y},{X_Goal, Y_Goal}}, Dict), - Dict2 - end, - DictToList = dict:to_list(Dict2), - DictToList2 = lists:map(fun({A, {B,C}}) -> {A,B,C} end, DictToList), - %print_list(DictToList2), - print_chessboard(Chessboard, DictToList2), - main(Chessboard, Dict2); + Dict2 = dict:store(PID, {{X,Y}, {undefined, undefined}, N}, Dict), + transform_print(Chessboard, Dict2), + render(Chessboard, Dict2, N+1); + {ok, {{_,_},{X_Goal, Y_Goal}, ID}} -> + Dict2 = dict:store(PID, {{X,Y},{X_Goal, Y_Goal}, ID}, Dict), + transform_print(Chessboard, Dict2), + render(Chessboard, Dict2, N) + end; + % target position of goal sent by detect {target, PID, X, Y} -> case dict:find(PID, Dict) of error -> - Dict2 = dict:store(PID, {{undefined, undefined},{X,Y}}, Dict), - Dict2; - {ok, {{X_Pos, Y_Pos}, {_,_}}} -> - Dict2 = dict:store(PID, {{X_Pos, Y_Pos},{X,Y}}, Dict), - Dict2 - end, - DictToList = dict:to_list(Dict2), - DictToList2 = lists:map(fun({A, {B,C}}) -> {A,B,C} end, DictToList), - %print_list(DictToList2), - print_chessboard(Chessboard, DictToList2), - main(Chessboard, Dict2); + Dict2 = dict:store(PID, {{undefined, undefined},{X,Y}, N}, Dict), + transform_print(Chessboard, Dict2), + render(Chessboard, Dict2, N+1); + {ok, {{X_Pos, Y_Pos}, {_,_}, ID}} -> + Dict2 = dict:store(PID, {{X_Pos, Y_Pos},{X,Y}, ID}, Dict), + transform_print(Chessboard, Dict2), + render(Chessboard, Dict2, N) + end; %sent by ambient when car park or restart {parked, PID, X, Y, IsParked} -> io:format("RENDER: Car ~p is parked at (~p, ~p): ~p~n", [PID, X, Y, IsParked]), - main(Chessboard, Dict); + render(Chessboard, Dict, N); %sent by friendship actor TODO: implement this {friendship, PID, PIDLIST} -> io:format("RENDER: Car ~p is friend with ~p~n", [PID, PIDLIST]), - main(Chessboard, Dict) - + render(Chessboard, Dict, N) end. + +main(Chessboard, Dict) -> + PID_R = spawn(render, render, [Chessboard, Dict, 1]), + register(render, PID_R), + io:format("RENDER: Correctly registered ~p as 'render' ~n", [PID_R]), + PID_R. %DEBUG \ No newline at end of file diff --git a/Actors/wellknown.erl b/Actors/wellknown.erl index 63c8276..9654934 100644 --- a/Actors/wellknown.erl +++ b/Actors/wellknown.erl @@ -2,16 +2,20 @@ -module(wellknown). -export([main/0, wellknown/1]). - +%%%%%%%% +%@param PIDSLIST: list of tuples {PIDF, PIDS} where PIDF is the PID of friendship actor and PIDS is the PID of state actor. +% Represents all the car that wellknown knows about. Initially it is empty wellknown(PIDSLIST) -> receive %PID1 is the PID of friendship actor, PID2 is the PID of state actor {getFriends, PID1, PID2, Ref} -> - io:format("WK: getFriends received from PID: ~p~n", [PID1]), + %io:format("WK: getFriends received from PID: ~p~n", [PID1]), + %Create a new list that contains all elements form PIDSLIST except the one that makes the request cause no one is friend with himself PIDSLIST2 = [ {PIDF, PIDS} || {PIDF, PIDS} <- PIDSLIST, PIDF =/= PID1], PID1 ! {myFriends, PIDSLIST2, Ref}, %io:format("WK: Sent myFriends to PID: ~p, myFriends:~p~n", [PID1, PIDSLIST]), - case lists:member({PID1, PID2}, PIDSLIST) of + case lists:member({PID1, PID2}, PIDSLIST) of + %If the PID is already in my list true -> wellknown(PIDSLIST); false -> %Monitor the friendship actor of the Car I added to my list so I can remove it if he dies @@ -19,41 +23,21 @@ wellknown(PIDSLIST) -> %Add the new actor to the list wellknown([{PID1, PID2}|PIDSLIST]) end; - %case a PID I monitor dies + %Case a PID I monitor dies {'DOWN', _, _, PID_Friendship, _Reason} -> + %io:format("WK: Delete PID: ~p for reason: ~p~n", [PID_Friendship, _Reason]), %Create a new list that contains all elements form PIDSLIST except the one that died UpdatedList = [ {PIDF, PIDS} || {PIDF, PIDS} <- PIDSLIST, PIDF =/= PID_Friendship], - io:format("WK: Delete PID: ~p for reason: ~p~n", [PID_Friendship, _Reason]), wellknown(UpdatedList) end. + +%%%%% +% Main of wellknown actor it spawns the wellknown actor and registers it with the name wellknown +%@return PID_W : PID of wellknown actor main() -> PID_W = spawn(?MODULE, wellknown, [[]]), register(wellknown, PID_W), io:format("WN: Wellknown started with PID ~p registered with wellknown~n", [PID_W]), - Spawn_loop = fun Spawn_loop(N, List) -> - case N > 0 of - true -> - {PID_F, Ref_monitor} = spawn_monitor(car, friendship, [[],[],10]), - io:format("WN: Spawned car with PID: ~p~n", [PID_F]), - List2 = lists:append(List, [PID_F]), - timer:sleep(5000), - Spawn_loop(N-1, List2); - false -> - %choose the first car from the list, kill and remove it - case length(List) of - 12 -> - PID_F2 = lists:nth(7, List), - exit(PID_F2, kill), - List3 = [ {PIDF, PIDS} || {PIDF, PIDS} <- List, PIDF =/= PID_F2], - Spawn_loop(0, List3); - _-> ok - end, - receive - {'DOWN', _, _, PID, Reason } -> - io:format("WN: Died PID: ~p, Reason: ~p~n", [PID, Reason]), - Spawn_loop(0, List) - end %end of receive - end %end of case - end, % end of fun - Spawn_loop(12, []). + PID_W. + From fd5722b907f7feebd750e24945e13a2dd89eaf7c Mon Sep 17 00:00:00 2001 From: MarcoTomasone Date: Wed, 17 May 2023 18:35:11 +0200 Subject: [PATCH 18/18] [FIX] Fixed Render, switched from link to monitor main car w/@Lucajett99 @minosse99 --- Actors/car.erl | 23 ++++++------ Actors/main.erl | 94 ++++++++++++++++++++--------------------------- Actors/render.erl | 64 ++++++++++++++++++++++---------- 3 files changed, 95 insertions(+), 86 deletions(-) diff --git a/Actors/car.erl b/Actors/car.erl index 6e6480e..c3e6d09 100644 --- a/Actors/car.erl +++ b/Actors/car.erl @@ -13,6 +13,7 @@ %Monitor all the friends in the list and save the ref in RefList RefList2 = lists:map(fun({PIDF, _}) -> monitor(process, PIDF) end, FriendList2), %io:format("FRI: I'm ~p my friends are:~p~n ", [self(), FriendList2]), + PID_S ! {listModified, FriendList2}, timer:sleep(5000), case length(FriendList2) < 5 of @@ -48,10 +49,10 @@ case length(FriendsList) of 5 -> - io:format("FRI: I'm ~p I have 5 friends:~p~n ", [self(), FriendsList]), + %io:format("FRI: I'm ~p I have 5 friends:~p~n ", [self(), FriendsList]), receive {getFriends, PIDF, PIDS, Ref} -> - io:format("FRI: I'm ~p receiving get friends from ~p~n", [self(), PIDF]), + %io:format("FRI: I'm ~p receiving get friends from ~p~n", [self(), PIDF]), PIDF ! {myFriends, FriendsList, Ref}, friendship(FriendsList, RefList, PID_S); %case a friend dies @@ -100,7 +101,7 @@ case {X=:=X_Goal, Y =:= Y_Goal} of %If the goal is busy, I have to generate a new goal {true,true} -> - io:fwrite("DISCOVER I HAVE TO CREATE A NEW: ~p~n", [{X,Y}]), + io:fwrite("DISCOVER I HAVE TO CREATE A NEW GOAL: ~p~n", [{X,Y}]), {X_Goal_New, Y_Goal_New} = generate_coordinates(H, W), PID_D ! {updateGoal, X_Goal_New, Y_Goal_New}, state(PID_D, World_Knowledge2, X_Goal_New, Y_Goal_New, H, W,FriendList); @@ -130,7 +131,7 @@ case {X=:=X_Goal, Y =:= Y_Goal} of %If the goal is busy, I have to generate a new goal {true,true} -> - io:fwrite("NOTIFIED I HAVE TO CREATE A NEW: ~p~n", [{X,Y}]), + %io:fwrite("NOTIFIED I HAVE TO CREATE A NEW GOAL: ~p~n", [{X,Y}]), {X_Goal_New, Y_Goal_New} = generate_coordinates(H, W), PID_D ! {updateGoal, X_Goal_New, Y_Goal_New}, state(PID_D, World_Knowledge2, X_Goal_New, Y_Goal_New, H, W,FriendList); @@ -143,6 +144,8 @@ %TODO: case a friend sends me a new list of friends {listModified, NewFriendList} -> %io:format("Received new list of friends: ~p~n", [NewFriendList]), + + render ! {friends, PID_D, NewFriendList}, %send to render the new list of friends state(PID_D, World_Knowledge, X_Goal, Y_Goal, H, W , NewFriendList); %Default @@ -262,7 +265,7 @@ _ -> detect(X_New, Y_New, X_Goal, Y_Goal, H, W, PID_S) end; - _ -> io:fwrite("No Pattern Matching Found~n") %TODO: Kill process? + X -> io:fwrite("~p~n",[X]) %TODO: Kill process? end. %The main actor creates other actors and re-creates them if they fail @@ -272,21 +275,19 @@ %io:format("X_Goal: ~p, Y_Goal: ~p~n", [X_Goal, Y_Goal]), Spawn_loop = fun Spawn_loop() -> + {X_Spawn, Y_Spawn} = generate_coordinates(H, W), {X_Goal, Y_Goal} = generate_coordinates(H, W), PID_S = spawn(?MODULE, state, [X_Goal, Y_Goal, H, W]), - {PID_D, Ref_monitor} = spawn_monitor(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W, PID_S]), + PID_D = spawn_link(?MODULE, detect, [X_Spawn, Y_Spawn, X_Goal, Y_Goal, H, W, PID_S]), PID_S ! {pidDetect, PID_D}, PID_F = spawn(?MODULE, friendship, [PID_S, PID_D]), render ! {target, PID_D, X_Goal, Y_Goal}, render ! {position, PID_D, X_Spawn, Y_Spawn}, receive - {'DOWN', _, _, PID, Reason } -> + {'EXIT', PID, Reason } -> io:format("Died PID: ~p, Reason: ~p~n", [PID, Reason]), - Spawn_loop(); - %Print all other messages - X -> io:format("X: ~p~n", [X]) - + Spawn_loop() end end, Spawn_loop(). diff --git a/Actors/main.erl b/Actors/main.erl index 0f14bd1..0055f19 100644 --- a/Actors/main.erl +++ b/Actors/main.erl @@ -1,67 +1,51 @@ -module(main). --export([main/0]). +-export([main/0, kill_spawn_loop/3, spawn_loop/4, kill_loop/2]). + +kill_spawn_loop(CarList, H, W) -> + N_Cars = rand:uniform(4), + NewList = kill_loop(N_Cars, CarList), + NewList2 = spawn_loop(N_Cars, NewList, H, W), + timer:sleep(10000), + kill_spawn_loop(NewList2, H, W). + +spawn_loop(N_Cars_to_Spawn, CarList, H, W) -> + case N_Cars_to_Spawn > 0 of + true -> + {PID_M, Ref_monitor} = spawn_monitor(car, main, [H,W]), + io:format("MAIN: Spawned car with PID: ~p~n", [PID_M]), + CarList2 = lists:append(CarList, [PID_M]), + timer:sleep(5000), + render ! {print}, + spawn_loop(N_Cars_to_Spawn-1, CarList2, H, W); + false -> + CarList + end. + +kill_loop(N_Cars_to_Kill, CarList) -> + case N_Cars_to_Kill > 0 of + true -> + %Choose randomly a car to kill + PID_M2 = lists:nth(rand:uniform(length(CarList)), CarList), + exit(PID_M2, kill), + io:format("MAIN: Killed car with PID: ~p~n", [PID_M2]), + CarList2 = [ PIDM || PIDM <- CarList, PIDM =/= PID_M2], + kill_loop(N_Cars_to_Kill-1, CarList2); + false -> + CarList + end. + + main() -> H = 10, W = 10, Chessboard = dict:from_list([{{X, Y}, undefined} || X <- lists:seq(0, H-1), Y <- lists:seq(0, W-1)]), - - + %TODO: MONITOR THE SPAWNED ACTORS ?? PID_A = ambient:main(Chessboard), %spawn the ambient actor PID_W = wellknown:main(), PID_R = render:main([{X, Y} || X <- lists:seq(0, H-1), Y <- lists:seq(0, W-1)], dict:new()), - - Spawn_loop = fun Spawn_loop(N, List) -> - case N > 0 of - true -> - {PID_M, Ref_monitor} = spawn_monitor(car, main, [H,W]), - io:format("MAIN: Spawned car with PID: ~p~n", [PID_M]), - List2 = lists:append(List, [PID_M]), - timer:sleep(5000), - Spawn_loop(N-1, List2); - false -> - List - end - end, - List = Spawn_loop(6, []), - - Kill_spawn_loop = fun Kill_spawn_loop(CarList) -> - %choose the first car from the list, kill and remove it - %N_Cars = rand:uniform(4), - N_Cars = 1, - - Kill_Loop = fun Kill_Loop(N_Cars_to_Kill, CarList2) -> - case N_Cars_to_Kill > 0 of - true -> - %Choose randomly a car to kill - PID_M2 = lists:nth(rand:uniform(length(CarList2)), CarList2), - exit(PID_M2, kill), - io:format("MAIN: Killed car with PID: ~p~n", [PID_M2]), - CarList3 = [ {PIDF, PIDS} || {PIDF, PIDS} <- CarList2, PIDF =/= PID_M2], - Kill_Loop(N_Cars_to_Kill-1, CarList3); - false -> - CarList2 - end - end, - - NewList = Kill_Loop(N_Cars, CarList), - Spawn_Loop = fun Spawn_Loop(N_Cars_to_Spawn, CarList2) -> - case N_Cars_to_Spawn > 0 of - true -> - {PID_M, Ref_monitor} = spawn_monitor(car, main, [H,W]), - io:format("MAIN: Spawned car with PID: ~p~n", [PID_M]), - CarList3 = lists:append(CarList2, [PID_M]), - timer:sleep(5000), - Spawn_loop(N_Cars_to_Spawn-1, CarList3); - false -> - CarList2 - end - end, - NewList2 = Spawn_Loop(N_Cars, NewList), - timer:sleep(10000), - Kill_spawn_loop(NewList2) - end, - Kill_spawn_loop(List). + List = spawn_loop(10, [], H, W), + kill_spawn_loop(List, H, W). diff --git a/Actors/render.erl b/Actors/render.erl index 5589fac..ab7872e 100644 --- a/Actors/render.erl +++ b/Actors/render.erl @@ -12,37 +12,42 @@ print_chessboard([{X,Y}|T], DictToList) -> end, A = lists:keyfind({X,Y}, 2, DictToList), B = lists:keyfind({X,Y}, 3, DictToList), + %The struct is {PID, {POS}, {GOAL}, [FRIENDS], ID} case {A,B} of {false, false} -> io:format("O\t"); - {{_,{X,Y},_, ID}, {_,_,{X,Y}, ID}} -> io:format("*~p*\t", [ID]); - {{_,{X,Y},_, ID}, _} -> io:format("~p\t", [ID]); - {_ , {_,_,{X,Y}, ID}} -> io:format("~p*\t", [ID]) + {{_,{X,Y},_,_, ID}, {_,_,{X,Y}, _, ID}} -> io:format("*~p*\t", [ID]); + {{_,{X,Y},_,_, ID}, _} -> io:format("~p\t", [ID]); + {_ , {_,_,{X,Y},_, ID}} -> io:format("~p*\t", [ID]) end, %io:format("A IS EQUAL TO ~p~n", [Dict]), print_chessboard(T, DictToList ); -print_chessboard([],_)-> io:format("\n"). + print_chessboard([],_)-> io:format("\n"). transform_print(Chessboard, NewDict) -> DictToList = dict:to_list(NewDict), - DictToList2 = lists:map(fun({A, {B,C,D}}) -> {A,B,C,D} end, DictToList), + DictToList2 = lists:map(fun({A, {B,C,D,E}}) -> io:format("R: Car ~p with PID ~p is Friend with ~p~n", [E,A,D]), {A,B,C,D,E} end, DictToList), print_chessboard(Chessboard, DictToList2). render(Chessboard, Dict, N) -> % PID -> {{POS},{GOAL}, int} DICT STRUCTURE receive + {print} -> + transform_print(Chessboard, Dict), + render(Chessboard, Dict, N); % position of car sent by detect {position, PID, X, Y} -> case dict:find(PID, Dict) of error -> - Dict2 = dict:store(PID, {{X,Y}, {undefined, undefined}, N}, Dict), - transform_print(Chessboard, Dict2), + Dict2 = dict:store(PID, {{X,Y}, {undefined, undefined}, [], N}, Dict), + monitor(process, PID), + %transform_print(Chessboard, Dict2), render(Chessboard, Dict2, N+1); - {ok, {{_,_},{X_Goal, Y_Goal}, ID}} -> - Dict2 = dict:store(PID, {{X,Y},{X_Goal, Y_Goal}, ID}, Dict), - transform_print(Chessboard, Dict2), + {ok, {{_,_},{X_Goal, Y_Goal}, FriendsList, ID}} -> + Dict2 = dict:store(PID, {{X,Y},{X_Goal, Y_Goal}, FriendsList, ID}, Dict), + %transform_print(Chessboard, Dict2), render(Chessboard, Dict2, N) end; @@ -50,26 +55,45 @@ render(Chessboard, Dict, N) -> {target, PID, X, Y} -> case dict:find(PID, Dict) of error -> - Dict2 = dict:store(PID, {{undefined, undefined},{X,Y}, N}, Dict), - transform_print(Chessboard, Dict2), + Dict2 = dict:store(PID, {{undefined, undefined},{X,Y}, [], N}, Dict), + monitor(process, PID), + %transform_print(Chessboard, Dict2), render(Chessboard, Dict2, N+1); - {ok, {{X_Pos, Y_Pos}, {_,_}, ID}} -> - Dict2 = dict:store(PID, {{X_Pos, Y_Pos},{X,Y}, ID}, Dict), - transform_print(Chessboard, Dict2), + {ok, {{X_Pos, Y_Pos}, {_,_}, FriendsList, ID}} -> + Dict2 = dict:store(PID, {{X_Pos, Y_Pos},{X,Y}, FriendsList, ID}, Dict), + %transform_print(Chessboard, Dict2), render(Chessboard, Dict2, N) end; %sent by ambient when car park or restart {parked, PID, X, Y, IsParked} -> - io:format("RENDER: Car ~p is parked at (~p, ~p): ~p~n", [PID, X, Y, IsParked]), + {_,_,_, Num} = dict:fetch(PID, Dict), + io:format("RENDER: Car N_~p with PID ~p is parked at (~p, ~p): ~p~n", [Num, PID, X, Y, IsParked]), render(Chessboard, Dict, N); %sent by friendship actor TODO: implement this - {friendship, PID, PIDLIST} -> - io:format("RENDER: Car ~p is friend with ~p~n", [PID, PIDLIST]), - render(Chessboard, Dict, N) + {friends, PID, PIDLIST} -> + case dict:find(PID, Dict) of + error -> + Dict2 = dict:store(PID, {{undefined, undefined}, {undefined, undefined}, PIDLIST, N}, Dict), + monitor(process, PID), + %transform_print(Chessboard, Dict2), + render(Chessboard, Dict2, N+1); + + {ok, {{X_Pos, Y_Pos}, {X_Goal, Y_Goal}, _, ID}} -> + Dict2 = dict:store(PID, {{X_Pos, Y_Pos},{X_Goal,Y_Goal}, PIDLIST ,ID}, Dict), + %transform_print(Chessboard, Dict2), + %io:format("RENDER: Car N_~p with PID: ~p is friend with ~p~n", [ID, PID, PIDLIST]), + render(Chessboard, Dict2, N) + end; + {'DOWN', _, _, PID, Reason } -> + {_,_,_, Num} = dict:fetch(PID, Dict), + io:format("RENDER: Died PID: ~p with N_~p, Reason: ~p~n", [PID, Num, Reason]), + %remove from dict + Dict2 = dict:erase(PID, Dict), + render(Chessboard, Dict2, N) end. main(Chessboard, Dict) -> PID_R = spawn(render, render, [Chessboard, Dict, 1]), register(render, PID_R), io:format("RENDER: Correctly registered ~p as 'render' ~n", [PID_R]), - PID_R. %DEBUG \ No newline at end of file + PID_R. %DEBUG