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 = "." parse :: String *World -> (SokobanPuzzle, *World) parse fp w # (ok, f, w) = fopen fp FReadText w | not ok = abort ("Couldn't open file: '" +++ fp +++ "'") # (contents, f) = readEntireFile f | isEmpty contents = abort "File is empty or unreadable" # (ok, w) = fclose f w | not ok = abort "Couldn't close file" = (Sokoban (parseRows contents), w) 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 ' ' = 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)