Cleanup
[cleanpeg.git] / peg.icl
1 module peg
2
3 import StdEnv
4
5 from Text import class Text, instance Text String
6 import qualified Text
7 from Data.Func import $
8 import Data.Tuple
9 import Data.List
10 import Data.Functor
11 import Data.Monoid
12 import Control.Monad
13 import Control.Monad.RWST
14 import Control.Applicative
15 import Data.Maybe
16 import Data.Functor
17
18 :: Coord :== (Int, Int)
19 :: Position = Inv | Emp | Peg
20 :: PegBoard :== {{Position}}
21 :: Move :== (Coord, Direction)
22 :: Direction = N | E | S | W
23 :: Solver a :== RWST () [PegBoard] PegBoard Maybe a
24
25 european :: PegBoard
26 european =
27 {{Inv, Inv, Peg, Peg, Peg, Inv, Inv}
28 ,{Inv, Inv, Peg, Peg, Peg, Inv, Inv}
29 ,{Peg, Peg, Peg, Peg, Peg, Peg, Peg}
30 ,{Peg, Peg, Peg, Emp, Peg, Peg, Peg}
31 ,{Peg, Peg, Peg, Peg, Peg, Peg, Peg}
32 ,{Inv, Inv, Peg, Peg, Peg, Inv, Inv}
33 ,{Inv, Inv, Peg, Peg, Peg, Inv, Inv}
34 }
35
36 empty = RWST \_ _->Nothing
37 (<|>) (RWST fa) (RWST fb) = RWST \r s->maybe (fb r s) Just (fa r s)
38
39 instance toChar Position where
40 toChar p = case p of Inv = ' '; Emp = '.'; Peg = 'o'
41
42 transform :: Coord Direction -> Coord
43 transform (x, y) d = case d of N = (x, y+1); S = (x, y-1); W = (x+1, y); E = (x-1, y)
44
45 getPos :: Coord -> Solver Position
46 getPos (x, y) = get >>= \b->if (valid b) empty (pure b.[y].[x])
47 where
48 valid b = y<0 || x<0 || y >= size b || x >= size b.[0] || b.[y].[x] =: Inv
49
50 move :: Move -> Solver ()
51 move (tc=:(tx, ty), d)
52 # sc=:(sx, sy) = transform tc d
53 # fc=:(fx, fy) = transform sc d
54 = get >>= \b->liftM3 tuple3 (getPos fc) (getPos sc) (getPos tc) >>= \f->case f of
55 (Peg, Peg, Emp)
56 # b = {{{c\\c<-:r}\\r<-:b} & [fy,fx]=Emp, [sy,sx]=Emp, [ty,tx]=Peg}
57 = tell [b] >>| put b
58 _ = empty
59
60 getCoords :: (Position -> Bool) PegBoard -> [Coord]
61 getCoords f b = [(x, y)\\r<-:b & y<-[0..] , c<-:r & x<-[0..] | f c]
62
63 win :: (PegBoard -> Bool)
64 win = (==) 1 o length o getCoords (\c->c=:Peg)
65
66 printPegBoard :: PegBoard -> String
67 printPegBoard b = 'Text'.join "\n" [{#toChar x\\x<-:r}\\r <-: b]
68
69 moves :: Solver [Move]
70 moves = gets $ \b->[(c,d)\\c<-getCoords (\c->c=:Emp) b, d<-[N,E,S,W]]
71
72 solve :: PegBoard -> Maybe [PegBoard]
73 solve b = snd <$> evalRWST (tell [b] >>| solver) () b
74 where
75 solver = get >>= \board->if (win board)
76 (get >>= tell o pure)
77 (moves >>= foldr (<|>) empty o map (\m->move m >>| solver))
78
79 Start = 'Text'.join "\n" o map printPegBoard <$> solve european