diff --git a/23ss_MiM_Bonus_01.pdf b/23ss_MiM_Bonus_01.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..9f6bc5da322a4ed0cd96496911a55661dfcfd99a
Binary files /dev/null and b/23ss_MiM_Bonus_01.pdf differ
diff --git a/Acht-Damen.py b/Acht-Damen.py
new file mode 100644
index 0000000000000000000000000000000000000000..2fa708495c37521db703c1b9d29f1f3033dfa3d3
--- /dev/null
+++ b/Acht-Damen.py
@@ -0,0 +1,87 @@
+import numpy as np
+from copy import deepcopy
+
+
+class Board:
+    blocked = 0
+    allowed = 1
+    queen = 2
+    
+    def __init__(self, x: int, y: int):
+        self.board = np.ones((x, y), dtype=int)
+        self.dimX = x
+        self.dimY = y
+        
+    def copy(self):
+        return deepcopy(self)
+    
+    def toConsole(self) -> None:
+        for y in range(self.dimY):
+            line = ""
+            for x in range(self.dimX):
+                if self.board[x, y] == self.blocked:
+                    line += "X"
+                if self.board[x, y] == self.allowed:
+                    line += "O"
+                if self.board[x, y] == self.queen:
+                    line += "@"
+            print(line)
+        print("")
+    
+    def print(self) -> None:
+        self.toConsole()
+    
+    def get_allowed_fields(self):
+        allowed_fields = []
+        for x in range(self.dimX):
+            for y in range(self.dimY):
+                if self.board[x, y] == self.allowed:
+                    allowed_fields.append((x, y))
+        return allowed_fields
+    
+    def get_queen_fields(self):
+        queen_fields = []
+        for x in range(self.dimX):
+            for y in range(self.dimY):
+                if self.board[x, y] == self.allowed:
+                    queen_fields.append((x, y))
+        return queen_fields
+    
+    def put_queen(self, x: int, y: int) -> bool:
+        if self.board[x, y] == self.allowed:
+            for _x in range(self.dimX):
+                self.board[_x, y] = self.blocked
+            for _y in range(self.dimY):
+                self.board[x, _y] = self.blocked
+
+            _x = x
+            _y = y
+            while _x > 0 and _y > 0:
+                _y -= 1
+                _x -= 1
+                self.board[_x, _y] = self.blocked
+            
+            _x = x
+            _y = y
+            while _x < self.dimX-1 and _y < self.dimY-1:
+                _y += 1
+                _x += 1
+                self.board[_x, _y] = self.blocked
+            self.board[x, y] = self.queen
+            return True
+        else:
+            return False
+
+
+if __name__ == "__main__":
+    board = Board(8, 8)
+    
+    saved_boards = []
+    iters = 0
+    while board.get_allowed_fields().__len__() > 0:
+        board.put_queen(board.get_allowed_fields()[0][0],
+                        board.get_allowed_fields()[0][1])
+        iters += 1
+        board.toConsole()
+        saved_boards.append(board.copy())
+    print("Queens: " + str(iters))
diff --git a/TravellingSalesman.py b/TravellingSalesman.py
index 137ea479fce93ddbf06c6df4b01593b1d7b71af6..faf277b61b9c52aa387e249537813fd3fdd26a23 100644
--- a/TravellingSalesman.py
+++ b/TravellingSalesman.py
@@ -4,16 +4,17 @@ from random import randint
 from string import ascii_uppercase
 from itertools import permutations
 # config:
-brute_force = True
-num_nodes = 9
-do_plot = True
+brute_force = False
+optimize = True
+num_nodes = 10
+do_plot = False
 pause = 1
 
 class Node:
     x: int
     y: int
     name: str
-    def __init__(self, x: int, y: int, name: str):
+    def __init__(self, x: int, y: int, name: str = ""):
         self.x = x
         self.y = y
         self.name = name
@@ -46,24 +47,27 @@ class Path:
         plt.plot([this.A.x, this.B.x], [this.A.y, this.B.y], 'go-')
 
 
-def plot_route(route: list) -> None:
+def plot_route(route: list, nodes: list = [], circle: bool = False) -> None:
     plt.close("all")
     for i in range(len(route)):
-        if i == len(route) - 1:
+        if i == len(route) - 1 and circle:
             Path(A=route[i], B=route[0]).plot()
         else:
             Path(A=route[i], B=route[i+1]).plot()
+    for node in nodes:
+        node.plot()
     plt.show()
     plt.pause(pause)
 
 
-def brute(nodes: list):
+def brute(nodes: list) -> list:
     if len(nodes) <= 1:
         return
     best_route = nodes
     best_route_length = total_distance(nodes)
     if do_plot:
         plot_route(best_route)
+#TODO Noch nicht rekursiv!
     for i, route in enumerate(permutations(nodes, len(nodes))):
         route_length = total_distance(route)
         if route_length < best_route_length:
@@ -76,6 +80,36 @@ def brute(nodes: list):
     return best_route
 
 
+def get_closest_node(current_node: Node, nodes: list) -> Node:
+    if len(nodes) == 0:
+        return
+    closest_node = nodes[0]
+    closest_distance = distance(current_node, nodes[0])
+    for node in nodes:
+        dist = distance(current_node, node)
+        if dist < closest_distance:
+            closest_node = node
+            closest_distance = dist
+    return closest_node
+
+def nearest_neighbour(_nodes: list) -> list:
+    remaining_nodes = _nodes.copy()
+    route = []
+    if len(remaining_nodes) == 0:
+        return route
+    route.append(remaining_nodes[0])
+    last_node = remaining_nodes[0]
+    remaining_nodes.remove(last_node)
+    while(len(remaining_nodes) > 0):
+        next_node = get_closest_node(last_node, remaining_nodes)
+        remaining_nodes.remove(next_node)
+        route.append(next_node)
+        last_node = next_node
+        if do_plot:
+            plot_route(route, _nodes)
+    return route
+
+
 def generate_paths(nodes: list) -> list:
     _nodes = nodes.copy()
     paths = []
@@ -94,16 +128,74 @@ def generate_paths(nodes: list) -> list:
     return paths
 
 
+#TODO Zuweisungen brechen die Kette!
+def optimize_2opt(_route: list) -> list:
+    route = _route.copy()
+    
+    for i in range(len(route)-1):
+        a = route[i]
+        b = route[i+1]
+        ab  = distance(a, b)
+        
+        for j in range(2, len(route)-1):
+            swapped = False
+            c = route[j]
+            d = route[j+1]
+            
+            cd = distance(c, d)
+            abcd = ab + cd
+            
+            ac = distance(a, c)
+            db = distance(d, b)
+            acdb = ac + db
+            
+            ad = distance(a, d)
+            cb = distance(c, b)
+            adcb = ad + cb
+            
+            if adcb < acdb:
+                if adcb < abcd:
+                    #adcb
+                    #swap d & b
+                    route[i+1] = d
+                    route[j+1] = b
+                    #abcd
+                    swapped = True
+            else:
+                if acdb < abcd:
+                    #acdb
+                    #swap c & b
+                    route[j] = b
+                    route[i+1] = c
+                    #abdc
+                    #swap c & d
+                    route[j] = d
+                    route[j+1]  = c
+                    #abcd
+                    swapped = True
+            if swapped:
+                break
+
+    
+    return route
+
+
 
 if __name__ == "__main__":
     nodes = []
     for i in range(num_nodes):
-        nodes.append(Node(x=randint(0, 100), y=randint(0, 100), name=ascii_uppercase[i]))
+        nodes.append(Node(x=randint(0, 100), y=randint(0, 100), name=str(hex(i))))
         
 
     plt.ion()
     
-    best_route = brute(nodes)
+    if brute_force:
+        best_route = brute(nodes)
+    else:
+        best_route = nearest_neighbour(nodes)
+        if optimize:
+            best_route = optimize_2opt(best_route)
+    
     
-    plot_route(best_route)
+    plot_route(best_route, nodes, circle=True)
     plt.show(block=True)