;Tic - Tac - Toe : Human vs. Computer
;By Rohit Kumar
;Date: 3 Nov. 2002

;0 represents empty state
;1 represents human player
;2 represents computer player

;list structure ([row1 col1 state] 12 13 21 22 23 31 32 33)

(setq CurrentState '(0 0 0 0 0 0 0 0 0))
(setq Turn 0)

(defun CheckWin(GameState Player)  ;GameState is a list of 9 elements
	(if	(and (eq (nth 0 GameState) Player) (eq (nth 1 GameState) Player) (eq (nth 2 GameState) Player)) ;first row
	    	(setq temp T)
		(if	(and (eq (nth 3 GameState) Player) (eq (nth 4 GameState) Player) (eq (nth 5 GameState) Player)) ;second row
			(setq temp T)
			(if	(and (eq (nth 6 GameState) Player) (eq (nth 7 GameState) Player) (eq (nth 8 GameState) Player)) ;third row
				(setq temp T)
				(if	(and (eq (nth 0 GameState) Player) (eq (nth 3 GameState) Player) (eq (nth 6 GameState) Player)) ;first column
					(setq temp T)
					(if (and (eq (nth 1 GameState) Player) (eq (nth 4 GameState) Player) (eq (nth 7 GameState) Player)) ;second column
						(setq temp T)
						(if (and (eq (nth 2 GameState) Player) (eq (nth 5 GameState) Player) (eq (nth 8 GameState) Player)) ;third column
							(setq temp T)
							(if (and (eq (nth 0 GameState) Player) (eq (nth 4 GameState) Player) (eq (nth 8 GameState) Player)) ;diagonal 1 \
								(setq temp T)
								(if (and (eq (nth 2 GameState) Player) (eq (nth 4 GameState) Player) (eq (nth 6 GameState) Player)) ;diagonal 2 /
									(setq temp T)
								)
							)
						)
					)
				)
			)
		)
	)
)

(defun DisplayBoard (state)
	(format T "~d ~d ~d" (nth 0 state) (nth 1 state) (nth 2 state))
	(fresh-line)
	(format T "~d ~d ~d" (nth 3 state) (nth 4 state) (nth 5 state))
	(fresh-line)
	(format T "~d ~d ~d" (nth 6 state) (nth 7 state) (nth 8 state))
	(fresh-line)
)

(defun BoardFilled (state)
	(let (position)
		(dolist (position state)
			(if (eq position 0)
				(return-from BoardFilled nil)
			)
		)
		(return-from BoardFilled t)
	)
)

(defun Make2 (GameState)
	(if (eq 0 (nth 4 GameState))
		(return-from Make2 5)
	)
	(if (eq 0 (nth 1 GameState))
		(return-from Make2 2)
	)
	(if (eq 0 (nth 3 GameState))
		(return-from Make2 4)
	)
	(if (eq 0 (nth 5 GameState))
		(return-from Make2 6)
	)
	(if (eq 0 (nth 7 GameState))
		(return-from Make2 8)
	)
)

(defun Posswin (GameState PlayerNo)
	(let (temp templist pos)
		(setq templist (subseq GameState 0 9))
		(setq pos 0)
		(dolist (temp templist)
			(if (eq temp 0)
				(let ()
					(setf (nth pos templist) PlayerNo)
					(if (CheckWin templist PlayerNo)
						(return-from Posswin (+ pos 1))
					)
					(setf (nth pos templist) 0)
				)
			)
			(setq pos (1+ pos))
		)
		(return-from Posswin 0)
	)
)

(defun ComputerPlay (GameState Turn)
	(print "Turn is")
	(print Turn)
	(if (eq Turn 1)
		(return-from ComputerPlay 1)
	)
	(if (eq Turn 2)
		(if (eq 0 (nth 4 GameState))
			(return-from ComputerPlay 5)
			(return-from ComputerPlay 1)
		)
	)
	(if (eq Turn 3)
		(if (eq 0 (nth 8 GameState))
			(return-from ComputerPlay 9)
			(return-from ComputerPlay 3)
		)
	)
	(if (eq Turn 4)
		(if (not (eq 0 (setq temp (Posswin GameState 1))))
			(return-from ComputerPlay temp)
			(return-from ComputerPlay (Make2 GameState))
		)
	)
	(if (eq Turn 5)
		(if (not (eq 0 (setq temp (Posswin GameState 2))))
			(return-from ComputerPlay temp)
			(if (not (eq 0 (setq temp (Posswin GameState 1))))
				(return-from ComputerPlay temp)
				(if (eq 0 (nth 6 GameState))
					(return-from ComputerPlay 7)
					(return-from ComputerPlay 3)
				)
			)
		)
	)	
	(if (eq Turn 6)
		(if (not (eq 0 (setq temp (Posswin GameState 2))))
			(return-from ComputerPlay temp)
			(if (not (eq 0 (setq temp (Posswin GameState 1))))
				(return-from ComputerPlay temp)
				(return-from ComputerPlay (Make2))
			)
		)
	)
	(if (not (eq 0 (setq temp (Posswin GameState 2))))
		(return-from ComputerPlay temp)
		(if (not (eq 0 (setq temp (Posswin GameState 1))))
			(return-from ComputerPlay temp)
		)
	)
	(setq pos 0)
	(dolist (temp GameState)
		(if (eq 0 (nth pos GameState))
			(return-from ComputerPlay (+ 1 pos))
		)
	)
)

(defun PlayTICTACTOE ()
	(setq currentstate '(0 0 0 0 0 0 0 0 0))
	(loop
		(DisplayBoard currentstate)
		(setq Turn (1+ Turn))
		(loop
			(print "Human User 1 Turn. Enter your move (1-9): ")
			(setq humaninput (read))
			(if (eq (nth (- humaninput 1) currentstate) 0) (return nil))
		)
		(setf (nth (- humaninput 1) currentstate) 1)
		(if	(CheckWin currentstate 1)
			(let (temp1)
				(print "Human User Wins")
				(return-from PlayTICTACTOE 1)
			)
		)
		(if (BoardFilled currentstate)
			(let ()
				(print "Game is a Draw")
				(return-from PlayTicTacToe -1)
			)
		)
		(DisplayBoard currentstate)
		(setq Turn (1+ Turn))
		(print "Computer User's Turn. Deciding...")
		(setq computerinput (ComputerPlay currentstate Turn))
		(print "Done.")
		(print "Computer User Input:")
		(print computerinput)
		(setf (nth (- computerinput 1) currentstate) 2)
		(if	(CheckWin currentstate 2)
			(let (temp1)
				(print "Computer User Wins")
				(return-from PlayTICTACTOE)
			)
		)
		(if (BoardFilled currentstate)
			(let ()
				(print "Game is a Draw")
				(return-from PlayTicTacToe -1)
			)
		)
	)
)
