works!
[mc1516pa.git] / code / SokobanObjectwise.icl
index f234ae1..15fb732 100644 (file)
@@ -1,5 +1,159 @@
 module SokobanObjectwise
 
+import StdString
+import StdFile
+import StdTuple
+import StdFunc
+import StdOrdList
+import StdList
+
+from Data.Func import $
+from Data.List import intercalate, maximum, permutations
+from Text import class Text(concat,join), instance Text String
+
 import Sokoban
 
-Start = "hi"
+:: AnnotatedSokoban :== [(Int, Int, SokobanTile)]
+
+Start :: *World -> *World
+Start w
+# (io, w) = stdio w
+# (puzzle, io) = parseFromFile io
+# io = io <<< encode puzzle <<< "\n"
+= snd (fclose io w)
+
+encode :: SokobanPuzzle -> String
+encode p = join "\n" [
+       "MODULE main",
+       "VAR",
+       encodeObVar "agent" maxX maxY,
+       join "\n" [encodeObVar ("b" <+ i) maxX maxY\\i<-boxnums],
+       "\tmovement: {left, up, right, down, finished};",
+       "--Handy variable for deltas",
+       deltaDefine,
+       "--Initial values",
+       "INIT",
+       encodeObInit "agent" agent <+ " &",
+       join " &\n" [encodeObInit ("b" <+ i) p\\p<-boxes & i<-[0..]],
+       "--Agent not on the box",
+       "INVAR " <+ encodeAgentNotOnBox boxnums <+ ";",
+       "--Allowed box positions on the field",
+       join "\n" ["INVAR "<+encodeObPosition ("b"<+b) legalPos<+";"\\b<-boxnums],
+       "--Box not on box",
+       encodeBoxOnBoxes (indexList boxes),
+       "--Allowed agent positions",
+       "INVAR " <+ encodeObPosition "agent" legalPos,
+       "--Goal state",
+       "INVAR " <+ encodeGoalState boxnums targetPos <+ ";",
+       "",
+       encodeObMovement "agent",
+       encodeBoxMovement boxnums,
+       "CTLSPEC ! EF (movement = finished);",
+
+       ""]
+       where
+               targetPos = getTargets annot
+               boxes = getBoxes annot
+               boxnums = indexList boxes
+               agent = hd $ getAgents annot
+               legalPos = legalPositions annot
+               annot = annotate p
+               (maxX, maxY) = getMetrics annot
+
+deltaDefine :: String
+deltaDefine = join "\n" [
+       "DEFINE dx := case",
+       "\t\tmovement = left : -1;",
+       "\t\tmovement = right: +1;",
+       "\t\tTRUE:              0;",
+       "\tesac;",
+       "\tdy := case",
+       "\t\tmovement = up  : -1;",
+       "\t\tmovement = down: +1;",
+       "\t\tTRUE:             0;",
+       "\tesac;"]
+
+//THIS IS NAIVE AND SHOULD BE IMPROVED
+legalPositions :: AnnotatedSokoban -> [(Int, Int)]
+legalPositions p = [(x, y)\\(x, y, t)<-p | case t of Wall=False; _=True]
+
+annotate :: SokobanPuzzle -> AnnotatedSokoban
+annotate (Sokoban p) = flatten [[(x, y, t)\\t<-r & x<-[0..]]\\r<-p & y<-[0..]]
+
+getTargets :: AnnotatedSokoban -> [(Int, Int)]
+getTargets p = [(x, y)\\(x, y, t)<-p | 
+       case t of Target=True;TargetBox=True;TargetAgent=True;_=False] 
+
+getMetrics :: AnnotatedSokoban -> (Int, Int)
+getMetrics p = (maximum (map fst3 p),maximum (map snd3 p))
+
+getAgents :: AnnotatedSokoban -> [(Int, Int)]
+getAgents p = [(x, y)\\(x, y, Agent)<-p] ++ [(x, y)\\(x, y, TargetAgent)<-p]
+
+getBoxes :: AnnotatedSokoban -> [(Int, Int)]
+getBoxes p = [(x, y)\\(x, y, Box)<-p] ++ [(x, y)\\(x, y, TargetBox)<-p]
+
+(<+) infixr 5 :: a b -> String | toString a & toString b
+(<+) a b = toString a +++ toString b
+
+encodeGoalState :: [Int] [(Int, Int)] -> String
+encodeGoalState boxes targets = "(" <+
+       join " |\n\t" (map encodeOneGoal boxtargets) <+ ")<->movement=finished"
+       where
+               boxtargets = map (zip2 targets) (permutations boxes)
+               
+               encodeOneGoal :: [((Int, Int), Int)] -> String
+               encodeOneGoal p = "(" <+ join " & " (encodeOneGoal` p) <+ ")"
+
+               encodeOneGoal` :: [((Int, Int), Int)] -> [String]
+               encodeOneGoal` [] = []
+               encodeOneGoal` [((x, y), b):xs] = [
+                       "b" <+ b <+ "x = " <+ x <+ " & " <+
+                       "b" <+ b <+ "y = " <+ y:encodeOneGoal` xs]
+
+encodeBoxOnBoxes :: [Int] -> String
+encodeBoxOnBoxes [] = ""
+encodeBoxOnBoxes [b] = ""
+encodeBoxOnBoxes [b:bs] = "INVAR " <+ encodeBoxOnBox b bs <+ ";\n" <+
+       encodeBoxOnBoxes bs
+       where
+               encodeBoxOnBox :: Int [Int] -> String
+               encodeBoxOnBox x bs = join " & " ["!(b" <+ x <+ "x=b" <+ b <+ "x &" <+ 
+                       "b" <+ x <+ "y=b" <+ b <+ "y)"\\b<-bs]
+
+encodeAgentNotOnBox :: [Int] -> String
+encodeAgentNotOnBox bs = join " &\n\t" [
+       "!(b" <+ i <+ "x = agentx & b" <+ i <+ "y = agenty)"\\i<-bs]
+
+encodeObMovement :: String -> String
+encodeObMovement s = "TRANS next(" <+ s <+ "x) = " <+ s <+ "x + dx;\n" <+
+       "TRANS next(" <+ s <+ "y) = " <+ s <+ "y + dy;"
+
+encodeObPosition :: String [(Int, Int)] -> String
+encodeObPosition b p = join " |\n\t" [forThisX b x p\\x<-removeDup $ map fst p]
+       where
+               forThisX :: String Int [(Int, Int)] -> String
+               forThisX s cx p = "(" <+ s <+ "x=" <+ cx <+ " & (" <+
+                       join " | " [s <+ "y=" <+ y \\(x, y)<-p | x == cx] <+ "))"
+
+encodeObInit :: String (Int, Int) -> String
+encodeObInit s (x, y) = "\t" <+ s <+ "x=" <+ x <+ " & " <+ s <+ "y=" <+ y
+
+encodeObVar :: String Int Int -> String
+encodeObVar s mx my = "\t" <+ s <+ "x: 0.." <+ mx <+ ";\n" <+ 
+       "\t" <+ s <+ "y: 0.." <+ my <+ ";\n"
+
+encodeBoxMovement :: [Int] -> String
+encodeBoxMovement bs = join "\n" $ map ebm bs
+       where
+               ebm :: Int -> String
+               ebm i = "TRANS next(b" <+ i <+ "x) = case\n" <+
+                       "\t\tnext(agentx) = b" <+ i <+ "x & " <+
+                       "next(agenty) = b" <+ i <+ "y: b" <+ i <+ "x + dx;\n" <+
+                       "\t\tTRUE: b" <+ i <+ "x;\n" <+
+                       "\tesac;\n" <+
+                       "TRANS next(b" <+ i <+ "y) = case\n" <+
+                       "\t\tnext(agentx) = b" <+ i <+ "x & " <+
+                       "next(agenty) = b" <+ i <+ "y: b" <+ i <+ "y + dy;\n" <+
+                       "\t\tTRUE: b" <+ i <+ "y;\n" <+
+                       "\tesac;"