Advertisement
jckuri

MissionariesAndCannibals.hs

Feb 13th, 2013
140
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- MissionariesAndCannibals.hs
  2.  
  3. import qualified Data.Map as Map
  4.  
  5. data Human = Missionary | Cannibal deriving (Eq,Show,Ord)
  6. data Boat = LeftSide | RightSide deriving (Eq,Show)
  7. type Place = [Human]
  8. data State = State {
  9.  steps :: Int,
  10.  boat :: Boat,
  11.  leftSide :: Place,
  12.  rightSide :: Place,
  13.  lastState :: Maybe State,
  14.  lastTravel :: Maybe Travel
  15. }
  16. type Travel = [Human]
  17. data Counters = Counters {
  18.  missionaries :: Int,
  19.  cannibals :: Int
  20. } deriving (Show)
  21.  
  22. placeToString :: Place -> String
  23. placeToString humans=
  24.  (take (missionaries counters) $ repeat 'M')++(take (cannibals counters) $ repeat 'C')
  25.  where counters=countHumans humans
  26.  
  27. instance Eq State where
  28.  state0 == state1 =
  29.   and
  30.    [missionaries lc0==missionaries lc1,cannibals lc0==cannibals lc1,
  31.     missionaries rc0==missionaries rc1,cannibals rc0==cannibals rc1,
  32.     (boat state0)==(boat state1)]
  33.   where
  34.    lc0=countHumans (leftSide state0)
  35.    rc0=countHumans (rightSide state0)
  36.    lc1=countHumans (leftSide state1)
  37.    rc1=countHumans (rightSide state1)
  38.  
  39. instance Show State where
  40.  show (State steps boat leftSide rightSide lastState lastTravel) =
  41.   concat [parentString lastState lastTravel,"[",leftString,"~",rightString,"]"]
  42.   where
  43.    leftString=placeToString leftSide
  44.    rightString=placeToString rightSide
  45.    riverString Nothing=""
  46.    riverString (Just theLastTravel)=
  47.     let
  48.      direction=if boat==LeftSide then "<-" else "->";
  49.      travelString=placeToString theLastTravel
  50.     in
  51.      concat [show steps," ",direction,travelString,direction]
  52.    parentString Nothing _ = ""
  53.    parentString (Just theLastState) lastTravel =
  54.     concat [show theLastState," ",riverString lastTravel," "]
  55.    
  56.  
  57. initialState = State {
  58.  steps = 0,
  59.  --boat = RightSide,
  60.  boat = LeftSide,
  61.  leftSide = [Missionary,Missionary,Missionary,Cannibal,Cannibal,Cannibal],
  62.  rightSide = [],
  63.  lastState = Nothing,
  64.  lastTravel = Nothing
  65. }
  66.  
  67. initialState2 = State {
  68.  steps = 0,
  69.  --boat = RightSide,
  70.  boat = LeftSide,
  71.  leftSide = [Missionary,Missionary,Missionary,Cannibal,Cannibal],
  72.  rightSide = [],
  73.  lastState = Nothing,
  74.  lastTravel = Nothing
  75. }
  76.  
  77. countHuman :: Counters -> Human -> Counters
  78. countHuman counters human =
  79.  Counters {
  80.   missionaries=(missionaries counters)+(if human==Missionary then 1 else 0),
  81.   cannibals=(cannibals counters)+(if human==Cannibal then 1 else 0)
  82.  }
  83.  
  84. countHumans :: [Human] -> Counters
  85. countHumans humans = foldl countHuman Counters {missionaries=0,cannibals=0} humans
  86.  
  87. areThereEnoughHumans :: Place -> Travel -> Bool
  88. areThereEnoughHumans place travel =
  89.  and [missionaries placeCounters>=missionaries travelCounters,cannibals placeCounters>=cannibals travelCounters]
  90.  where
  91.   placeCounters=countHumans place
  92.   travelCounters=countHumans travel
  93.  
  94. allPossibleTravels = [[Missionary],[Cannibal],[Missionary,Cannibal],[Missionary,Missionary],[Cannibal,Cannibal]]
  95.  
  96. getPossibleTravels :: State -> [Travel]
  97. getPossibleTravels State {steps=_,boat=LeftSide,leftSide=leftSide,rightSide=_} =
  98.  filter (areThereEnoughHumans leftSide) allPossibleTravels
  99. getPossibleTravels State {steps=_,boat=RightSide,leftSide=_,rightSide=rightSide} =
  100.  filter (areThereEnoughHumans rightSide) allPossibleTravels
  101.  
  102. isPlaceSafe :: Place -> Bool
  103. isPlaceSafe place =
  104.  or [missionaries counters >= cannibals counters,missionaries counters == 0]
  105.  where counters=countHumans place
  106.  
  107. isStateSafe :: State -> Bool
  108. isStateSafe state =
  109.  and [isPlaceSafe $ leftSide state,isPlaceSafe $ rightSide state]
  110.  
  111. createPlace :: Int -> Int -> Place
  112. createPlace missionaries cannibals =
  113.  (take missionaries $ repeat Missionary) ++ (take cannibals $ repeat Cannibal)
  114.  
  115. travel :: State -> Travel -> State
  116. travel state travel =
  117.  State {
  118.   steps=(steps state)+1,
  119.   boat=newBoatPosition,
  120.   leftSide=newLeftSide,
  121.   rightSide=newRightSide,
  122.   lastState=Just state,
  123.   lastTravel=Just travel
  124.  }
  125.  where
  126.   leftCounters=countHumans $ leftSide state
  127.   rightCounters=countHumans $ rightSide state
  128.   travelCounters=countHumans travel
  129.   newBoatPosition=if boat state == LeftSide then RightSide else LeftSide
  130.   sign=if boat state == LeftSide then 1 else (-1)
  131.   newLeftSide=
  132.    createPlace ((missionaries leftCounters)-sign*(missionaries travelCounters)) ((cannibals leftCounters)-sign*(cannibals travelCounters))
  133.   newRightSide=
  134.    createPlace ((missionaries rightCounters)+sign*(missionaries travelCounters)) ((cannibals rightCounters)+sign*(cannibals travelCounters))
  135.    
  136. getPossibleNextStates :: State -> [State]
  137. getPossibleNextStates state =
  138.  filter isStateSafe (map (travel state) (getPossibleTravels state))
  139.  
  140. isFinalState :: State -> Bool
  141. isFinalState state =
  142.  and [missionaries rightCounters==3,cannibals rightCounters==3]
  143.  where rightCounters=countHumans $ rightSide state
  144.  
  145. isStateVisited :: [State] -> State -> Bool
  146. isStateVisited visitedStates state =
  147.  any (== state) visitedStates
  148.  
  149. getNextGeneration :: [State] -> [State] -> [State]
  150. getNextGeneration states visitedStates =
  151.  filter (not . (isStateVisited visitedStates)) newGen
  152.  where
  153.   newGen = foldl (\acc state -> acc++(getPossibleNextStates state)) [] states
  154.  
  155. findSolution :: [State] -> [State]-> Maybe State
  156. findSolution [] _ = Nothing
  157. findSolution states visitedStates =
  158.  if length solutions > 0 then
  159.   Just $ head solutions
  160.  else
  161.   findSolution (getNextGeneration states visitedStates) (visitedStates++states)
  162.  where
  163.   solutions = filter isFinalState states
  164.  
  165. main = do
  166.  putStrLn $ "Find Solution: " ++ (show $ findSolution [initialState] [])
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement