{- Springerproblem in Haskell

Problemstellung:
----------------
Ein Springer wird an eine vorgegebene Position 
auf ein Schachbrett gestellt.
Von dort aus soll er alle Felder des Bretts genau 
einmal besuchen (und nur erlaubte Züge auf dem Brett
machen).
Die mögliche Lösung wird ausgegeben (sofern existent).
Die Lösung soll rekursiv gefunden werden und mit
den zu definierenden Funktionen erstellt werden.
------------------------------------------------
Gegeben: Position auf dem Schachbrett
Gesucht: Nummerierung aller Felder für eine Tour auf dem Brett.
---------------------------------------------------------------}

import Char -- for GHC

data Board = Brd [[Int]]

type Position = (Int,Int)

showBoard :: Board -> IO ()
showBoard (Brd b) = do
               showBoardLines (reverse b) -- umdrehen für die übliche Darstellung...(Sicht von Weiß)
	       putStrLn ('\t':(foldr (\x str -> x:'\t':str) "" (take (length b) ['A','B'..]))) --Schlusszeile

showBoardLines :: [[Int]] -> IO ()
showBoardLines []     = return ()
showBoardLines l@(x:xs) = do
			 putStrLn (show (length l) ++ "\t" ++ concat (map ((++"\t").show) x)) -- Felder mit Tab trennen
			 showBoardLines xs 

-- für Test einschränken (ab wann existieren Lösungen ?)
boardsize :: Int
boardsize = 7

empty :: Board 
--empty = Brd (replicate 8 (replicate 8 0)) falsch
empty = Brd (replicate boardsize (replicate boardsize 0))

main :: IO ()
main = do 
        (a,b) <- inputPos
        putStrLn ("Startposition: " ++ [numToChar a,' '] ++ show (1+b) ++ ".")
	case (tryPos empty 1 (a,b)) of 
		[]      -> putStrLn ("Kein Ergebnis zu Startposition " ++ [numToChar a,' '] ++ show (1+b) ++ ".")
		(brd:_) -> do
			    putStrLn "Gefundenes Ergebnis:"
			    showBoard brd

-- Eingabe der Startposition und Konvertierung
inputPos :: IO Position
inputPos = do
	    let limits = "a-" ++ [numToChar (boardsize-1)] ++ ", 1-" ++ show (boardsize)
	    putStr ("Startposition xy (" ++ limits ++ ") eingeben: ")
	    input <- getLine
	    if (length input < 2)
	        then again
	        else let 
		       x = (toLower.head) input
		       y = (read (dropWhites (tail input))):: Int
                       pos = (charToNum x,y-1)
		     in 
                       if (not (validPos pos)) then again
		                               else return pos
     where again = do 
		    print "Falsches Eingabeformat (bitte nochmal)"
		    inputPos
	   dropWhites = dropWhile isSpace

-- Helpers:
-----------
-- Eingabekonvertierung:
charToNum :: Char -> Int
charToNum c = fromEnum c - fromEnum 'a'
numToChar :: Int -> Char
numToChar n = chr (n+97)

-- Positionen auf Gültigkeit prüfen
validPos :: Position -> Bool
validPos (a,b) = and [a>=0,a <= limit,b>=0, b<=limit]
    where limit = boardsize-1

-------------------------------------------------------------------------------

-- Liste der erlaubten Züge
moves :: Position -> Board -> [Position]
moves _ _ = [] -- To Do...

markPosition :: Int -> Position -> Board -> Board
markPosition _ _ _ = empty -- To Do...

-- backtracking-Algorithmus:
--tryPos :: ???
tryPos _ _ _ = [] -- To Do...
