noDuplicates(Lst) :-
    setof(X, member(X, Lst), Set),
    length(Lst, N),
    length(Set, N).

distTo(hamburg, bremen,80).
distTo(hamburg, berlin, 230).
distTo(bremen, dortmund, 200).
distTo(hannover, nuernberg, 380).
distTo(dortmund, koeln, 80).
distTo(kassel, frankfurt, 180).
distTo(nuernberg, muenchen, 160).
distTo(hamburg, hannover,110).
distTo(bremen, hannover,100).
distTo(hannover, kassel,140).
distTo(dortmund, kassel,130).
distTo(kassel, wuerzburg,180).
distTo(frankfurt, wuerzburg,110).

dist(From,To,Km) :-
    distTo(From,To,Km).
dist(From,To,Km) :-
    distTo(To,From,Km).

%%%%%%%%%%% CASO RUTA INSTANCIADA %%%%%%%%%%%

route(From, To, []) :-
    dist(From, To, _).

route(From, To, Route) :-
    nonvar(Route),
    % noDuplicates(Route), %Suponemos que Route no tiene duplicados
    [Head | Tail] = Route,
    dist(From, Head, _),
    route(Head, To, Tail),
    From \= To.

%%%%%%%%%%% CASO RUTA NO INSTANCIADA %%%%%%%%%%

route(From, To, Route) :-
    var(Route),
    length(Route, _), %Debe ser una lista
    route__(From, To, Route).

route__(To, To, []).
route__(From, To, [X|Route]) :-
    dist(From, X, _),
    route__(X, To, Route),
    \+ member(X, Route),
    \+ member(From, [X|Route]).

%%%%%%%%%%%%%%%% SHORTEST PATH %%%%%%%%%%%%%%%%
route(From, To, [], Km) :-
    dist(From, To, Km).

route(From, To, Route, Km) :-
    nonvar(Route),
    % noDuplicates(Route), %Suponemos que Route no tiene duplicados
    [Head | Tail] = Route,
    dist(From, Head, Dist),
    route(Head, To, Tail, DistRest),
    From \= To,
    Km is Dist+DistRest.

route(From, To, Route, Km) :-
    var(Route),
    length(Route, _), %Debe ser una lista
    route__(From, To, Route, Km).

route__(From, To, [To], Km) :-
    dist(From, To, Km).

route__(From, To, [X|Route], Km) :-
    dist(From, X, Dist),
    route__(X, To, Route, DistRest),
    \+ member(X, Route),
    \+ member(From, [X|Route]),
    Km is Dist+DistRest.

listMinimum([L|Ls], Min) :-
    listMinimum__(Ls, L, Min).

listMinimum__([], Min, Min).
listMinimum__([L|Ls], Min0, Min) :-
    Min1 is min(L, Min0),
    listMinimum__(Ls, Min1, Min).

shortestPath(From, To, Route, MinDist) :-
    findall(Km, route(From, To, Route, Km), ListDistances),
    listMinimum(ListDistances, MinDist).
