Last active
May 27, 2019 13:43
-
-
Save caotic123/9181cf740b3062acb90a4f14c52befba to your computer and use it in GitHub Desktop.
8 puzzle : A* game solver
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Control.Monad | |
import Data.Maybe | |
import qualified Data.Set as Set | |
import qualified Data.Map.Strict as Map | |
data Puzzle = Puzzle [Int] Int Int Int deriving Show | |
heuristic_comp :: [Int] -> Int | |
heuristic_comp [] = 8 | |
heuristic_comp (x : xs) = do | |
let k = (heuristic_comp xs) | |
if (x + (length (x : xs)) == 10) then (k - 1) else k | |
class A_search k where | |
goal :: k -> Bool | |
prof :: k -> Int | |
fherustic :: k -> Int | |
nodes :: k -> [Maybe k] | |
heur :: k -> Int -> Int -> k | |
instance Ord Puzzle where | |
compare (Puzzle x y c _) (Puzzle x' y' c' _) = (compare ((heuristic_comp x) + c) ((heuristic_comp x') + c')) | |
instance Eq Puzzle where | |
(Puzzle x y _ _) ==( Puzzle x' y' _ _) = (x == x' && y == y') | |
instance A_search Puzzle where | |
goal (Puzzle xs _ _ _) = xs == [1, 2, 3, 4, 5, 6, 7, 8, 0] | |
prof (Puzzle xs _ _ p) = p | |
fherustic (Puzzle xs _ _ _) = heuristic_comp xs | |
nodes k = swap k | |
heur k q i = heuristic k q i | |
data Swap_Pos a = Swap_Pos [(a -> a)] | |
split_t :: Int -> Int -> [a] -> [a] | |
split_t x y t = fst (splitAt y (snd (splitAt x t))) | |
index_ :: Int -> [a] -> a | |
index_ i xs = head (split_t (i - 1) i xs) | |
swap :: Puzzle -> [Maybe Puzzle] | |
swap (Puzzle xs i j q) = [ | |
if ((i - 4) >= 0) then | |
Just (Puzzle | |
((split_t 0 (i - 4) xs) ++ [index_ i xs] ++ (split_t (i - 3) 2 xs) ++ [index_ (i - 3) xs] ++ ((split_t i ((length xs) - i) xs))) | |
(i - 3) j q) | |
else Nothing, -- Top Rotate | |
if ((i + 3) <= (length xs)) then | |
Just (Puzzle | |
((split_t 0 (i - 1) xs) ++ [index_ (i + 3) xs] ++ (split_t i 2 xs) ++ [index_ i xs] ++ ((split_t (i + 3) ((length xs) - (i + 3)) xs))) | |
(i + 3) j q) | |
else Nothing, -- Down | |
if ((mod i 3) /= 0 && (i + 1) <= (length xs)) then | |
Just (Puzzle | |
((split_t 0 (i -1) xs) ++ [index_ (i + 1) xs] ++ [index_ i xs] ++ (split_t (i + 1) ((length xs) - (i +1)) xs)) | |
(i + 1) j q) | |
else Nothing, -- Right Rotate | |
if ((mod (i - 1) 3) /= 0 && (i - 1) >= 0) then | |
Just (Puzzle | |
((split_t 0 (i - 2) xs) ++ [index_ i xs] ++ [index_ (i - 1) xs] ++ (split_t i ((length xs) - i) xs)) | |
(i - 1) j q) | |
else Nothing -- Left Rotate | |
] | |
heuristic (Puzzle k i l q) p q' = (Puzzle k i p q') | |
expand_node m = (Prelude.foldl (\x -> \y -> case y of | |
Just y' -> ((heuristic y' 0) : x) | |
Nothing -> x) | |
[] m) | |
get_lis_puzzle (Puzzle xs _ _ _) = xs | |
print_puzzle xs = foldM_ (\x -> \y -> (show_puzzle (get_lis_puzzle y)) >>= (\a -> putStrLn " ----- " >> return a)) [] xs | |
where | |
show_puzzle :: (Show a) => [a] -> IO ([a]) | |
show_puzzle [] = return [] | |
show_puzzle xs = do | |
let puzzle_list = (split_t 3 (length xs) xs) | |
putStrLn (print_t xs) | |
v <- show_puzzle puzzle_list | |
return xs | |
print_t [] = "" | |
print_t (x : (y : (z : xs))) = " " ++ (show x) ++ " " ++ (show y) ++ " " ++ (show z) | |
expand k = expand_node (swap k) | |
discard_keys [] = [] | |
discard_keys ((x, k) : xs) = k : discard_keys xs | |
a_star :: Puzzle -> IO () | |
a_star k = do | |
let v' = (heuristic k 0 (heuristic_comp (get_lis_puzzle k))) | |
print_puzzle (search_a (Set.insert v' Set.empty)) | |
where | |
search_a :: A_search a => Ord a => (Set.Set a) -> [a] | |
search_a ls | |
| (Set.size ls > 0) = do | |
let current = (Set.findMin ls) | |
if (goal current) | |
then [current] | |
else (current : (search_a (succ (nodes current) (Set.delete current ls) ((prof current) + 1)))) | |
| otherwise = [] | |
where | |
succ (y : ls) k i = case y of | |
Just y -> do | |
(Set.insert (heur y (i + fherustic y) i) (succ ls k i)) | |
Nothing -> succ ls k i | |
succ [] k i = k | |
main :: IO () | |
main = do | |
let i = 5 -- pos of 0 in list | |
let puzzle_i = (Puzzle [1, 2, 3, 4, 0, 5, 7, 8, 6] i 0 0) | |
a_star puzzle_i | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment