Modified AStar to take a nextNode function instead of using a typeclass

master
Abhinav Sarkar 2012-08-31 13:30:28 +05:30
parent 42c8b7db80
commit c8eaa78c82
2 changed files with 23 additions and 27 deletions

View File

@ -8,15 +8,10 @@ import qualified Data.Map as M
import Data.List (foldl') import Data.List (foldl')
import Data.Maybe (fromJust) import Data.Maybe (fromJust)
-- A node in the search
class (Ord a, Ord b, Num b, Bounded b) => SearchNode a b where
-- get the next search node and the cost to reach to it from the current node
nextNode :: a -> [(a, b)]
-- A* algorithm: Find a path from initial node to goal node using a heuristic function. -- A* algorithm: Find a path from initial node to goal node using a heuristic function.
-- Returns Nothing if no path found. Else returns Just (path cost, path). -- Returns Nothing if no path found. Else returns Just (path cost, path).
astar :: SearchNode a b => a -> a -> (a -> a -> b) -> Maybe (b, [a]) astar :: (Ord a, Ord b, Num b) => a -> a -> (a -> [(a, b)]) -> (a -> a -> b) -> Maybe (b, [a])
astar initNode goalNode hueristic = astar initNode goalNode nextNode hueristic =
astar' (PQ.singleton (hueristic initNode goalNode) (initNode, 0)) astar' (PQ.singleton (hueristic initNode goalNode) (initNode, 0))
S.empty (M.singleton initNode 0) M.empty S.empty (M.singleton initNode 0) M.empty
where where
@ -42,10 +37,12 @@ astar initNode goalNode hueristic =
-- Find the successors (with their g and h costs) of the node -- Find the successors (with their g and h costs) of the node
-- which have not been seen yet -- which have not been seen yet
successors = filter (\(s, g, _) -> successors =
not (S.member s seen') && filter (\(s, g, _) ->
g < M.findWithDefault maxBound s gscore) not (S.member s seen') &&
$ successorsAndCosts node gcost (not (s `M.member` gscore)
|| g < (fromJust . M.lookup s $ gscore)))
$ successorsAndCosts node gcost
-- Insert the successors in the open set -- Insert the successors in the open set
pq'' = foldl' (\q (s, g, h) -> PQ.insert (g + h) (s, g) q) pq' successors pq'' = foldl' (\q (s, g, h) -> PQ.insert (g + h) (s, g) q) pq' successors

View File

@ -50,25 +50,24 @@ isValidNotation notation =
head notation `elem` ['a'..'h'], head notation `elem` ['a'..'h'],
last notation `elem` ['1'..'8']] last notation `elem` ['1'..'8']]
-- Makes Board an instance of SearchNode for astar to work -- Finds the next possible board configurations for one knight's move.
instance SearchNode Board Int where -- Move cost is one.
-- Finds the next possible board configurations for one knight's move. nextKnightPos board@(Board {..}) =
-- Move cost is one. zip
nextNode board@(Board {..}) = (map (\pos -> board { knightPos = pos })
zip . filter isValidMove
(map (\pos -> board { knightPos = pos }) . map (\(x, y) -> (fst knightPos + x, snd knightPos + y))
. filter isValidMove $ moves)
. map (\(x, y) -> (fst knightPos + x, snd knightPos + y)) (repeat 1)
$ moves) where
(repeat 1) moves = [(1,2), (1,-2), (-1,2), (-1,-2), (2,1), (2,-1), (-2,1), (-2,-1)]
where isValidMove (x, y) =
moves = [(1,2), (1,-2), (-1,2), (-1,-2), (2,1), (2,-1), (-2,1), (-2,-1)] and [x > 0, x < 9, y > 0, y < 9, not $ (x, y) `S.member` blockedSquares]
isValidMove (x, y) =
and [x > 0, x < 9, y > 0, y < 9, not $ (x, y) `S.member` blockedSquares]
knightAstar heuristic blockedSquares start target = knightAstar heuristic blockedSquares start target =
fmap (second (map knightPos)) fmap (second (map knightPos))
$ astar (Board start blockedSquares) (Board target blockedSquares) heuristic $ astar (Board start blockedSquares) (Board target blockedSquares)
nextKnightPos heuristic
-- Finds a path from a start square to an end square using BFS -- Finds a path from a start square to an end square using BFS
bfsSearch :: S.Set Square -> Square -> Square -> Maybe (Int, [Square]) bfsSearch :: S.Set Square -> Square -> Square -> Maybe (Int, [Square])