implementation module Sokoban import StdFile import StdList import StdString import StdMisc Start :: *World -> (String, *World) Start w # (s, w) = parse "../sokobanzip/screens/screen.1" w = ("\n" +++ toString s, w) instance toString SokobanPuzzle where toString (Sokoban []) = "" toString (Sokoban [[]:rows]) = "\n" +++ toString (Sokoban rows) toString (Sokoban [[x:xs]:rows]) = toString x +++ toString (Sokoban [xs:rows]) instance toString SokobanTile where toString Free = " " toString Wall = "#" toString Box = "$" toString Agent = "@" toString Target = "." toString TargetBox = "*" toString TargetAgent = "+" parseFromFile :: *File -> (SokobanPuzzle, *File) parseFromFile f # (contents, f) = readEntireFile f | isEmpty contents = abort "File is empty or unreadable" = (Sokoban (parseRows contents), f) parse :: String *World -> (SokobanPuzzle, *World) parse fp w # (ok, f, w) = fopen fp FReadText w | not ok = abort ("Couldn't open file: '" +++ fp +++ "'") # (puzzle, f) = parseFromFile f # (ok, w) = fclose f w | not ok = abort "Couldn't close file" = (puzzle, w) numberOfBlocks :: SokobanPuzzle -> Int numberOfBlocks (Sokoban bs) = let fbs = flatten bs in length ([1\\(Box)<-fbs] ++ [1\\(TargetBox)<-fbs]) parseRows :: [Char] -> [[SokobanTile]] parseRows cs = case parseRow cs of ([], _) = [] (x, rest) = [x:parseRows rest] parseRow :: [Char] -> ([SokobanTile], [Char]) parseRow [] = ([], []) parseRow ['\n':xs] = ([], xs) parseRow [x:xs] # (rest, xs) = parseRow xs # current = case x of '#' = Wall '$' = Box '@' = Agent '.' = Target '+' = TargetAgent '*' = TargetBox ' ' = Free _ = abort ("Unknown char: '" +++ toString x +++ "'") = ([current:rest], xs) readEntireFile :: *File -> *([Char], *File) readEntireFile f # (b, c, f) = freadc f | not b = ([], f) # (cs, f) = readEntireFile f = ([c:cs], f)