%% ------------------------------------------------------------- %% ------------------------------------------------------------- %% -- BACKTRACKING ATUNCI CÂND CUNOAȘTEM LUNGIMEA SOLUȚIEI -- %%% 1. (2p) %% Înțelegeți predicatele solve_maps/1, template/1 și correct/1. %% Observați că lipsește definiția predicatului safe/2. neighbours(1, [2, 3]). neighbours(2, [1, 3, 4]). neighbours(3, [1, 2, 4, 5, 6]). neighbours(4, [2, 3, 5]). neighbours(5, [3, 4, 6]). neighbours(6, [3, 5]). neighbours(7, []). %% template/1 %% template(?List) %% List are forma unei soluții pentru problema colorării hărților pentru 7 țări. %% Lungimea soluției este cunoscută și fixă. template([1/_, 2/_, 3/_, 4/_, 5/_, 6/_, 7/_]). %% correct/1 %% correct(?Solution) %% Solution reprezintă o soluție validă pentru problema colorării hărților. correct([]):-!. correct([X/Y|Others]):- correct(Others), member(Y, ["r", "g", "b"]), safe(X/Y, Others). %% solve_maps/1 %% solve_maps(-Solution) %% Solution este o soluție a problemei colorării hărților. solve_maps(S):-template(S), correct(S). %% Scrieți predicatul safe/2 utilizat în rezolvarea problemei colorării hărților. %% Predicatul va avea antetul safe(+X/Y, +Others) cu semnificația că se verifică %% dacă alegerea culorii Y pentru țara X este în concordanță cu culorile alese în %% lista Others (nicio țară nu are aceeași culoare cu niciun vecin). Lista Others %% are forma [X1/Y1, X2/ Y2/ ...]. %% safe/2 %% safe(+X/Y, +Others) safe(_,_) :- fail. check1:- \+ safe(5/"r", [6/"r"]), write('.'), \+ safe(4/"g", [5/"g"]), write('.'), safe(2/"b", [5/"b"]), write('.'), \+ safe(1/"b", [2/"b", 3/"r"]), write('.'), safe(7/"b", [3/"b"]), write('.'), safe(4/"g", [2/"b", 3/"r", 5/"b", 6/"g"]), write('.'), \+ safe(3/"r", [1/"b", 2/"b", 4/"g", 5/"r", 6/"b"]), write('.'), safe(3/"r", [1/"b", 2/"g", 3/"r", 4/"b", 5/"g", 6/"g", 7/"r"]), write('.'), findall(Sol, solve_maps(Sol), All), length(All, 18), write('.'), writeln('Exercițiul 1 rezolvat corect!'), !. %% Întrebați-l pe Prolog "solve_maps(Sol)" pentru a vizualiza soluțiile. %% ------------------------------------------------------------- %% ------------------------------------------------------------- %% -- BACKTRACKING ATUNCI CÂND NU CUNOAȘTEM LUNGIMEA SOLUȚIEI -- %%% 2. (6p) %% Înțelegeți cum funcționeză predicatele solve și search pentru rezolvarea %% unei probleme de căutare în spațiul stărilor. Observați utilizarea %% predicatelor initial_state/1, final_state/1 și next_state/2. search([CurrentState|Other], Solution):- final_state(CurrentState), !, reverse([CurrentState|Other], Solution). search([CurrentState|Other], Solution):- next_state(CurrentState, NextState), \+ member(NextState, Other), search([NextState,CurrentState|Other], Solution). solve(Solution):- initial_state(State), search([State], Solution). %% Exemplu: problema țăranului, a lupului, a caprei și a verzei. %% Vom reprezenta o stare astfel: %% state(MalBarcă, MalȚăran, MalLup, MalCapră, MalVarză) opus(est, vest). opus(vest, est). initial_state(state(est, est, est, est, est)). final_state(state(_, vest, vest, vest, vest)). %% Taranul calatoreste singur next_state(state(MalBarca1, MalBarca1, MalLup, MalCapra, MalVarza), state(MalBarca2, MalBarca2, MalLup, MalCapra, MalVarza)):- opus(MalBarca1, MalBarca2), opus(MalLup, MalCapra), opus(MalCapra, MalVarza). %% Taranul calatoreste cu lupul next_state(state(MalBarca1, MalBarca1, MalBarca1, MalCapra, MalVarza), state(MalBarca2, MalBarca2, MalBarca2, MalCapra, MalVarza)):- opus(MalBarca1, MalBarca2), opus(MalCapra, MalVarza). %% Taranul calatoreste cu capra next_state(state(MalBarca1, MalBarca1, MalLup, MalBarca1, MalVarza), state(MalBarca2, MalBarca2, MalLup, MalBarca2, MalVarza)):- opus(MalBarca1, MalBarca2). %% Taranul calatoreste cu varza next_state(state(MalBarca1, MalBarca1, MalLup, MalCapra, MalBarca1), state(MalBarca2, MalBarca2, MalLup, MalCapra, MalBarca2)):- opus(MalBarca1, MalBarca2), opus(MalLup, MalCapra). %% Rescrieți predicatele initial_state/1, final_state/1, și next_state/2 pentru %% a rezolva problema celor trei călători. %% Trei călători %% Trei călători se alfă pe același mal al unui râu și vor să ajungă pe celălalt. %% Primul călător are două valize, al doilea are una singură, iar cel de-al treilea %% nu are nicio valiză. Aceștia pot să folosească o barcă, care la o traversare a %% râului poate duce un calator, doi călători sau un călător și o valiză. Niciun călător %% nu poate să rămână singur cu valizele altuia. Găsiți cum pot aceștia să ajungă pe %% malul opus, cu tot cu valizele lor. %% Pentru o mai bună structură, implementați întâi predicatele boat/1 %% și safe/1 detaliate mai jos. %% Predicate utile: sort/2, @= 0, A < L1), N1f), findall((A, B), (member((A, B), N2), B >= 0, B < L2), N2f), append(N1f, N2f, N), findall((X1, Y1), (member((X1, Y1), N), get_grid((X1, Y1), Grid, 0)), Neigh). %% manhattan/3 %% manhattan(+P1, +P2, -Distance) %% Distance este distanța Manhattan între două puncte. manhattan((X1, Y1), (X2, Y2), D) :- D is abs(X1-X2)+abs(Y1-Y2). %% get_path/5 %% get_path(+Start, +End, +Discovered, +Aux, -Path) %% Path este drumul între Start și End get_path(Start, Start, _, Path, Path). get_path(Start, End, Discovered, Aux, Path) :- member(End:(Parent, _), Discovered), get_path(Start, Parent, Discovered, [Parent|Aux], Path). %% astar_search/4 %% astar_search(+Start, +End, +Grid, -Path) %% Path este calea dintre Start și End astar_search(Start, End, Grid, Path) :- manhattan(Start, End, H), astar(End, [H:Start], [Start:("None", 0)], Grid, Discovered), get_path(Start, End, Discovered, [End], Path). %% TODO %% astar/5 %% astar(+End, +Frontier, +Discovered, +Grid, -Result) %% End: punctul de final de pe hartă. %% Frontier: coadă de priorități, care va conține inițial elementul de start cu %% valoarea sa. (ex: [6:(5, 5)], 6 = distanța Manhattan de la Start: (5, 5) la End: (8, 8))) %% Discovered: dicționar în care se vor reține părintele nodului și costul real cu care a fost %% descoperit. (ex: [(5, 5):("None", 0)]) %% Grid: matrice care reprezintă harta. %% Result: va fi Discovered în momentul în care primul element din Frontier este End. %% Algoritm: %% 1. Cât timp Frontier nu este goală, se ia primul element din aceasta %% 2. Dacă elementul este cel final, căutarea se încheie %% 3. Se iau toți vecinii elementului și li se calculează costul(new_cost), adăugând 1 %% la costul părintelui din Discovered. Dacă vecinul nu este în Discovered, sau costul %% acestuia este mai mic decât cel deja existent, atunci noua valoare va fi adăugată în %% Discovered, apoi se va fi introdus în Frontier cu prioritatea calculată astfel: %% new_cost + manhattan(vecin, end) astar(_, _, _, _, _) :- fail. %% Testare replace([_|T], 0, X, [X|T]). replace([H|T], I, X, [H|R]) :- I > 0, I1 is I - 1, replace(T, I1, X, R). build(_,0,[]). build(X, N, List) :- findall(X, between(1, N, _), List). grid(X, N, M, Grid) :- build(X, M, Row), build(Row, N, Grid). replace_grid(X, N, M, Grid, R) :- nth0(N, Grid, Row), replace(Row, M, X, NewRow), replace(Grid, N, NewRow, R), !. replace_more(R1, R1, _, Grid, Grid) :- !. replace_more(R1, R2, X, Grid, LastGrid) :- R1 =< R2, R11 is R1 + 1, replace_grid(1, R1, X, Grid, NewGrid), replace_grid(1, X, R1, NewGrid, NewGrid1), replace_more(R11, R2, X, NewGrid1, LastGrid). check4 :- grid(0, 10, 20, Grid), replace_more(2, 7, 6, Grid, FinalGrid), astar_search((5, 5), (8, 8), FinalGrid, Path), length(Path, L), L == 15, writeln('.Exercițiul 4 (BONUS) rezolvat corect!'), !. %% ------------------------------------------------------------- %% ------------------------------------------------------------- :- dynamic punct/2. tests(Ex, [], _) :- !, format('Exercitiul ~w a fost rezolvat corect.~n', [Ex]). tests(Ex, [T | R], Idx) :- Idx1 is Idx + 1, ( call(T), !, write('.'), tests(Ex, R, Idx1); format('Esec la exercitiul ~w testul ~w: ~n ~w~n', [Ex, Idx1, T]), !, fail). tests(Ex, L) :- tests(Ex, L, 0). check:- retractall(punct(_, _)), once((check1, assert(punct(1, 2)) ; assert(punct(1, 0)))), once((check2, assert(punct(2, 6)) ; assert(punct(2, 0)))), once((check3, assert(punct(3, 2)) ; assert(punct(3, 0)))), once((check4, assert(punct(4, 5)) ; assert(punct(4, 0)))), fail. check:- findall(P, punct(_, P), L), sum_list(L, S), format('Punctaj total: ~f~n',[S]).