-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBlackAndWhite.hs
85 lines (66 loc) · 2.59 KB
/
BlackAndWhite.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
module BlackAndWhite where
import qualified Data.Set as Set
import Data.Graph.AStar
import Data.List
import Data.Maybe
data Tile = Black | White | Hole deriving (Eq, Show, Ord)
type State = [Tile]
lastWhite :: State -> Maybe Int
lastWhite state | list == [] = Nothing
| otherwise = Just $ last list where
list = elemIndices White state
firstBlack :: State -> Maybe Int
firstBlack = elemIndex Black
isSolution :: State -> Bool
isSolution state = fromMaybe False $ do
w <- lastWhite state
b <- firstBlack state
return $ w < b
inv :: State -> Int
inv state = invInner 0 state where
invInner n [] = n
invInner n (Black : xs) = invInner ((length $ elemIndices White xs) + n) xs
invInner n (x : xs) = invInner n xs
khi :: State -> Int
khi state | isInfixOf [Hole, Black, White] state || isInfixOf [Black, White, Hole] state = (-1)
| otherwise = 0
heuristic :: State -> Int
heuristic state = 2 * (inv state) + (khi state)
startState :: Int -> Int -> State
startState b w = replicate b Black ++ (replicate w White) ++ [Hole]
switchBeforPrev :: State -> Maybe State
switchBeforPrev [] = Nothing
switchBeforPrev (x : []) = Nothing
switchBeforPrev (x : y : []) = Nothing
switchBeforPrev (x : y : Hole : xs) = Just $ Hole : y : x : xs
switchBeforPrev (x : xs) = fmap (x :) (switchBeforPrev xs)
switchPrev :: State -> Maybe State
switchPrev [] = Nothing
switchPrev (x : []) = Nothing
switchPrev (x : Hole : xs) = Just $ Hole : x : xs
switchPrev (x : xs) = fmap (x :) (switchPrev xs)
switchAfterNext :: State -> Maybe State
switchAfterNext [] = Nothing
switchAfterNext (x : []) = Nothing
switchAfterNext (x : y : []) = Nothing
switchAfterNext (Hole : x : y : xs) = Just $ y : x : Hole : xs
switchAfterNext (x : xs) = fmap (x :) (switchAfterNext xs)
switchNext :: State -> Maybe State
switchNext [] = Nothing
switchNext (x : []) = Nothing
switchNext (Hole : x : xs) = Just $ x : Hole : xs
switchNext (x : xs) = fmap (x :) (switchNext xs)
moves = [switchAfterNext, switchNext, switchPrev, switchBeforPrev]
extendState :: State -> Set.Set State
extendState state = Set.fromList $ catMaybes [move state | move <- moves]
solvePuzzle :: Int -> Int -> Maybe [State]
solvePuzzle b w = aStar extendState (\a b -> 1) heuristic isSolution (startState b w)
stateToString :: State -> String
stateToString state = concatMap tileToString state ++ "\n" where
tileToString Black = "■ "
tileToString White = "□ "
tileToString Hole = "_ "
solveForOutput :: Int -> Int -> String
solveForOutput a b = case solvePuzzle a b of
Nothing -> "No solution found"
Just list -> concatMap stateToString (startState a b : list)