module Rubik.IDA where
import qualified Data.Set as S
data Succ label length node = Succ {
eLabel :: label,
eCost :: length,
eSucc :: node
}
data Search f a l node = Search {
goal :: node -> Bool,
estm :: node -> a,
edges :: node -> f (Succ l a node)
}
type Result a l = Maybe [l]
data SearchResult a l = Next !a | Found [l] | Stop
instance Ord a => Monoid (SearchResult a l) where
mempty = Stop
mappend f@(Found _) _ = f
mappend _ f@(Found _) = f
mappend (Next a) (Next b) = Next (min a b)
mappend Stop x = x
mappend x Stop = x
dfSearch
:: (Foldable f, Num a, Ord a)
=> Search f a l node
-> node -> a -> [l] -> a -> SearchResult a l
dfSearch (Search goal estm edges) n g ls bound
= dfs n g ls bound
where
dfs n g ls bound
| g == bound && g == f && goal n = Found (reverse ls)
| f > bound = Next f
| otherwise
= foldMap searchSucc $ edges n
where
isGoal = goal n
f = g + estm n
searchSucc (Succ eLabel eCost eSucc)
= dfs eSucc (g + eCost) (eLabel : ls) bound
search
:: forall f a l node . (Foldable f, Num a, Ord a)
=> Search f a l node
-> node -> Maybe [l]
search s root = rootSearch (estm s root)
where
rootSearch :: a -> Maybe [l]
rootSearch d =
case dfSearch s root 0 [] d of
Stop -> Nothing
Found ls -> Just ls
Next d' -> rootSearch d'
data SelfAvoid node = SelfAvoid (S.Set node) node
selfAvoid (Search goal estm edges) = Search {
goal = goal . node,
estm = estm . node,
edges = edges'
}
where
node (SelfAvoid _ n) = n
edges' (SelfAvoid trace n)
= [ Succ l c (SelfAvoid (S.insert s trace) s)
| Succ l c s <- edges n, S.notMember s trace ]
selfAvoidRoot root = (root, S.singleton root)