diff --git a/Tutorium/tut07/README.md b/Tutorium/tut07/README.md index e69de29..33ce71c 100644 --- a/Tutorium/tut07/README.md +++ b/Tutorium/tut07/README.md @@ -0,0 +1,169 @@ +# Tutorium 07 - 01.12.2023 + +## Execrise 06 + +- Korrektur wieder am Samstag + +### Problematik ChatGPT und Plagiate + +- ChatGPT ist ein tolles Tool, warum? + - Manchmal liefert es andere Lösungen zu Problemen + - Grundverständnis bei neuen Problemen + - integriert in die IDE (z.B. Github Copilot): + - schneller Code schreiben +
+ Wie viele Zeilen Code schreibt ein Entwickler durchschnittlich am Tag? + 10 bis 50 Codezeilen +
+ - Leichtsinnsfehler ausbessern + - Kurz: Es nimmt einen repetetive Arbeit ab + +#### Die Problematik? + +- Ein EidP soll das Grundverständnis von Programmieren vermittelt werden + - Denkweise + - Konzepte in der theoretischen Informatik + - Konzepte in Programmiersprachen + - Übung +- Um ChatGPT sinnvoll zu nutzen müsst ihr diese Grundverständnis bereits besitzen +- Auch Studierende mit Vorwissen profitieren davon die Übung sinnvoll zu bearbeiten + - Wenn Ihr für die Aufgaben ChatGPT verwendet, dann habt ihr nicht genug Vorwissen + +
+Studienleistung WS2022 + +
+
+Notenverteilung WS2022 + +
+ + +#### Also, macht eure Aufgaben selber! + +---- + +## Wichtiges/Hilfreiches für Exercise-07 + +### Rekursion + +- Rekursion in Python sind Funktionen die sich selbst aufrufen + ```python + def fac(n: int) -> int: + if n <= 1: # Abbruchbedingung, kein Rekursiver Aufruf mehr! + return 1 + return n * fac(n - 1) # Rekursiver Aufruf + ``` +- Eine Rekursion braucht eine **Abbruchbedingung** +- primitive Rekursionen können auch einfach iterative gelöst werden + ```python + def fac2(n: int) -> int: + fac = 1 + for i in range(1, n + 1): + fac *= i + return fac + ``` +- Eine Rekursion kann mehrere Rekursionspfade haben! (Kaskadenförmige Rekursion), welche auch primitiv berechenbar sind! + ```python + def fib(n: int) -> int: + if n in {0, 1}: # Abbruchbedingung + return n + return fib(n - 1) + fib(n - 2) # mehrere Rekursionsaufrufe + ``` +- Wie Funktioniert das? + - Es wird ein Rekursionsbaum aufgebaut + - Wenn dieser Fertig ist wird berechnet + - Z.b. `fac`: + ``` + fac(5) + 5 * fac(4) + 5 * 4 * fac(3) + 5 * 4 * 3 * fac(2) + 5 * 4 * 3 * 2 * fac(1) + 5 * 4 * 3 * 2 * 1 + 120 + ``` + + ``` + fib(4) + fib(3) + fib(2) + (fib(2) + fib(1)) + (fib(0) + fib(1)) + ((fib(0) + fib(1)) + fib(1)) + (fib(0) + fib(1)) + ((0 + 1) + 1) + (0 + 1) + 3 + ``` +- Gibt es Rekursionen die nicht iterative berechenbar sind? + - $\mu$-Rekursionen oder partiell Rekursionen + - erste partiell rekursive Funktion von Wilhelm Ackermann 1926, die "Ackermannfunktion" + $\alpha(0, m) = m + 1$ + $\alpha(n, 0) = \alpha(n - 1, 1)$ + $\alpha(n, m) = \alpha(n, \alpha(n, m - 1))$ + + ```python + def ack(n: int, m: int) -> int: + match (n, m): + case (0, _): + return m + 1 + case (_, 0): + return ack(n - 1, 1) + case _: + return ack(n - 1, ack(n, m - 1)) + ``` + +#### Tipp: + +Man kann alles rekursiv Aufbauen mit Operatoren (`+, -, *, /, %, //, &&, and, ...`), also auch Listen oder Strings + +```python +def all_fac(max: int) -> list[(int, int)]: + if max == 0: # Abbruchbedingung + return [(0, 1)] + return [(max, fac(max))] + all_fac(max - 1) # Rekursion + +def all_fac_str(min: int, max: int) -> str: + if min >= max: # Abbruchbedingung + return f"{fac(min)}" + return f"{fac(min)} " + all_fac_str(min + 1, max) # Rekursion + +def fib_str(n: int) -> str: + if n in {0, 1}: # Abbruchbedingung + return str(n) + return f"({fib_str(n - 1)} + {fib_str(n - 2)})" # Rekursion +``` + +### Rekursion in Bäumen + +- Drei möglichkeiten einen Baum *abzulaufen* + - **Pre-Order**: Knoten, links, rechts + ```python + def preorder[T](tree: BTree[T]): + match tree: + case Node(value, left, right): + print(value) + preorder(left) + preorder(right) + case _: + return + ``` + - **Post-Order**: links, rechts, Knoten + ```python + def postorder[T](tree: BTree[T]): + match tree: + case Node(value, left, right): + postorder(left) + postorder(right) + print(value) + case _: + return + ``` + - **In-Order**: links, Knoten, rechts + ```python + def inorder[T](tree: BTree[T]): + match tree: + case Node(value, left, right): + inorder(left) + print(value) + inorder(right) + case _: + return + ``` \ No newline at end of file diff --git a/Tutorium/tut07/img/ws2022-notenverteilung.png b/Tutorium/tut07/img/ws2022-notenverteilung.png new file mode 100644 index 0000000..762909f Binary files /dev/null and b/Tutorium/tut07/img/ws2022-notenverteilung.png differ diff --git a/Tutorium/tut07/img/ws2022-studienleistung.png b/Tutorium/tut07/img/ws2022-studienleistung.png new file mode 100644 index 0000000..0a6665d Binary files /dev/null and b/Tutorium/tut07/img/ws2022-studienleistung.png differ diff --git a/Tutorium/tut07/src/solutions-exercise-06/mastermind.py b/Tutorium/tut07/src/solutions-exercise-06/mastermind.py new file mode 100644 index 0000000..7d8dbf6 --- /dev/null +++ b/Tutorium/tut07/src/solutions-exercise-06/mastermind.py @@ -0,0 +1,57 @@ +import random + + +def remove_char(string: str, c: str) -> str: + for i, s in enumerate(string): + if s == c: + return string[:i] + string[i + 1:] + return string + + +def perfect_chars(inp: str, sol: str) -> str: + chars = "" + for c, s in zip(inp, sol): + if c == s: + chars = chars + c + return chars + + +def correct_chars(inp: str, sol: str) -> str: + res = "" + for c in inp: + if c in sol: + res += c + sol = remove_char(sol, c) + return res + + +def compare(inp: str, sol: str) -> tuple[int, int]: + perfect = len(perfect_chars(inp, sol)) + correct = len(correct_chars(inp, sol)) + return perfect, correct - perfect + + +def compare_alt(inp: str, sol: str) -> tuple[int, int]: + perfect = perfect_chars(inp, sol) + for c in perfect: + sol = remove_char(sol, c) + inp = remove_char(inp, c) + correct = correct_chars(inp, sol) + return len(perfect), len(correct) + + +def game(length: int, symbols: str): + solution = "".join(random.choices(symbols, k=length)) + print("Länge:", length, "Zeichen:", symbols) + result = (0, 0) + while result != (length, 0): + c = input() + if len(c) != length: + print("Try again!") + continue + result = compare(c, solution) + print("Antwort:", result[0] * "X" + result[1] * "-") + + +if __name__ == '__main__': + game(5, "ABCDE") diff --git a/Tutorium/tut07/src/solutions-exercise-06/typevars.py b/Tutorium/tut07/src/solutions-exercise-06/typevars.py new file mode 100644 index 0000000..2c79ae1 --- /dev/null +++ b/Tutorium/tut07/src/solutions-exercise-06/typevars.py @@ -0,0 +1,35 @@ +from typing import Optional + + +def head[T](xs: list[T]) -> Optional[T]: + if not xs: + return None + return xs[0] + + +def tail[T](xs: list[T]) -> Optional[list[T]]: + if not xs: + return None + return xs[1:] + + +def concat[T](xss: list[list[T]]) -> list[T]: + outer = list() + for xs in xss: + outer += xs + return outer + + +def zip[T, U](xs: list[T], ys: list[U]) -> list[tuple[T, U]]: + out = list() + for i, x in enumerate(xs): + if i >= len(ys): + return out + else: + out += [(x, ys[i])] + return out + + +def assoc[T, U, V](t: tuple[tuple[T, U], V]) -> tuple[T, tuple[U, V]]: + (x, y), z = t + return (x, (y, z)) diff --git a/Tutorium/tut07/src/trees.py b/Tutorium/tut07/src/trees.py new file mode 100644 index 0000000..fcc4c52 --- /dev/null +++ b/Tutorium/tut07/src/trees.py @@ -0,0 +1,36 @@ +@dataclass +class Node[T]: + value: T + left: Optional['Node[T]'] = None + right: Optional['Node[T]'] = None + +type BTree[T] = Node[T] | None + +def preorder[T](tree: BTree[T]): + match tree: + case Node(value, left, right): + print(value) + preorder(left) + preorder(right) + case _: + return + + +def postorder[T](tree: BTree[T]): + match tree: + case Node(value, left, right): + postorder(left) + postorder(right) + print(value) + case _: + return + + +def inorder[T](tree: BTree[T]): + match tree: + case Node(value, left, right): + inorder(left) + print(value) + inorder(right) + case _: + return \ No newline at end of file diff --git a/Tutorium/tut07/src/tutorium_07.py b/Tutorium/tut07/src/tutorium_07.py new file mode 100644 index 0000000..71356f0 --- /dev/null +++ b/Tutorium/tut07/src/tutorium_07.py @@ -0,0 +1,55 @@ +def fibonacci(n: int) -> int: + if n in {0, 1}: # Abbruchbedingung + return n + return fibonacci(n - 1) + fibonacci(n - 2) # mehrere Rekursionsaufrufe + + +def fac(n: int) -> int: + if n <= 0: # Abbruchbedingung, kein Rekursiver Aufruf mehr! + return 1 + return n * fac(n - 1) # Rekursiver Aufruf + + +def fac2(n: int) -> int: + num = 1 + for i in range(1, n + 1): + num *= i + return num + + +def ack(n: int, m: int) -> int: + match (n, m): + case (0, _): + return m + 1 + case (_, 0): + return ack(n - 1, 1) + case _: + return ack(n - 1, ack(n, m - 1)) + + +def all_fac(max: int) -> list[(int, int)]: + if max == 0: # Abbruchbedingung + return [(0, 1)] + return [(max, fac(max))] + all_fac(max - 1) # Rekursion + + +def all_fac_str(min: int, max: int) -> str: + if min >= max: # Abbruchbedingung + return f"{fac(min)}" + return f"{fac(min)} " + all_fac_str(min + 1, max) # Rekursion + + +def fib_str(n: int) -> str: + if n in {0, 1}: + return str(n) + return f"({fib_str(n - 1)} + {fib_str(n - 2)})" + + +if __name__ == "__main__": + assert [fibonacci(n) for n in range(15)] == [0, 1, 1, 2, + 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377] + assert [fac(n) for n in range(11)] == [1, 1, 2, 6, 24, + 120, 720, 5040, 40320, 362880, 3628800] + assert [fac(n) for n in range(10)] == [fac2(n) for n in range(10)] + assert list(reversed(all_fac(10))) == [(n, fac(n)) for n in range(11)] + assert all_fac_str(0, 10) == "1 1 2 6 24 120 720 5040 40320 362880 3628800"