% Musterloesung Aufgabenblatt 6
% P1 [[WiSe]] 04/05
% Daniel Schreckling
% Aufgabe 1
% ---------
% Hilfsprädikat max(+Zahl1, +Zahl2, ?Max)
%
% Liefert in ?Max das Maximum der Zahlen +Zahl1
% und +Zahl2
max(Zahl1, Zahl2, Zahl2) :- Zahl1 < Zahl2.
max(Zahl1, Zahl2, Zahl1) :- Zahl1 >= Zahl2.
% Hilfsprädikat Ort(?Ort, ?Hoehe)
%
% Liefert die ?Hoehe zu einem Ort ?Ort
ort(Ort, Hoehe) :-
region(Ort,Hoehe).
ort(Ort, Hoehe) :-
wasserwerk(Ort, Hoehe).
ort(Ort, Hoehe) :-
pumpstation(Ort, Hoehe).
% es werden Prädikate aus früheren Übungsaufgaben verwendet
% und modifiziert
% Aufgabe 1a
% ----------
% Hilfsprädikat hoehen_unterschied(+Ort1, +Ort2, ?Unterschied)
%
% berechnet die Hoehendifferenz nach der Vorschrift:
% Hoehe von Ort1 minus Hoehe von Ort2
hoehen_unterschied(Ort1, Ort2, Unterschied) :-
ort(Ort1, Hoehe1),
ort(Ort2, Hoehe2),
Unterschied is (Hoehe1 - Hoehe2).
% hoehen_unterschied_verb(+Senke, +Quelle, ?Unterschied)
%
% Gelingt, wenn +Senke und +Quelle in Fließrichtung direkt
% miteinander verbunden sind. ?Unterschied enthält bei
% Erfolg den Hoehenunterschieds ziwschen Senke und Quelle
hoehen_unterschied_verb(Senke, Quelle, Unterschied) :-
ist_angeschlossen_an(Senke, Quelle),
hoehen_unterschied(Senke, Quelle, Unterschied).
% Aufgabe 1b
% ----------
% hoehenunterschied_ww_verbr(+Wasserwerk, +[[VerbrRegion]], ?Unterschied)
%
% Gelingt, wenn die Verbraucherregion +[[VerbrRegion]] letztlich von
% +Wasserwerk mit Wasser versorgt wird. ?Unterschied enthaelt bei Erfolg
% den Hoehenunterschied zwischen Wasserwerk und Verbraucherregion.
% Da es mehrere Wege geben kann, liefert hoehen_unterschied_ww_verbr\3
% gegebenenfalls auch mehrer Hoehenunterschiede.
hoehenunterschied_ww_verbr(Wasserwerk, [[VerbrRegion]], Unterschied) :-
wasserwerk(Wasserwerk, [[HoeheWW]]),
region([[VerbrRegion]], [[HoeheVR]]),
wird_versorgt_von([[VerbrRegion]], Wasserwerk, _),
hoehen_unterschied([[VerbrRegion]], Wasserwerk, Unterschied).
% Aufgabe 1c
% ----------
% wird_versorgt_von(?Senke, ?Quelle, ?[[MaxDiff]])
%
% Gelingt, wenn ?Senke von ?Quelle mit Trinkwasser versorgt wird.
% In ?[[MaxDiff]] wird die größte Höhendifferenz gespeichert,
% die auf irgendeinem Weg von der Senke zur Quelle überwunden wird.
% Da es mehrere Wege geben kann, liefert wird_versorgt_von\2
% gegebenenfalls auch mehrer Hoehenunterschiede.
wird_versorgt_von(Senke,Quelle, [[MaxDiff]]) :-
wasserwerk(Quelle, _),
ist_angeschlossen_an(Senke,Quelle),
hoehen_unterschied(Senke, Quelle, [[MaxDiff]]).
wird_versorgt_von(Senke,Quelle, [[MaxDiff]]) :-
ist_angeschlossen_an(Senke,Ort),
wird_versorgt_von(Ort,Quelle, [[ThisDiff]]),
hoehen_unterschied(Senke, Ort, Diff),
max(Diff, [[ThisDiff]], [[MaxDiff]]).
% max_hoehenunterschied_ww_verbr(+Wasserwerk, +[[VerbrRegion]], ?[[MaxDiff]])
%
% Gelingt, wenn die Verbraucherregion +[[VerbrRegion]] letztlich von
% +Wasserwerk mit Wasser versorgt wird. ?[[MaxDiff]] liefert bei Erfolg
% den maximalen Hoehenunterschied zwischen zwei Netzknoten auf dem Weg
% zwischen Wasserwerk und Verbraucherregion.
% Da es mehrere Wege geben kann, liefert hoehen_unterschied_ww_verbr\3
% gegebenenfalls auch mehrer Hoehenunterschiede.
max_hoehenunterschied_ww_verbr(Wasserwerk, [[VerbrRegion]], [[MaxDiff]]) :-
region([[VerbrRegion]], _),
wasserwerk(Wasserwerk, _),
wird_versorgt_von([[VerbrRegion]], Wasserwerk, [[MaxDiff]]).
% Aufgabe 2a
% ----------
% zinseszins(+Anlage,+Zinssatz,+Laufzeit,?Ausschuettung)
%
% Das Kapital +Anlage ist in Währungseinheiten anzugeben,
% der +Zinssatz in Prozent, z.b. `5' entspricht 5%,
% die +Laufzeit in Jahren.
% Die +Ausschuettung wird ebenfalls in Währungseinheiten ausgegeben
zzins(Anlage, _, 0, Anlage).
zzins(Anlage, Zinssatz, Laufzeit, Ausschuettung) :-
Laufzeit > 0,
[[Years2Go]] is Laufzeit - 1,
zzins(Anlage, Zinssatz, [[Years2Go]], [[ZwischenBetrag]]),
Ausschuettung is ([[ZwischenBetrag]] * (1 + Zinssatz/100)).
% Aufgabe 2b
% ----------
% Im Prolog-System genügen fünf Nachkommastellen, um genaue
% Verdopplung zu erreichen:
%
% ?- zzins(1000,7.17735,10,X).
%
% X = 2000.0
% Es gibt eine analytische Loesung, denn für das Kapital
% K_n nach n Jahren gilt bei einem Zinssatz p und einem
% Startkapital K:
%
% K_n = K * (1 + p/100)^n
%
% Damit ergibt sich für eine Verdopplung von K nach 10 Jahren
% (also K_10 = 2 * K) für den Zinssatz p folgende Gleichheit:
%
% p = (sqrt(10, 2) - 1) * 100 = 7.1773463
%
% wobei sqrt(10, 2) die 10te Wurzel aus 2 berechnet.
% Aufgabe 2c
% ----------
% Prädikat zzinslist(+Anlage, +Zinssatz, +Laufzeit, ?Liste)
%
% Liefert zu einem Startkapital +Anlage und einem Zinssatz +Zinssatz
% eine Liste ?Liste der Kapitalbeträge in den Jahren +Laufzeit, in
% denen das Anlagekapital verzinst wird
zzinslist(Anlage, Zinssatz, Laufzeit, Liste) :-
findall(
kapital(Jahr, Kapital),
(between(0, Laufzeit, Jahr),
zzins(Anlage, Zinssatz, Jahr, Kapital)),
Liste).
% ?-zzinslist(10000, 7.17735, 10, List).
% List = [kapital(0, 10000),
% kapital(1, 10717.7),
% kapital(2, 11487.0),
% kapital(3, 12311.4),
% kapital(4, 13195.1),
% kapital(5, 14142.1),
% kapital(6, 15157.2),
% kapital(7, 16245.1),
% kapital(8, 17411.0),
% kapital(9, 18660.7),
% kapital(10, 20000.0)]
% Aufgabe 3
% ---------
% Hier ein Beispiel, in dem das Ausmaß des quadratischen Wachstums
% veranschaulicht wird. Es wird eine normale Parabel gezeichnet, deren
% Punkte aber proportional zum Funktionswert größer werden. Das
% Ergebnis könnte jedem Monster[[/Alien/Katastrophenfilm]] entnommen sein;
% schon kubisches Wachstum wäre nicht mehr richtig zu erkennen,
% geschweige denn exponentielles.
%
% Man beachte die symmetrischen Moirémuster unterhalb des letzten
% Funktionswertes.
draw(Max) :-
free(@bild),
new(@bild,picture('Beispiel',size(900,900))),
send(@bild,background,colour(black)),
send(@bild,open),
draw_parabola(@bild,0,Max).
% draw_parabola(+Bildobjekt, +X, +[[MaxX]]) erzeugt eine normale Parabel,
% d.h. die Kurve y = x^2, wobei die Punkte proportional zum Wert y
% größer werden.
draw_parabola(_,X,[[MaxX]]):- X >= [[MaxX]].
draw_parabola(Bild,X,[[MaxX]]) :-
Y is X*X / 100,
new(O, circle(Y)),
send(O,fill_pattern(colour(yellow))),
% XPCE zählt Y von links oben, aber wir wollen von links unten zählen
Y2 is 300 - Y,
send(Bild, display(O, point(X,Y2))),
X2 is X + 1,
draw_parabola(Bild,X2,[[MaxX]]).
% :-draw(300).
% Aufgabe 4a
% ----------
% (i) Bindungen sind X=y und Y=x
% (ii) Bindungen sind L=a und X=[a,a]
% (iii) Bindungen sind F=[a,b], G=[[a,[b]], [[b]|a]], A=a und B=[b]
% Aufgabe 4b
% ----------
%% Prädikat last\2
%% mylast(+List, +Element)
%% Ausgabe: yes, wenn letztes Element der Liste +List
%% mit dem Element +Element identisch ist.
mylast([Last], Last).
mylast([_|Tail], Element) :- mylast(Tail, Element).
% Das Prädikat läßt sich sowohl zum Testen als auch zum Extrahieren
% oder Generieren einsetzten. Wenn nur Variable angegeben werden,
% werden nacheinander abstrakte Listen aller möglichen Längen
% angegeben. Bei leeren Listen mißlingt der Aufruf sofort.
% Aufgabe 4c
% ----------
% Hilfsprädikat gerade_Pos(+Liste, ?Element)
% ist erfolgreich, falls ?Element an einer Position
% in +Liste mit geradem Index steht (der Index ist
% nullbasiert, d.h. das erste Element in der Liste hat
% Index 0, das zweite Element den Index 1, ...)
%
% Die Anwendung dieses Prädikates auf eine leere Liste
% ist nicht erfolgreich.
gerade_Pos([_,E|_], E).
gerade_Pos([_,_|R], E) :- gerade_Pos(R,E).
% Teil (i)
% --------
% Prädikat slice_i(+Liste, ?[[NewList]])
%
% Extrahiert aus der Liste +Liste jedes zweite Element und
% speichert diese mit Hilfe gerade_Pos/2 und findall/3 in
% ?[[NewList]]
%
% Da gerade_Pos/2 für eine leere Liste nicht erfolgreich,
% liefert slice_i([], [[NewList]]) in [[NewList]] auch eine leere
% Liste.
slice_i(List, [[NewList]]) :-
findall(Element, gerade_Pos(List, Element), [[NewList]]).
% Teil (ii)
% ---------
% Prädikat slice_ii(+Liste, ?[[NewList]])
%
% Extrahiert aus der Liste +Liste jedes zweite Element und
% konstruiert mit Hilfe von von Rekursion eine Ergebnisliste,
% die genau diese Elemente enthält
slice_ii([], []).
slice_ii([_], []).
slice_ii([_,Element2|Tail], [Element2|[[NewList]]]) :- slice_ii(Tail, [[NewList]]).