forked from hemigloben/Glitter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPolyomino.hs
118 lines (93 loc) · 3.06 KB
/
Polyomino.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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
{-
author: Jackson C. Wiebe
date: March 1 2018
-}
module Polyomino
( Polyomino (Polyomino, token, parts, width, Empty)
, createPolyomino
, flipxy
, flipv
, move
, move'
, orientations
) where
import Types
import Data.List
import Debug.Trace
data Polyomino = Empty | Polyomino { parts::[Location]
, width::Int
, height::Int
, token::Token
}
deriving (Eq, Ord)
createPolyomino :: [Location] -> Token -> Polyomino
createPolyomino xs token =
let points = unzip xs;
width = (maximum $ fst points) + 1;
height = (maximum $ snd points) + 1 in
Polyomino xs width height token
flipxy :: Polyomino -> Polyomino
flipxy p@(Polyomino{ parts=(ps), width=w, height=h }) =
p{ parts=sort $ flip' ps, width=h, height=w }
where flip' :: [Location] -> [Location]
flip' ((a,b):xs) = (b,a):flip' xs
flip' [] = []
flipv :: Polyomino -> Polyomino
flipv p@(Polyomino{ parts=ps, width=w }) =
p{ parts = sort $ map (flip flipv' w) ps }
where flipv' :: Location -> Width -> Location
flipv' (x,y) w = ((w - 1 - x),y)
orientations :: Polyomino -> [Polyomino]
orientations p =
let p' = flipv p;
a = rotate p;
b = rotate a;
c = rotate b;
a' = flipv a;
b' = flipv b;
c' = flipv c in
nub [p,a,b,c,p',a',b',c']
where
rotate = flipv . flipxy
-- Translate the polyomino to given location
move :: Polyomino -> Location -> Polyomino
move p@(Polyomino{ parts=xs }) loc =
p { parts = map (add loc) xs }
where
add :: Location -> Location -> Location
add (a,b) (c,d) = (a + c, b + d)
move' :: Polyomino -> Location -> [Polyomino]
move' p@(Polyomino{ parts=xs, token=t }) loc = do
let parts = map (add loc) xs
let pivots = map (sub parts) parts
map (flip createPolyomino t) pivots
where
add :: Location -> Location -> Location
add (a,b) (c,d) = (a + c, b + d)
sub :: [Location] -> Location -> [Location]
sub xs' o = map (sub' o) xs
sub' :: Location -> Location -> Location
sub' (a,b) (c,d) = (a-c, b-d)
instance Show Polyomino where
show (Polyomino{parts=ps, token=t, width=w, height=h}) =
let m = ["\n"] in
concat $
"\n" : (intercalate m $ splitEvery w $ setTokens [] t (sort ps) w)
where
setTokens :: [Token] -> Token -> [Location] -> Int -> [Token]
setTokens vs a ((x,y):xs) w = do
let vs' = setAt (x + y * w) a " " vs
setTokens vs' a xs w
setTokens vs _ [] _ = vs
splitEvery :: Int -> [Token] -> [[Token]]
splitEvery _ [] = []
splitEvery n list =
let (first,rest) = splitAt n list in
first : (splitEvery n rest)
setAt :: Int -> Token -> Token -> [Token] ->[Token]
setAt 0 a _ (_:xs) = a : xs
setAt 0 a b [] = [a]
setAt i a b (x:xs) | i > 0 = x : setAt (i-1) a b xs
| otherwise = []
setAt i a b [] | i > 0 = b : setAt (i-1) a b []
| otherwise = []