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"