/****************************************************************************************** *
Sujet 1 : Métro de Saint-petersbourg

Bonnard Mickael			Desmottes François
Desmottes François		Plossard Séverin

*******************************************************************************************/


% Description des lignes
ligne(1,['Primorskaya','Vasileostrovskaya','Gostiny Dvor','Ploschad Vosstania/Moscow Train Station','Ploschad Alexandra Nevskovo','Elizarovskaya','Lomonosovskaya','Proletarskaya','Obukhovo','Rybatskoe']).
ligne(2,['Chkalovskaya','Sportivnaya','Sadovaya','Dostoevskaya','Ligovskiy Prospect','Ploschad Alexandra Nevskovo','Novocherkasskaya','Ladozhskaya','Prospect Bolshevikov','Ulitsa Dybenko']).
ligne(3,['Prospect Prosvescheniya','Ozerki','Udelnaya','Pionerskaya','Chyornaya Rechka','Petrogradskaya','Gorkovskaya','Nevskiy Prospect','Sennaya Ploschad','Tekhnologichesky Institut','Frunzenskaya','Moskovskiye Vorota','Elektrosila','Park Pobedy','Moskovskaya (Bus to airport)','Zvezdnaya','Kupchino']).
ligne(4,['Devyatkino','Grazhdanskiy Prospect','Akademicheskaya','Politekhnicheskaya','Ploschad Muzhestva','Lesnaya','Vyborgskaya','Ploschad Lenina/Finland Train Station','Chernyshevskaya','Mayakovskaya','Vladimirskaya','Pushkinskaya/Vitebsk Train Station','Tekhnologichesky Institut','Baltiyskaya/Baltic/Warsaw Train Stations','Narvskaya','Kirovsky Zavod','Avtovo','Leninsky Prospect','Prospect Veteranov']).


% Description des jonctions inter-lignes dans un sens
jonction('Nevskiy Prospect', 'Gostiny Dvor', 1, 3). 
jonction('Ploschad Vosstania/Moscow Train Station', 'Mayakovskaya', 1, 4). 
jonction('Ploschad Alexandra Nevskovo', 'Ploschad Alexandra Nevskovo', 1, 2).
jonction('Sadovaya', 'Sennaya Ploschad', 2, 3). 
jonction('Dostoevskaya', 'Vladimirskaya', 2, 4).
jonction('Tekhnologichesky Institut', 'Tekhnologichesky Institut', 3, 4).
% Description des jonctions inter-lignes dans l'autre sens
jonction('Gostiny Dvor','Nevskiy Prospect',3,1). 
jonction('Mayakovskaya','Ploschad Vosstania/Moscow Train Station', 4, 1). 
jonction('Ploschad Alexandra Nevskovo', 'Ploschad Alexandra Nevskovo', 2, 1).
jonction('Sennaya Ploschad','Sadovaya', 3,  2). 
jonction('Vladimirskaya','Dostoevskaya', 4, 2).
jonction('Tekhnologichesky Institut','Tekhnologichesky Institut', 4,  3).

%-----------------------------------------------------------------------------------------------------------------
% Menu de sélection du trajet :
%-----------------------------------------------------------------------------------------------------------------
menu:-
	write('               Metro de Saint-Petersbourg Version 2000'),nl,nl,
	write('Choisissez votre ligne de départ (1,2,3,4): '),
		read(Numero_ligne_depart),
		affiche_ligne(Numero_ligne_depart),
		write('Choisissez le n° de la station correspondante : '),
		read(Numero_station_depart),
		read_station(Numero_ligne_depart,Numero_station_depart,Station_depart),nl,
		write('Choisissez votre ligne d''arrivée (1,2,3,4): '),
		read(Numero_ligne_arrivee),
		affiche_ligne(Numero_ligne_arrivee),
		write('Choisissez le n° de la station correspondante : '),
		read(Numero_station_arrivee),
		read_station(Numero_ligne_arrivee,Numero_station_arrivee,Arrivee),
		chemin(Station_depart,Arrivee),nl,
	write('Voulez vous effectuer une autre recherche (o/n)? '),read(Reponse),autre_recherche(Reponse),nl.

% Fin de programme, réitérer sur une autre recherche ?	
autre_recherche(Reponse):-
	Reponse='o',nl,nl,menu.
autre_recherche(Reponse):-
	Reponse='n',
	write('Merci d''avoir utilisé le programme de repérage dans le métro'),nl.

% procédure pour préparer à l'affichage de toutes les stations de la ligne
affiche_ligne(Numero_ligne):-
	ligne(Numero_ligne,Ligne),			% On récupère la liste des stations correspondante à la ligne
	Indice=1,					% Indice pour les numéros de stations
	aff_liste(Indice,Ligne).			% Affichage de toutes les stations de la ligne actuelle

% Affichage de toutes les stations de la ligne actuelle en récursif
aff_liste(Indice,[]).	% On arrête lorsque la liste est vide
aff_liste(Indice,[Tete|Queue]):-
	write('     '),
	write(Indice),					% Affiche le numéro de station  
	write(' : '),
	write(Tete),nl,
	Nouvel_indice is Indice+1,			% incrément de l'indice
	aff_liste(Nouvel_indice,Queue).			% On dépile la tête

% Prépare à retourner le nom de la station grâce à ses numéros de ligne et de station
read_station(Numero_ligne,Numero_station,Station):-
	ligne(Numero_ligne,Ligne),			% Retourne le liste des stations de la ligne
	read_liste(Numero_station,Ligne,Station).	% Retourne le nom de la station grâce à ses numéros de ligne et de station

% Retourne le nom de la station grâce à ses numéros de ligne et de station
read_liste(Numero_station,[],Station):-			% Cut si le numéro de station choisi dépasse le nbre de stations sur la ligne
	write('Le nombre que vous avez rentré ne correspond à aucune station'),
	menu,
	!.
read_liste(1,[Tete|Queue],Tete):-			% Cut si on a retrouvé le nom de station grâce à son numéro sur la ligne et station prend la valeur de la tete
	!.
read_liste(Indice,[Tete|Queue],Station):-	
	Nouvel_indice is Indice-1,			% On décrémente l'indice jusqu'à retrouver la station sélectionnée
	read_liste(Nouvel_indice,Queue,Station).	% On dépile la tête
%-----------------------------------------------------------------------------------------------------------------
% Fin du menu de sélection du trajet
%-----------------------------------------------------------------------------------------------------------------

%-----------------------------------------------------------------------------------------------------------------
% Recherche du parcours :
%-----------------------------------------------------------------------------------------------------------------
% Chemin de la staton de départ à celle d'arrivée
chemin(Station_1, Station_2) :- 
	parcours(Station_1, Station_2, Precedent),nl, 
	affiche_resultat(Precedent).

% Parcours lorsque les 2 stations sont sur la même ligne
parcours(Station_1, Station_2, [de,Station_1,à,Station_2,sans,changer,de,ligne,direction,Direction,.,nl]) :-
	cherche_ligne(Station_1, Ligne, _),					% Cherche la ligne (numéro) sur laquelle se trouve la station_1
 	member(Station_2, Ligne),						% Regarde si la station 2 est sur la même ligne que la 1
 	cherche_dir(Station_1, Station_2, Ligne,Ligne, Direction).		% Cherche la direction pour aller de la stion 1 à la 2

% Parcours lorsqu'il faut rechercher un changement
parcours(Station_1, Station_2, [de,Station_1,direction,Direction,changer,à,Station_changer,puis,nl|Next]) :-
	cherche_ligne(Station_1, Ligne, Nouvel_ligne),				% Cherche la ligne (numéro) sur laquelle se trouve la station_1
	selecti(Station_1, Station_changer, Ligne),				% cherche une station de jonction sur la même ligne que la station courante
	jonction(Station_changer,Station_jonction,Nouvel_ligne,Nouvel_Ligne),	% Cherche une jonction entre la station trouvée précédemment et la nouvelle ligne à emprunter
	cherche_dir(Station_1, Station_changer, Ligne, Ligne, Direction),	% Cherche la direction entre les deux stations
	parcours(Station_jonction,Station_2,Next).				% relance le parcours depuis la staion de jonction vers celle d'arrivée

% Cherche la ligne (numéro) sur laquelle se trouve la station
cherche_ligne(Station, Liste_stations, Num_ligne) :-
	estdans(Num_ligne, [1, 2, 3, 4]),					% Retourne 1,2,3 ou 4, pour les numéros de ligne
	ligne(Num_ligne, Liste_stations),					% Permet de récupérer la liste des stations correspondant au numéro de ligne
	estdans(Station, Liste_stations).					% regarde si la station appartient à la ligne
 
% Le premier paramètre est-il dans la liste (second paramètre) ?
estdans(Tete, [Tete|_]).							% Oui, si en tête de liste
estdans(Tete, [_|Queue]) :- estdans(Tete, Queue).				% Sinon, on dépile la tête

% Le premier paramètre est-il membre de la liste (second paramètre) ?
member(Tete, [Tete|_]) :- !.							% Cut si oui
member(Tete, [_|Queue]) :- member(Tete, Queue).					% Sinon, on dépile la tête

% Sélection d'une station si celle-ci est différente de la station courante
selecti(Tete, Y, [Tete|Queue]) :- selecti(Tete, Y, Queue).			% On dépile si la station est égale à la station courante
selecti(X, Y, [Y|_]) :- not(X=Y).						% Sélection si la station  est différente de la station courante
selecti(X, Y, [_|Queue]) :- selecti(X, Y, Queue).				% On dépile la tête de la liste (ligne)

% Recherche de la direction pour aller d'une station à une autre
cherche_dir(_, Station_2, [Station_2|_], [Direction|_], Direction).		% Si la station 2 est en tête, la direction est la tête de liste
cherche_dir(Station_1, _, [Station_1|Queue], _, Direction) :- dernier(Queue, Direction). % Si la station_1 est en tête, la direction est le dernier élément
cherche_dir(Station_1, Station_2, [_|Queue], Ligne, Direction) :- cherche_dir(Station_1, Station_2, Queue, Ligne, Direction). % Si non cas particulier, on dépile jusqu'à atteindre soit l'une ou l'autre des 2 stations

% Renvoie le dernier élément d'une liste
dernier([X], X).								% Stoppe si dernier élément
dernier([_|Queue], Direction) :- dernier(Queue, Direction).			% Sinon, on continue à dépiler

% Affiche le résultat du parcours trouvé
affiche_resultat(Precedent) :- display_liste(['parcours :',nl|Precedent]), nl.

% Affiche la liste des indications empilées
display_liste([]).								% Stoppe si la liste est vide
display_liste([nl|Queue]) :-							% Si la tête est un saut de ligne, on saute une ligne puis on relance sur la fonction
	nl, 
	display_liste(Queue).
display_liste([Tete|Queue]) :-							% On affiche chaque élément de liste séparé par un espace
	display(Tete), 
	display(' '), 
	display_liste(Queue).							% On réitère récursivement sur la queue de la liste

%-----------------------------------------------------------------------------------------------------------------
% Fin de recherche du parcours :
%-----------------------------------------------------------------------------------------------------------------
