;;; Daniel Schreck  2507496
;;; Johannes Wender 2029525
;;; Robert Vollmann 2030097
(let ((board nil))
  (labels (

		   (empty-board ()
						"Erzeugt ein leeres board"
						(make-array '(3 3)))

		   (is-taken (rowcol board)
					 "Überprüft ob das Feld belegt ist"
					 (or 
					   (equal (get-pos (first rowcol) (second rowcol) board) 'o)
					   (equal (get-pos (first rowcol) (second rowcol) board) 'x)))

		   (is-empty (rowcol board)
					 "Überprüft ob das Feld nicht belegt ist"
					 (not (is-taken rowcol board)))

		   ; 'x := Muss vom ersten Spieler belegt sein
		   ; 'o := Muss vom zweiten Spieler belegt sein
		   ; '_ := Hier darf noch nichts festgestellt worden sein
		   ; '? := beliebig
		   (matches-pattern-of-cell (x y pattern board)
											  "Überprüft ob Position (x y) des Boards dem gegebenen Pattern entspricht."
											  (cond ((and (equal pattern 'x) 
														  (not (equal (get-pos x y board) 'x))) (not t))
													((and (equal pattern 'o) 
														  (not (equal (get-pos x y board) 'o))) (not t))
													((and (equal pattern '_) 
														  (is-taken (list x y) board)) (not t))
													(t 			t)))  ; Nimm an, er wäre '? verlangt, ist immer ok.		

		   (matches-pattern (p00 p01 p02 p10 p11 p12 p20 p21 p22 board)
									  "Überprüft ob das Board einem gegebenen Pattern entspricht."
									  (and 	(matches-pattern-of-cell 0 0 p00 board)
											(matches-pattern-of-cell 0 1 p01 board)
											(matches-pattern-of-cell 0 2 p02 board)
											(matches-pattern-of-cell 1 0 p10 board)
											(matches-pattern-of-cell 1 1 p11 board)
											(matches-pattern-of-cell 1 2 p12 board)
											(matches-pattern-of-cell 2 0 p20 board)
											(matches-pattern-of-cell 2 1 p21 board)
											(matches-pattern-of-cell 2 2 p22 board)))
											
	(guarantee-OK (rowcol board)
	   "Stellt sicher das wir einen, irgendeinen gültigen Zug machen."
		 (if (is-taken rowcol board)
		 (progn (format t "PLAYER COULD KNOW ~a \n" rowcol) 
		  (cond   ((is-empty '(0 0) board) '(0 0))  ; Ein freies Feld waehlen
				((is-empty '(0 1) board) '(0 1))
				((is-empty '(0 2) board) '(0 2))
				((is-empty '(1 0) board) '(1 0))
				((is-empty '(1 1) board) '(1 1))
				((is-empty '(1 2) board) '(1 2))
				((is-empty '(2 0) board) '(2 0))
				((is-empty '(2 1) board) '(2 1))
				(t			       '(2 2)))) 
		 rowcol)) ; Alles ok. Ist bereits ein freies Feld
		 
		   (set-pos (row col board mark)
					"Setzt eine Markierung auf das Board"
					(setf (aref board row col) mark)
					board)

		   (get-pos (row col board)
					"Liefert die Art der Markierung auf dem gegebenen Feld"
					(aref board row col))

		   (compute-move (board action count)
						 "Berechnet den nächsten Zug"
						   (if (= (mod count 2) 0)
							 ;Der Pattern-matcher überprüft die gegenwärtige Position und reagiert entsprechend darauf
							 
							 ;Falls wir anfangen
							 (cond
								 ; 1. Stein
								((matches-pattern 
									'_ '_ '_
									'_ '_ '_
									'_ '_ '_ 
									board)	'(1 1))

									; Stein 2
									((matches-pattern 
										'_ '_ '_
										'_ 'x '_
										'_ '_ '_ 
										board)	'(0 1))
								
										; Stein 3
										((matches-pattern 
											'_ 'x '_
											'_ 'x '_
											'_ '_ '_ 
											board)	'(2 1))
									
										; Stein 3
										((matches-pattern 
											'_ 'x '_
											'_ 'x '_
											'_ 'o '_ 
											board)	'(2 2))
									
											; Stein 4
											((matches-pattern 
												'_ 'x '_
												'_ 'x '_
												'_ 'o 'x 
												board)	'(0 0))
										
											; Stein 4
											((matches-pattern 
												'o 'x '_
												'_ 'x '_
												'_ 'o 'x 
												board)	'(1 0))
												
												; Stein 5
												((matches-pattern 
													'o 'x '_
													'x 'x '_
													'_ 'o 'x 
													board)	'(1 2))
											
												; Stein 5
												((matches-pattern 
													'o 'x '_
													'x 'x 'o
													'_ 'o 'x 
													board)	'(0 2))
											
												; Stein 5
												((matches-pattern 
													'o 'x 'o
													'x 'x 'o
													'_ 'o 'x 
													board)	'(2 0))
											
											; Stein 4
											((matches-pattern 
												'o 'x '_
												'o 'x '_
												'_ 'o 'x 
												board)	'(2 0))
										
												; Stein 5
												((matches-pattern 
													'o 'x '_
													'o 'x '_
													'x 'o 'x 
													board)	'(0 2))
										
												; Stein 5
												((matches-pattern 
													'o 'x 'o
													'o 'x '_
													'x 'o 'x 
													board)	'(1 2))
													
										; Stein 3
										((matches-pattern 
											'_ 'x '_
											'_ 'x '_
											'_ 'o 'o 
											board)	'(2 0))
									
											; Stein 4
											((matches-pattern 
												'_ 'x '_
												'_ 'x '_
												'x 'o 'o 
												board)	'(0 2))
									
											; Stein 4
											((matches-pattern 
												'_ 'x 'o
												'_ 'x '_
												'x 'o 'o 
												board)	'(1 2))
									
											; Stein 5
											((matches-pattern 
												'_ 'x 'o
												'_ 'x 'x
												'x 'o 'o 
												board)	'(1 0))
									
											; Stein 5
											((matches-pattern 
												'_ 'x 'o
												'o 'x 'x
												'x 'o 'o 
												board)	'(0 0))
									
									; Stein 2
									((matches-pattern 
										'_ 'o '_
										'_ 'x '_
										'_ '_ '_ 
										board)	'(1 2))
								
										; Stein 3
										((matches-pattern 
											'_ 'o '_
											'_ 'x 'x
											'_ '_ '_ 
											board)	'(1 0))
								
										; Stein 3
										((matches-pattern 
											'_ 'o '_
											'o 'x 'x
											'_ '_ '_ 
											board)	'(2 2))
								
											; Stein 4
											((matches-pattern 
												'_ 'o '_
												'o 'x 'x
												'_ '_ 'x 
												board)	'(0 2))

											; Stein 4
											((matches-pattern 
												'_ 'o 'o
												'o 'x 'x
												'_ '_ 'x 
												board)	'(0 0))
												
								(t (progn (print "Achtung, das stimmt was nicht. Kein passendes Muster gefunden!\n") '(0 0))))
							 ;Falls wir nicht anfangen
							 (progn 
							   (cond
								 ; 1. Stein
								 ((matches-pattern 
									'_ '_ '_
									'_ '_ '_
									'_ '_ '_ 
									board)		'(1 1))

								 ; Gegner hat Mitte				 

								 ((matches-pattern 
									'_ '_ '_
									'_ 'o '_
									'_ '_ '_ 
									board)		'(0 0))

								 ; 2. Stein
								 ((matches-pattern 
									'_ '_ '_
									'_ 'x '_
									'_ '_ '_ 
									board)		'(0 0))

								 ((matches-pattern 
									'o '_ '_
									'_ 'x '_
									'_ '_ '_ 
									board)		'(2 0))

								 ((matches-pattern 
									'o '_ '_
									'_ 'x '_
									'o '_ '_ 
									board)		'(1 0))

								 ; Gegner hat Mitte				 

								 ((matches-pattern 
									'x '_ '_
									'_ 'o '_
									'_ '_ '_ 
									board)		'(0 2))

								 ((matches-pattern 
									'x '_ 'o
									'_ 'o '_
									'_ '_ '_ 
									board)		'(2 0))

								 ; 3. Stein
								 ((matches-pattern 
									'x '_ '_
									'_ 'x '_
									'_ '_ '_ 
									board)		'(2 2))

								 ((matches-pattern 
									'x '_ '_
									'_ 'x '_
									'_ '_ 'o 
									board)		'(0 2))

								 ((matches-pattern 
									'x '_ 'o
									'_ 'x '_
									'_ '_ 'o 
									board)		'(1 2))  ; Zug ist sicher, da sonst schon zuvor beendet worden wäre

								 ((matches-pattern 
									'o '_ '_
									'_ 'x '_
									'x '_ '_ 
									board)		'(0 2))

								 ((matches-pattern 
									'o '_ 'o
									'_ 'x '_
									'x '_ '_ 
									board)		'(0 1))

								 ((matches-pattern 
									'o '_ '_
									'x 'x '_
									'o '_ '_ 
									board)		'(1 2))

								 ((matches-pattern 
									'o '_ '_
									'x 'x 'o
									'o '_ '_ 
									board)		'(2 1))

								 ; Gegner hat Mitte				 

								 ((matches-pattern 
									'x '_ 'x
									'_ 'o '_
									'_ '_ '_ 
									board)		'(0 1))

								 ((matches-pattern 
									'x 'o 'x
									'_ 'o '_
									'_ '_ '_ 
									board)		'(2 1)) ; Zug ist sicher, da sonst schon zuvor beendet worden wäre

								 ((matches-pattern 
									'x '_ 'o
									'_ 'o '_
									'x '_ '_ 
									board)		'(1 0))

								 ((matches-pattern 
									'x '_ 'o
									'o 'o '_
									'x '_ '_ 
									board)		'(1 2))

								 ; 4. Stein	 
								 ((matches-pattern 
									'x '_ 'x
									'_ 'x '_
									'_ '_ 'o 
									board)		'(2 0))

								 ((matches-pattern 
									'x '_ 'x
									'_ 'x '_
									'o '_ 'o 
									board)		'(0 1))
									
								 ((matches-pattern 
									'x 'o 'x
									'_ 'x '_
									'o '_ 'o 
									board)		'(2 1))
								 
								 ((matches-pattern 
									'x '_ 'o
									'_ 'x 'x
									'_ '_ 'o 
									board)		'(1 0))

								 ((matches-pattern 
									'x '_ 'o
									'o 'x 'x
									'_ '_ 'o 
									board)		'(2 1)) 

								 ((matches-pattern 
									'x '_ 'o
									'o 'x 'x
									'_ 'o 'o 
									board)		'(2 0)) 
								 
								 ((matches-pattern 
									'o 'x 'o
									'_ 'x '_
									'x '_ '_ 
									board)		'(2 1))  
									
								 ((matches-pattern 
									'o 'x 'o
									'_ 'x '_
									'x 'o '_ 
									board)		'(1 2))
	
								 ((matches-pattern 
									'o 'x 'o
									'_ 'x 'o
									'x 'o '_ 
									board)		'(2 2))
								 
								 ((matches-pattern 
									'o '_ '_
									'x 'x 'o
									'o 'x '_ 
									board)		'(0 1))

								 ((matches-pattern 
									'o 'o '_
									'x 'x 'o
									'o 'x '_ 
									board)		'(0 2))
								 
								 ; Gegner hat Mitte				 

								 ((matches-pattern 
									'x 'o 'x
									'_ 'o '_
									'_ 'x '_ 
									board)		'(1 0)) 

								 ((matches-pattern 
									'x 'o 'x
									'o 'o '_
									'_ 'x '_ 
									board)		'(1 2)) ; Zug ist sicher, da sonst schon zuvor beendet worden wäre

								 ((matches-pattern 
									'x '_ 'o
									'o 'o 'x
									'x '_ '_ 
									board)		'(2 1))

								 ((matches-pattern 
									'x '_ 'o
									'o 'o 'x
									'x 'o '_ 
									board)		'(0 1))
								 (t	(progn (print "Achtung, das stimmt was nicht. Kein passendes Muster gefunden!\n") '(0 0))))))))

	#'(lambda (action count)
		(when (null board) (setf board (empty-board))) 

		(unless (null action)
		  (setf board
				(set-pos (first action) (second action) board 'o)))

		(let ((pos (guarantee-OK (compute-move board action count) board))) ; von compute-move gelieferter Zug wird sicherheitshalber nochmal überprüft 
		  (setf board
				(set-pos (first pos) (second pos) board 'x))
		  pos)))))

