/*Ebben a file-ban néhány mintapéldát lát. Tanulmányozásukhoz fogadja meg a következő
jó tanácsokat:*/

/*JÓTANÁCSOK:

1. Az alább leírtak csak segíthetik az önálló tanulást, de nem elegendőek a tudáshoz,
főleg pedig nem pótolhatják az önálló feladatmegoldást.
Valószínűleg az itt leírtak alapos áttanulmányozásához sem elég pár óra, de lehet, hogy egyetlen éjsza sem, az önálló feladatmegoldáshoz viszont még több idő kell. Ne sajnálja rá az időt, ha eredményes akar lenni.

2. Kövesse a leírt utasításokat is, vagyis darabonként is próbáljon ki egy-egy eljárást. Ezt a módszert egyébként is célszerű megszokni, vagyis amikor önállóan old meg feladatokat, akkor is próbálja ki részleteiben is az egyes eljárásokat.

3. Ha elakad, vagy csak nem igazán érti, hogy mit is csinál egy jól működő eljárás, kapcsolja be a trace-t. (Lehet a grafikusat is, az látványosabb, de a sima numerikus szerintem többet segít.)

4. Olvasgassa a help-et!

5. Konkrét javaslat az alább leírtakhoz:
A szövegben szabályok és magyarázatok váltják egymást, emiatt az egy feladatmegoldáshoz tartozó szabályok között esetleg sok egyéb sor is van. Javaslom, hogy rakja külön fájlba az egy-egy megoldáshoz tartozó szabályokat, és így is próbálja meg lefuttatni. Fontos, hogy együtt is lássa az összetartozó szabályokat. Figyelem! Egy szabály több feladatmegoldáshoz is tartozhat, vagyis több önálló fájlba is átkerülhet.
*/


		/*Variációk egy témára*/


/*1. Egy cégnek különböző beszállítói vannak. Egy lista tartalmazza a beszállítók nevét a beszállítás sorrendjében, 
(vagyis úgy, hogy egy név többször is szerepelhet). 
Készítse el a beszállítók névsorát, vagyis azt a listát, amelyben minden név csak egyszer szerepel.
*/


/* Először néhány variációt mutatok az egyszeres elemeket tartalmazó lista előállítására:
	egyszeres1(L1,L2)
	egyszeres2(L1,L2)
	           ... 
	egyszeres9(L1,L2).

(paraméterezés: első az eredeti, második az eredménylista).


Próbája ki őket önállóan is! 
(vagyis a konzultáció során ilyen jellegű kérdést tegyen fel:  
	egyszeresk([a,b,a,d,b,a,c],L). 		(k=1,2,...).

Figyelje meg, miben térnek el egymástól a megoldások! 
	Mitől függ a kapott sorrend? 
	Mikor melyik előfordulást törli? 
	Hány megoldás van?

Javaslat: segit a megértésben, ha bekapcsolja a trace-t, és úgy is végignézi a megoldáskeresést 
(csak ezt a konkrét célt, egyébként túl hosszú lenne).

/Nyomkövetés: trace.
Ekkor szövegesen tudja végigkövetni (én ezt szeretem jobban).
Ha a "trace" parancs kiadása előtt bekapcsolja a grafikus debugger-t,akkor látványosabb, de talán kevésbé világítja meg a prolog "gondolatmenetét"../
*/


egyszeres1([F|T],L):-member(F,T),egyszeres1(T,L),!.
egyszeres1([F|T],[F|L]):-egyszeres1(T,L).
egyszeres1([],[]).

	/*Itt azt vizsgáljuk, hogy az aktuális fej szerepel-e a lista további
 	részében. Ha igen, akkor egyszerűen elhagyjuk, ha nem,
	akkor szerepel majd az eredménylistában is.
	Részletezve: 
	1. szabály: vizsgálja meg, hogy F eleme-e a T törzsnek, és folytassa
	az eljárást a T törzzsel. Ha F szerepel a T-ben, akkor ne kerüljön be
	az eredménylistába.
	2. szabály: erre akkor kerül sor, ha az első sikertelen, vagyis ekkor
	kerüljön be az F az eredménylistába.
	3. ez a leállító szabály.
	
	Megjegyzés: a member beépített predikátum. Természetesen használhatja
	a saját maga által írt "eleme" eljárást is.
 
	Próbálja ki cut-tal és cut nélkül is! Mikor hány megoldás van? Miért?
	*/



egyszeres2([F|T],[F|L]):-egyszeres2(T,L),not(member(F,L)),!.
egyszeres2([_|T],L):-egyszeres2(T,L).
egyszeres2([],[]).

	/*Ha az eredeti lista törzsének elemeit már csak egyszeren
	tartalmazza az L lista, és a fej nincs benne ebben az L listában,
	akkor a fej bekerülhet az eredménylistába, egyébként nem.
	(Vegye észre, hogy ez a variáció ugyanabban különbözik az 
	előzőtől, mintha egy "if-then-else" elágazás megfogalmazásakor
	feltételként egy állítást vagy negáltját írnánk, és ettől függően 
	az eredménylistát vagy az "if" vagy az "else" ágon hoznánk létre.)
 
	Próbálja ki cut-tal és cut nélkül is! Mikor hány megoldás van? Miért?
	*/



egyszeres3(Eredeti, Eredm):-egyszeres3(Eredeti,[],Eredm).
egyszeres3([F|T],L,E):-\+member(F,T),egyszeres3(T,[F|L],E).
egyszeres3([_|T],L,E):-egyszeres3(T,L,E).
egyszeres3([],L,L).

		% A \+ a tagadás hivatalos jele, de lehet not(...)-t is írni.

	/*Az előzőekben "hátulról" töltöttük fel a listát, vagyis a rekurzió során
	akkor, amikor kifelé jöttünk a veremből. Lehet "befelé menet" is. Ehhez
	szükség van egy ideiglenes paraméterre. Ez induláskor üres, és ebbe
	rakjuk azokat az elemeket, amelyek nem fordulnak elő a törzsben.
	Ha szerepel benne az aktuális elem, akkor az ideiglenes listába nem
 	rakunk új elemet, hanem csak folytatjuk az eljárást az eredeti lista 
	törzsével.
	A harmadik paraméterre azért van szükség, mert valahol az eredményt
	is tárolnunk kell. Leálláskor az aktuális lista épp a keresett eredményt
	tartalmazza. Ezt úgy fejezhetjük ki, hogy az utolsó szabályban ugyanazt
	a változónevet adjuk az aktuális- és az eredménylistának.

	A legelső szabályra azért van szükség, hogy a felhasználónak ne kelljen
	foglalkoznia az eljárás "belügyeivel", vagyis az ideiglenes paraméterrel.
	Gondolja végig, miért lehet más paraméter-neveket használni az egyes 
	szabályokban! (*)
	
	Hány megoldás van? Gondolja végig, hova kellene cut-ot rakni, hogy 
	csak egy megoldást kapjunk. (több lehetséges variáció is van)

	Ha végiggondolta a cut-okat, akkor ismét állítsa vissza a cut nélküli 
	változatot, és próbálja ki a */

		proba :- egyszeres3([a,b,a,d,b,a,c],L),write(L).

	/*szabályt! (Bármelyik cut nélküli egyszeressel kipróbálhatja.)
	Mit tapasztal? Miért? (**)


	Ha nehezen megy a gondolkodás:

	(*) A paraméter-nevek hatásköre mindig csak az aktuális szabály!
	(mint más nyelvekben a lokális változó).
	Emiatt a különböző, de azonos fejű szabályokban sem a
 	paraméter-nevek számítanak, hanem a paraméterek sorrendjében
	elfoglalt helyük! (A hívás talán még egyértelműbb mindenki számára.)

	(**) A proba eljárás hivásában nincs paraméter, ezért ez vagy csak
	igaz, vagy csak hamis lehet, paraméter-értékektől függetlenül.
	Vagyis nem lehet  más paraméterezéssel igazzá tenni, ha egyszer
	nem volt az. Ezért nincs is értelme alternatíva-keresésnek.
	(Ha a cél tartalmaz paramétert, akkor ennek értékétől függ, hogy
	az állítás igaz vagy hamis, vagyis több olyan alternatíva is lehet, ahol
	igaz az állítás - ezért találhat több megoldást.) 

	*/



egyszeres4(Eredeti, Eredm):-egyszeres4(Eredeti,[],Eredm).
egyszeres4([F|T],L,E):-member(F,T),egyszeres4(T,L,E).
egyszeres4([F|T],L,E):-egyszeres4(T,[F|L],E).
egyszeres4([],L,L).

	/*Hasonlítsa össze az egyszeres3-mal! Azt is figyelje meg, hogy 
	hány megoldást talál az egyik, mennyit a másik! Mi lehet az eltérés oka?
	(a választ elküldheti e-mailben: achs@witch.pmmf.hu)
	Az egyszeres5, egyszeres6-ban még feltűnőbb a találatok különböző
	száma - esetleg annak kapcsán is végiggondolhatja a választ.
	*/



egyszeres5(Eredeti, Eredm):-egyszeres5(Eredeti,[],Eredm).
egyszeres5([F|T],L,E):-member(F,L),egyszeres5(T,L,E).
egyszeres5([F|T],L,E):-egyszeres5(T,[F|L],E).
egyszeres5([],L,L).

	/*Ha az eddig előállított listában már szerepel az éppen aktuális fej,
	akkor változtatás nélkül lépjen tovább, és vizsgálja a törzset,
	egyébként az aktuális fejet rakja az ideiglenes listához.
	*/



egyszeres6(Eredeti, Eredm):-egyszeres6(Eredeti,[],Eredm).
egyszeres6([F|T],L,E):-not(member(F,L)),egyszeres6(T,[F|L],E).
egyszeres6([_|T],L,E):-egyszeres6(T,L,E).
egyszeres6([],L,L).

	/*Gondolja végig, illetve mindkét esetben gondolja végig a cut helyét.
	*/



egyszeres7(Eredeti, Eredm):-egyszeres7(Eredeti,[],Eredm).
egyszeres7([F|T],L,E):-member(F,L),egyszeres7(T,L,E).
egyszeres7([F|T],L,E):-egyszeres7(T,[F|L],E).
egyszeres7([],L,K):-reverse(L,K).

	/*Hasonlítsa össze az egyszeres5-tel és olvassa el a reverse help-jét.
	*/



egyszeres8(L,K):-setof(X,member(X,L),K).


egyszeres9(L,K):-list_to_set(L,K).

	/*Nézze meg az egyes beépített predikátumok  helpjét. 
	Hasonlitsa össze a két eredményt!

	Erre a megoldásra már csak akkor kerítsen sort, ha a többin 
	átrágta magát!!!!!!!!!!!!!!!!
	(Egyébként átugorhatja :-)))

	*/


	/*****************************************************************/

/* Kerítsünk sort az eredetileg kitűzött feladat megoldására. Ehhez bármelyik
egyszeres eljárást használhatjuk. (természetesen csak az egyikkel oldom meg :-))
Legyen ez az egyszeres8:
*/

	egyszeres(L,K):-egyszeres8(L,K).



	/*	1. FELADAT MEGOLDÁSA: 	*/


start1 :- write('Kérem a beszállítókat!'), nl,
	write('Az utolsó beszállító után gépelje be a "vege" szót!'),nl,
	write('Gépeléskor minden adat után irjon pontot!'), nl,nl, 
	be(L), egyszeres(L,K), write('A beszállitók névsora: '), nl, ki(K).  

be([F|T]) :- read(F), F \== 'vege', be(T).
be([]).

ki([F|T]) :-  write(F), nl, ki(T).
ki([]).

	/*
	Megjegyzés: ha a "ki" első szabályában felcseréli a write és a ki 
	sorrendjét, akkor fordított sorrendben írja ki a lista elemeit, vagyis
	az egyszeres7 reverse eljárása kihagyható. (Feltéve persze, hogy
	csak a kiiratásnál számít a sorrend.)
	*/


	/*****************************************************************/

/* 2. Módosítsuk úgy az előző feladatot, hogy határozzuk meg a beszállítások és a beszállítók számát is!
*/


/* Órán vettük a lista hosszának kiszámítására vonatkozó
szabályokat. Most csak idemásolom őket. */

hossz1([_|T],H) :- hossz1(T,K), H is K+1.
hossz1([],0).

hossz2(L,H):-hossz2(L,H,0).
hossz2([_|T], H, Akt):- Ujakt is Akt +1, hossz2(T,H, Ujakt).
hossz2([],H,H).

	/*
	Megjegyzés: mindkét megoldás jó, a második hatékonyabb.	
	*/

/* A feladat megoldásához a beépített predikátumot használom, nézzen utána! */

	hossz(L,H) :- length(L,H).


	/*	2. FELADAT MEGOLDÁSA: 	*/


start2 :- write('Kérem a beszállítókat!'), nl,
	write('Az utolsó beszállító után gépelje be a "vege" szót!'),nl,
	write('Gépeléskor minden adat után irjon pontot!'), nl,nl, 
	be(L), egyszeres(L,K), write('A beszállitók névsora: '), nl, ki(K),
	hossz(L,H1), hossz(K,H2),
	writef( '%20L%10R%w',['A beszállítások száma: ', H1,'\n']), 
	write('A beszállítók száma: '), write(H2).

		% ha nincs kedve, nem muszáj ennyire formázott kiiratást használni,
		% elég a %w

		% viszont a write + nl helyett szebb a writeln vagy a write('\n.....)
		% (de nincs türelmem mindet kijavítani :( )


	/* 
	Megjegyzések:
	1. A meghívott szabályokat már korábban megírtuk ugyanebben a 
	fájlban.
	2. Hasonlísa össze a writef-t és a write-ot! Nézze meg a writef helpjét!
	(Érdemes elolvasni a beépített predikátumokra vonatkozó fejezetben is.) 	  
	*/


	/*****************************************************************/

/*3. Módosítsuk az előző feladatot  úgy, hogy kérjük be azt is, ki mennyi terméket szállított be, 
s határozzuk meg az összes beszállított áru mennyiségét!
(Feltételezzük, hogy azonos jellegű árukról van szó, vagyis összegezhető a mennyiség.)
*/

/* A megoldás előtt végig kell gondolni azt is, hogyan akarjuk tárolni a különböző jellegű adatokat (neveket, mennyiségeket).
Erre több variáció is adódhat, megnézünk néhányat (nem az összeset!)
*/

	/*	3. FELADAT MEGOLDÁSA: 		*/

	/*		A variáció			*/


/* Két külön listát képezünk, az egyik a beszállítók nevét, 
a másik a beszállított mennyiségeket tartalmazza a beszállítás sorrendjében. 
*/

start3a :-  write('Kérem a beszállítókat és a beszállított mennyiséget!'), nl,
	write('Az utolsó beszállító után gépelje be a "vege" szót!'),nl,
	write('Gépeléskor minden adat után irjon pontot!'), nl,nl, 
	be(Nevek, Dbok), ossz(Dbok,Db), 
	write('A beszállított áru össz-mennyisége: '), write(Db).

be([Fn|Tn],[Fd|Td]) :- write('beszállító: '), read(Fn), Fn\=='vege', 
	write('beszállított áru mennyisége: '), read(Fd), be(Tn,Td),!.
be([],[]).

ossz([F|T],H) :- ossz(T,K), H is K+F.
ossz([],0).

	/*
	Megjegyzések:

	1. Vegye észre, hogy az ossz szabály a hossz1 idemásolásával
	és kis módosításával készült. Természetesen meg lehetett volna
	oldani a hossz2 szabály módosításával is.
	(Sőt, az a gép szempontjából hatékonyabb lenne. Ezt viszont 
	rövidebb volt megírni :-))

	2. Figyelje meg a consult során kapott figyelmeztető üzenetet!
	A Nevek változó valóban csak egyszer szerepel, helyette lehetne _ -t
	írni. Nem szeretném azonban, ha egyáltalán eszébe jutna a be(_) jellegű
	eljáráshívás. Ez ugyanis azt jelenti, hogy teljesen mindegy, mit olvasok
	be, a programot nem érdekli. Ez jelen esetben igaz is, a feladat 
	szempontjából lényegtelen a beszállítók neve. (Még lesz olyan 
	módosítás, ahol az is lényeges lesz :-))

	*/



	/*	3. FELADAT MEGOLDÁSA: 		*/

	/*		B variáció			*/


/*A kérdéses adatok egy listában is tárolhatók név,mennyiség, név, mennyiség, stb. módon. 
Ekkor azonban csak a lista minden második elemét kell összegezni.
*/


start3b :-  write('Kérem a beszállítókat és a beszállított mennyiséget!'), nl,
	write('Az utolsó beszállító után gépelje be a "vege" szót!'),nl,
	write('Gépeléskor minden adat után irjon pontot!'), nl,nl, 
	be2(L), ossz2(L,Db), 
	write('A beszállított áru össz-mennyisége: '), write(Db).

be2([N,D|T]) :- write('beszállító: '), read(N), N\=='vege', 
	write('beszállított áru mennyisége: '), read(D), be2(T),!.
be2([]).
	/*
        Azért kell be2-nek nevezni, mert korábban már definiáltunk egy
	egy-paraméteres be predikátumot.
	Ugyanez az oka az ossz2 elnevezésnek is.
	*/

ossz2([_,F|T],H) :- ossz2(T,K), H is K+F.
ossz2([],0).

	/*
        Megjegyzés: Ha egy ilyen listából kellene kigyűjteni a beszállítók
 	névsorát, ott is minden második elemet kellene csak figyelembe-
	venni:
		kigyujt([F,_|T1],[F|T2]) :- kigyujt(T1,T2).
		kigyujt([],[]).

	Gondolja végig: ez a névsor az összes beszállítás beszállítóját
	tartalmazza, vagyis egy nevet esetleg többször is, vagy mindenkit
	csak egyszer?
	*/



	/*	3. FELADAT MEGOLDÁSA: 		*/

	/*		C variáció			*/


/*A kérdéses adatok úgy is tárolhatók egy listában, hogy jelezzük a nevek 
és mennyiségek összetartozását: (név,mennyiség), (név, mennyiség), stb. módon. 
*/

start3c :-  write('Kérem a beszállítókat és a beszállított mennyiséget!'), nl,
	write('Az utolsó beszállító után gépelje be a "vege" szót!'),nl,
	write('Gépeléskor minden adat után irjon pontot!'), nl,nl, 
	be3(L), ossz3(L,Db), 
	write('A beszállított áru össz-mennyisége: '), write(Db).

be3([(N,D)|T]) :- write('beszállító: '), read(N), N\=='vege', 
	write('beszállított áru mennyisége: '), read(D), be3(T),!.
be3([]).

ossz3([(_,F)|T],H) :- ossz3(T,K), H is K+F.
ossz3([],0).

	/*Megjegyzés: Úgy tűnik, csak formális különbség van a b és c 
	változat között, a kapott listák azonban nyilván eltérnek egymástól.
	Ezt legegyszerűbben úgy ellenőrízheti, hogy összehasonlítja a két 
	lista hosszát. (a be3-mal kapott listának fele annyi eleme van, mint
	a be2-vel beolvasott listának).
	*/
	

	/*****************************************************************/



/*4. Módosítsuk az előző feladatot  úgy, hogy állapítsuk meg, melyik beszállító összesen mennyit szállított.
*/


/* A megoldás előtt végig kell gondolni azt is, hogyan akarjuk tárolni a különböző jellegű adatokat. 
Mint láttuk, erre több variáció is adódhat. Ennek megfelelően több megoldási lehetőség is adódik. 
(Ráadásul minél bonyolultabb egy feladat, annál több (jó) megoldási lehetőség kínálkozik.) 

Egy lehetséges megoldás:
*/

	/*	4. FELADAT MEGOLDÁSA: 	*/



/*Ha csak egy beszállító lenne, akkor viszonylag egyszerű lenne a feladat, hiszen
azt kell csak tudni, hogy mikor mennyit szállított, és ezeket az értékeket összegezni. 
Akkor sem sokkal bonyolultabb a helyzet, ha több beszállító van,
de csak egynek a teljesítményére vagyunk kíváncsiak.
Ekkor a "beszallito" eljárás alkalmazható:
*/

beszallito(N,L,S) :- beszallito(N,L,0,S),!.
beszallito(N,[(N,D)|T],S,Ns) :-Ujs is S +D, beszallito(N,T,Ujs,Ns).
beszallito(N,[_|T],S,Ns)  :- beszallito(N,T,S,Ns).
beszallito(_,[],Ns,Ns).

	/*paraméterezés (a négy paraméter esetén):
	beszállító neve, a beszállítások listája, aktuális összeg, végösszeg

	Ha a beszállító neve az aktuális listafej, (pontosabban jelenleg az 
	aktuális listafej első eleme, de megoldható zárójelezés nélkül is - 
	[N,D|T], stb.) akkor növelje az aktuális S értéket a most beszállított
	D-vel, s az új aktuális összeggel keresse tovább a lista törzsében
	az N nevű beszállítót.
	Ha nem a keresett beszállító az aktuális listafej, akkor változtatás
	nélkül lépjen tovább, de ne felejtse el, hogy továbbra is az N-et 
	keresi, és továbbra is S az aktuális összeg.
	Ha végigért a listán (üres a lista), akkor mindegy, hogy kit keres,
	de az aktuális összeg pont a végösszeg lesz.
	*/

/* Ha egy beszállító össz-teljesítményét meg tudjuk határozni, akkor már nyert 
ügyünk van, hiszen ha ismerjük a beszállítók névsorát (mindenki egyszer szerepel), 
akkor meg tudjuk határozni minden egyes szereplőjének a teljesítményét is:
*/

beszallitas([N|Tn], L, [S|Ts]):-beszallito(N,L,S),beszallitas(Tn,L,Ts),!. 
beszallitas([],_,[]).

	/*paraméterezés:
	beszállítok névsora, a beszállítások listája, összeglista 
	(ez utóbbi a beszállítókhoz tartozó összegeket tartalmazza ugyanolyan sorrendben)

	Ha N a névsor aktuális feje, akkor alkalmazzuk rá a "beszallito"
	eljárást (természetesen az adott L beszállítási listával), s folytatjuk
	a "beszallitas"-t a lista törzsére. Az N-hez tartozó S érték az eredményül
	kapott összeg-lista feje lesz.


	Megjegyzés: Elegánsabb lenne, ha nem önálló összeglistát gyártanánk,
	hanem olyat, amelyben a név és összeg együtt szerepel:

	beszallitas([N|Tn], L, [(N,S)|Ts]):-beszallito(N,L,S),beszallitas(Tn,L,Ts),!.
	beszallitas([],_,[]).

	Gondolja végig a cut szerepét!
	*/

/* Ezek után összerakhatjuk a teljes megoldást. 
Ehhez a beolvasott listából először ki kellene gyűjteni a beszállítók névsorát. 
Azt viszont olyan esetre oldottuk meg, amikor az eredeti lista csak a beszállítók nevét tartalmazta, 
a mennyiséget nem.

Választás előtt állunk: 
- vagy átírjuk valamelyik "egyszeres"-t, 
- vagy át kell írnunk a "beszallito"-t,
- vagy a beolvasáskor két fajta listát hozunk létre: egy csak neveket tartalmazót,
illetve egy neveket és mennyiségeket tartalmazót. (Ez nagyon erőltetett megoldás, tűzoltó munka.)

Ez a dilemma azt mutatja, hogy

a/ a programírás elkezdése előtt végig kell gondolnunk a feladatot

b/ de ha ezt mégis elmulasztottuk valamilyen oknál fogva (:-(( ), akkor még utólag 
is van javítási lehetőségünk.

Válasszuk most valamelyik "egyszeres" átírását! (Pl. "egyszeres1"-t.): 
*/


egyszeres10([(F,_)|T],L):-member((F,_),T),egyszeres10(T,L),!.
egyszeres10([(F,_)|T],[F|L]):-egyszeres10(T,L).
egyszeres10([],[]).

	/*Megjegyzés: Természetesen olyan listára is átalakítható ez az
	eljárás, amelyben nem zárójelezzük a párokat. Ekkor az első két 
	szabály:
	egyszeres10([F,_|T],L):-member(F,T),egyszeres10(T,L),!.
	egyszeres10([F,_)|T],[F|L]):-egyszeres10(T,L).
	
	Erre az esetre sem alkalmazható az eredeti "egyszeres", hiszen
	kigyűjtené a számértékeket is. 
	*/


start4 :-  writeln('Kérem a beszállítókat és a beszállított mennyiséget!'),
	writeln('Az utolsó beszállító után gépelje be a "vege" szót!'),
	writeln('Gépeléskor minden adat után irjon pontot!\n'),
	be3(L), egyszeres10(L,Nevek),beszallitas(Nevek,L,Mennyi),
	write('\nBeszállító 	mennyiség\n'), ki(Nevek,Mennyi).
	
ki([N|Tn],[M|Tm]) :-writef('%15c%10c',[N,M]), nl, ki(Tn,Tm).
ki([],[]).

	/*Megjegyzés: ha azt a megoldást választjuk, hogy az S lista ne csak az 
	összegeket, hanem a neveket és a hozzájuk tartozó összegeket együtt
	tartalmazza, akkor csak S-t kell kiiratni, de egy kulon "ki2" eljárást
 	kellene írni:
		ki2([(N,M)|T])  :-writef('%15c%10c',[N,M]), nl, ki2(T).
		ki2([]).
	(vagy értelemszerűen [N,M|T])
	*/


/*Megjegyzések:

1. A megoldás szépséghibája: nem névsorban írja ki a beszállítókat (ahogy az 
"egyszeres8" teszi). Javítási lehetőség: beiktatunk egy névsorba-rendezést, vagy
mégsem igy oldjuk meg, hanem két listával.

2. A két listás "beszallito":

beszallito(N,Nevek,Mennyisegek,S) :- beszallito(N,Nevek,Mennyisegek,0,S),!.
beszallito(N,[N|Tn],[D|Td],S,Ns) :-Ujs is S +D, beszallito(N,Tn,Td,Ujs,Ns).
beszallito(N,[_|Tn],[_|Td],S,Ns)  :- beszallito(N,Tn,Td,S,Ns).
beszallito(_,[],[],Ns,Ns).

*/


	/*****************************************************************/

/*5. Módosítsuk az előző feladatot  úgy, hogy állapítsuk meg, melyik beszállító szállította a legtöbbet.
*/

/* A megoldás előtt végig kell gondolni azt is, hogyan akarjuk tárolni a különböző jellegű adatokat. 
Mint láttuk, erre több variáció is adódhat. Ennek megfelelően több megoldási lehetőség is adódik. 
(Ráadásul minél bonyolultabb egy feladat, annál több (jó) megoldási lehetőség kínálkozik.) 
Most azonban fel szeretnénk használni az előző feladat megoldását, vagyis azt, 
hogy annak két lista az eredménye, egy névsor és a hozzá tartozó számok. 
így két listával folytatjuk a feladat megoldását. Egy lehetséges megoldás:
*/


/*Először nézzük át, hogyan határozhatjuk meg egy lista legnagyobb elemét! 
Önállóan is próbálja ki az egyes változatokat, pl. max1([2,7,1,8,3],M) módon
*/


max1([F|T],F) :- max1(T,M), F > M.
max1([F|T],M) :- max1(T,M), F =< M.
max1([E],E).

	/*Ha a törzs első eleme (F) nagyobb a törzs legnagyobb eleménél
 	(M-nél), akkor a lista legnagyobb eleme is F.
	Ha a fej kisebb a törzs maximumánál, akkor pedig a törzs
	maximuma(M) a teljes listának is maximuma.
	Leállítási feltételként jelenleg az is megadható, hogy az üres lista
 	maximuma pl. 0, hiszen most a lista minden eleme pozitív, 
	általában azonban ez a jó megoldás, vagyis az, 
	hogy az egy elemű lista maximuma maga az elem.

	Gondolja végig, szükség van-e az F =< M feltételre? Mi történik, ha 
	kitörli? 
	Hány megoldás van? Ez mitől függ?
	*/



max2(L,Max) :- max(L,0,Max).
max([F|T],M,Max) :- F > M, UjM is F, max(T, UjM, Max),!.
max([_|T],M,Max) :- max(T, M, Max).
max([],Max,Max).

	/*Úgy is gondolkodhatunk, hogy ha M az eddig vizsgált elemek 
	maximuma, és F az aktuális fej, akkor ezt a két elemet kell
	összehasonlítani. 
	Ha F a nagyobb, akkor F lesz az új aktuális maximum, egyébként marad az M.
	Az első szabály 0-nak veszi az induló maximumot, de az előbb már
 	megbeszéltük, hogy ez nem mindig jó, jobb lenne az első elemről
 	indulni. Ez is megoldható:

		max2([F|T],Max):- max(T,F,Max).
	
	Mi a cut szerepe?

	Megjegyzés: ez a variáció sokkal hatékonyabb az előzőnél.
	*/


/* Próbálja ki max1, max2-t egy szimbólum-listára, pl.: max1([aa,ts,bb,cc],M).
Mit tapasztal?
Nézze meg a helpben a > reláció leírását!	

Keresse meg a beépített predikátumok (built in predicates) között a term-ek összehasonlítására (comparison) vonatkozó relációkat!
(Ha nagyon nem találja, vagy nagyon nem érti, akkor nézze meg a @> reláció helpjét.)
*/


max3([F|T],F) :- max3(T,M), F@> M,!.
max3([_|T],M) :- max3(T,M).
max3([E],E).

/*  Ezt is próbálja ki, pl: max3([aa,ts,bb,cc],M). */



	/*	5. FELADAT MEGOLDÁSA: 		*/

	/*		A variáció		*/


/*Feltételezzük, hogy mindenki különböző mennyiséget szállít, vagyis csak egy maximum van.
*/

start5a :-  writeln('Kérem a beszállítókat és a beszállított mennyiséget!'),
	writeln('Az utolsó beszállító után gépelje be a "vege" szót!')
	write('\nGépeléskor minden adat után irjon pontot!\n'), 
	be3(L), egyszeres10(L,Nevek),beszallitas(Nevek,L,Mennyi),
	write('\nBeszállító	mennyiség\n'),nl, ki(Nevek,Mennyi),nl,
	max(Nevek,Mennyi,Maxnev,Maxdb),
	write('A legjobb beszállító: '),writeln(Maxnev),
	write('Az általa szállított mennyiség: '),writef('%10c%w',[Maxdb,'darab']).

max([Fn|Tn],[Fs|Ts],Fn,Fs) :- max(Tn,Ts,_,M), Fs @> M,!.
max([_|Tn],[_|Ts],N,M) :- max(Tn,Ts,N,M).
max([N],[M],N,M).

	/* Ha megértette az egy listára vonatkozó maximumkeresést, akkor ez
 	már egyszerű: Ugyanarról van szó, csak duplázzuk a paraméterek számát.
	(Természetesen a max2-t is át lehetett volna írni. Sőt, szerencsésebb lett volna
	azt átírni, mert az jóval hatékonyabb, mint a max.)
	*/



	/*	5. FELADAT MEGOLDÁSA: 		*/

	/*		B variáció			*/


/*Ha megengedett a holtverseny, akkor nem elég (és nem korrekt) egyetlen beszállítót kiiratni. 
Ekkor a következőt tehetjük:
Határozzuk meg a mennyiségek maximumát (sima egy-listás maximumkeresés, én a max3-ra fogok hivatkozni, 
de bármelyik másik is jó lenne), majd gyűjtsük ki az összes olyan beszállítót, aki épp ennyit szállított.
*/

kigyujt(M,[N|Tn],[M|Tm],[N|T]):-kigyujt(M,Tn,Tm,T),!.
kigyujt(M,[_|Tn],[_|Tm],T):-kigyujt(M,Tn,Tm,T).
kigyujt(_,[],[],[]).

	/*Paraméterezés:
	keresett mennyiség, névsor, mennyiségek listája, kigyűjtött nevek listája

	Ha T a névsor-lista törzséből (Tn) kiválogatott neveket tartalmazza,
	és a keresett M mennyiség a mennyiségek listájának éppen aktuális 
	eleme (feje), akkor kerüljön a hozzá tartozó név is a kiválogatott nevek
	közé, vagyis a T listához, azaz a megfelelő lista fejébe.
	Egyébként pedig módosítás nélkül folytatódjon a kigyűjtés.
	Leállitás: üres listából nyilván nem tudunk kigyűjteni semmit.

	Próbálja ki önállóan is, pl. kigyujt(4,[aa,bb,cc,dd],[1,4,3,4],L). módon!
	Próbálja ki cut nélkül is. Hány megoldást kap?
	Ha nem értette meg teljesen a magyarázatot, akkor nyomkövetéssel
	is nézze végig. 
	*/

/*
Ezek után az inditás: 
*/

start5b :-  writeln('Kérem a beszállítókat és a beszállított mennyiséget!'),
	writeln('Az utolsó beszállító után gépelje be a "vege" szót!'),
	writeln('Gépeléskor minden adat után irjon pontot!\n'),  
	be3(L), egyszeres10(L,Nevek),beszallitas(Nevek,L,Mennyi),
	write('\nBeszállító	mennyiség\n'), ki(Nevek,Mennyi),
	max3(Mennyi,Maxdb), kigyujt(Maxdb,Nevek,Mennyi,Maxnevek),
	writeln('\nA legjobb beszállítók: '), ki(Maxnevek), 
	write('\nAz általuk szállított mennyiség: '), 
	writef('%10c%w',[Maxdb,'darab']).

		% ha nincs kedve, nem muszáj ennyire formázott kiiratást használni,
		% elég a %w

	/*****************************************************************/

/*6. Módosítsuk az előző feladatot  úgy, hogy gyűjtsük külön a "jó" és "rossz" beszállítókat, 
vagyis az adott mennyiségnél többet, illetve kevesebbet szállítók névsorát, és a hozzájuk tartozó mennyiségeket.
*/

/* A megoldás előtt végig kell gondolni azt is, hogyan akarjuk tárolni a különböző jellegű adatokat. 
Mint láttuk, erre több variáció is adódhat. Ennek megfelelően több megoldási lehetőség is adódik. 
(Ráadásul minél bonyolultabb egy feladat, annál több (jó) megoldási lehetőség kínálkozik.) 
Most azonban fel szeretnénk használni az előző (4.) feladat megoldását, vagyis azt, 
hogy annak két lista az eredménye, egy névsor és a hozzá tartozó számok. így két listával folytatjuk a feladat megoldását. Egy lehetséges megoldás:
*/


/*Először most is az "alapsémát" beszéljük meg, vagyis azt, hogyan lehet valamilyen szempont alapján szétválogatni egy lista elemeit.
Ez a gondolkodásmód nagyon hasonlít az 5/b megoldásban tárgyalt "kigyujt" 
eljáráshoz.
A válogatás:
*/

valogat([F|T],[F|T1],T2):-feltetel(F),valogat(T,T1,T2).
valogat([F|T],T1,[F|T2]):-valogat(T,T1,T2).
valogat([],[],[]).

	/*paraméterezés:
	szétválogatandó lista; a feltételnek eleget tevő elemek listája;
	a nem megfelelő elemek listája.
	Természetesen a paraméterek sorrendje (mint minden más esetben)
	szubjektív - most e mellett a sorrend mellett döntöttünk (döntöttem :-))

	Ha tudjuk azt, hogy a lista T törzsét T1 és T2 listákra bontottuk, akkor
	az éppen aktuális fej a feltétel teljesülésétől függően vagy T1 vagy T2
	elé kerül. (Vagyis a megfelelő "kupacba".)
	Leállításkor az üres listát nyilván csak üresekre tudjuk bontani.

	Próbalja ki önállóan is! (Esetleg nyomkövetéssel.) Ehhez persze kellene 
	egy feltétel is. Legyen ez pl.:
	*/
		feltetel(F):-F>0.

	/*Elvileg lehet, gyakorlatilag azonban nem indokolt ilyen egyszerű 
	feltételre külön szabályt irni, most azonban így tudjuk könnyen ellenőrizni. 
	Pl.: valogat([2,-4,6,3,-2],L1,L2).

	Hány megoldás van? Hogyan lehet segíteni rajta?
	*/

/*Az előző szabály-megfogalmazás inkább deklaratív szemléletű, de "procedurális fejjel" is végiggondolható: 
a rekurzív hívások sorozatával előbb eljutunk a lista végéig, majd a verem aljáról visszafelé jövet 
az éppen aktuális fej a megfelelő lista elé kerül. 

A válogatás más gondolkodásmód alapján is megoldható: a vizsgált elemet (fejet) azonnal berakjuk egy megfelelő listába. 
Ez (ezek, hiszen két részre bontjuk az eredeti listát) az eddig vizsgált elemeket tartalmazzák. 
Addig végezzük a szortírozást, amig a lista végére nem érünk. 
Ez a gondolkodásmód az aktuális részlistákra is igényt tart, ezért azokat is fel kell venni a paraméterlistára. 
Nyilván szükségünk van a végeredményt tartalmazó listákra is, vagyis ezek továbbra is a paraméterlistán maradnak. 
A végeredmény-listák akkor kapják meg a tartalmukat, amikor az eredeti lista kiürült. 
Ekkor tartalmuk megegyezik az éppen aktuális listák tartalmával.


A szabály felhasználójának nem kell tudnia arról, hogy a válogatáshoz ideiglenes listákat is használtunk, 
ezért ezeket célszerű "elrejteni". Erre szolgál a "valogat1" szabály. Ez indítja el a válogatást. 
Indításkor az aktuális listák nyilván üresek.

Az ilyen ötleten alapuló megoldás:
*/

valogat1(L,L1,L2):-valogat(L,[],[],L1,L2),!.
valogat([F|T],L1akt,L2akt,L1veg,L2veg) :- feltetel(F), 
		valogat(T,[F|L1akt],L2akt,L1veg,L2veg).
valogat([F|T],L1akt,L2akt,L1veg,L2veg) :- valogat(T,L1akt,[F|L2akt],L1veg,L2veg).
valogat([],L1veg,L2veg,L1veg,L2veg).


/* Próbálja ki ezt a változatot is. Lehet ugyanaz a kérdése, mint az előbb:
 valogat1([2,-4,6,3,-2],L1,L2).
*/

	
/*Jelenleg két lista alapján akarunk válogatni, vagyis a válogatás így módosul: 
(az első változat alapján oldom meg, így is elég sok paraméter lesz)
*/


	/*	6. FELADAT MEGOLDÁSA: 		*/


valogat(K,[Fn|Tn],[Fm|Tm],[Fn|Tn1],[Fm|Tm1],Tn2,Tm2):-Fm>K,
	valogat(K,Tn,Tm,Tn1,Tm1,Tn2,Tm2).
valogat(K,[Fn|Tn],[Fm|Tm],Tn1,Tm1,[Fn|Tn2],[Fm|Tm2]):-Fm=<K,
	valogat(K,Tn,Tm,Tn1,Tm1,Tn2,Tm2).
valogat(_,[],[],[],[],[],[]).

	/*Paraméterezés:
	1. A megadott korlát - ehhez hasonlítjuk a beszállított mennyiségeket.
	2. A beszállítók névsora.
	3. Az általuk szállított mennyiségek listája.
	4. A "jók" (K-nál többet szállítók) névsora.
	5. A "jók" által szállított mennyiségek.
	6. A "rosszak" (K-nál kevesebbet szállítók) névsora.
	7. A "rosszak által szállított mennyiségek.

	Ha a sima válogatást értette, akkor ez sem több, csak hosszabb.
	Megjegyzés: Az Fm=<K feltétel elhagyható, az eredeti sémában nem
	is szerepelt. Ha nem írjuk be, akkor önálló hivás esetén több megoldás
	is adódhat. Ezen az első szabály végére írt cut-tal is segíthetünk. 
	Ha nem önállóan hivjuk, vagyis egy szabálytörzsön belül, ahogy jelenlegi
	példánkban is, akkor meg is áll az első megoldásnál. 
	(Feltéve, hogy jól irtuk meg a hivó szabályt :-))
	*/

start6 :-  write('Kérem a beszállítókat és a beszállított mennyiséget!'), nl,
	write('Az utolsó beszállító után gépelje be a "vege" szót!'),nl,
	write('Gépeléskor minden adat után irjon pontot!'), nl,nl, 
	be3(L), egyszeres10(L,Nevek),beszallitas(Nevek,L,Mennyi),nl,
	write('Mi a szállítási küszöb? '), read(Korlat),nl,
	valogat(Korlat,Nevek,Mennyi,Jonevek,Jmennyi,Rossznevek,Rmennyi),
	write('Jó beszállítók: '),nl,
	write('Beszállító	mennyiség'),nl, ki(Jonevek,Jmennyi),nl,
	write('Rossz beszállítók: '),nl,
	write('Beszállító	mennyiség'),nl, ki(Rossznevek,Rmennyi).


/*Megjegyzés:
A válogatás természetesen más adatszerkezetre is átírható. 
Néhány példa (mindenhol csak a válogatás első sorát adom meg, a többi értelemszerű):

bemenő adat: [név,mennyiség,név, mennyiség, stb..]
eredmény: [név,mennyiség,név,mennyiség, stb..] szerkezetű listák.

valogat(K,[Fn,Fm|T],[Fn,Fm|T1],T2):-Fm>K,valogat(K,T,T1,T2).


bemenő adat: [(név,mennyiség),(név, mennyiség), stb..]
eredmény: [(név,mennyiség),(név,mennyiség), stb..] szerkezetű listák.

valogat(K,[(Fn,Fm)|T],[(Fn,Fm)|T1],T2):-Fm>K,valogat(K,T,T1,T2).


bemenő adat: [név,mennyiség,név, mennyiség, stb..]
eredmény: [név,név, stb..], [mennyiség,mennyiség, stb...] szerkezetű listák.

valogat(K,[Fn,Fm|T],[Fn|Tn1],[Fm|Tm1],Tn2,Tm2):-Fm>K,
		valogat(K,T,Tn1,Tm1,Tn2,Tm2).

*/


/*
Átrágta magát?
Értette? Kipróbálta?
Önállóan is meg tudna írni hasonló feladatokat?
Próbálja ki ezt is: A gyakorló feladatok között, ill. a html jegyzetben sok megoldandó feladatot talál.
Jó szórakozást!
 
*/ 