-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathChessBoard.hs
223 lines (194 loc) · 7.31 KB
/
ChessBoard.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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
module ChessBoard (
vHeader,
hHeader,
name,
goldenMosaic,
userMosaic,
initChessBoard,
loadChessBoard,
switchLocation,
newChessBoard,
saveChessBoard,
getMosaicRow,
getMosaicCol,
checkMosaic,
expandChessBoard,
hint,
cleanMosaic) where
import System.IO as S
import System.Random as R
import qualified Data.ByteString as B
import qualified Data.List as L
import Data.Matrix
import CXM
import Status
import Utils
data ChessBoard = ChessBoard {
name :: String,
vHeader :: Matrix Int,
hHeader :: Matrix Int,
goldenMosaic :: Matrix Status,
userMosaic :: Matrix Status
} deriving (Show)
initChessBoard :: ChessBoard
initChessBoard = ChessBoard {
name = "",
vHeader = zero 0 0,
hHeader = zero 0 0,
goldenMosaic = fromList 0 0 [Unknown],
userMosaic = fromList 0 0 [Unknown]
}
newChessBoard :: Int -> Int -> String->ChessBoard
newChessBoard row col na= ChessBoard {
name = na,
vHeader = zero 0 0,
hHeader = zero 0 0,
goldenMosaic = fromList 0 0 [Unknown],
userMosaic = matrix row col (\(_, _) -> Unknown)
}
saveChessBoard :: ChessBoard -> CXM
saveChessBoard cb = CXM {
vAuxRow = (nrows . vHeader) cb,
vAuxCol = (ncols . vHeader) cb,
hAuxRow = (nrows . hHeader) cb,
hAuxCol = (ncols . hHeader) cb,
setFlag = 'S',
unSetFlag = 'R',
cxmName = name cb,
vAuxBytes = (intList2bStr . toList . vHeader) cb,
hAuxBytes = (intList2bStr . toList . hHeader) cb,
bodyBytes = ((statusList2bStr 'S' 'R') . toList . goldenMosaic) cb
}
loadChessBoard :: CXM -> ChessBoard
loadChessBoard cxm = ChessBoard {
name = cxmName cxm,
vHeader = fromList (vAuxRow cxm) (vAuxCol cxm) ((bStr2IntList . vAuxBytes) cxm),
hHeader = fromList (hAuxRow cxm) (hAuxCol cxm) ((bStr2IntList . hAuxBytes) cxm),
goldenMosaic = fromList (vAuxRow cxm) (hAuxCol cxm) status,
userMosaic = matrix (vAuxRow cxm) (hAuxCol cxm) (\(_, _) -> (Unknown::Status))
} where
status = ((bStr2StatusList s u) . bodyBytes) cxm
s = setFlag cxm
u = unSetFlag cxm
loadChessBoard' :: [Int] -> [Int] -> [Status] -> ChessBoard
loadChessBoard' (vr:vc:vs) (hr:hc:hs) ms =
ChessBoard {
name = "",
vHeader = fromList vr vc vs,
hHeader = fromList hr hc hs,
goldenMosaic = fromList vr hc ms,
userMosaic = matrix vr hc (\(_, _) -> (Unknown::Status))
}
hint :: IO ChessBoard -> IO ChessBoard
hint ioCB = do
cb <- ioCB
let m = (nrows . userMosaic) cb
n = (ncols . userMosaic) cb
r <- randomRIO (1, m+n)
case compareLine cb r of
True -> hint ioCB
False -> return (getMosaicLine r cb)
compareLine :: ChessBoard -> Int -> Bool
compareLine c n
| n <= ((nrows . userMosaic) c)= compareRow c n
| otherwise = compareCol c (n - ((nrows . userMosaic) c))
compareRow :: ChessBoard -> Int -> Bool
compareRow c n = (((getRow n) . userMosaic) c) == (((getRow n) . goldenMosaic) c)
compareCol :: ChessBoard -> Int -> Bool
compareCol c n = (((getCol n) . userMosaic) c) == (((getCol n) . goldenMosaic) c)
switchLocation :: Int -> Int -> ChessBoard -> ChessBoard
switchLocation row col d
| not ((isValid) col row d) = d
| otherwise = ChessBoard {
name = name d,
vHeader = vHeader d,
hHeader = hHeader d,
goldenMosaic = goldenMosaic d,
userMosaic = setElem (switch oldVal) (row, col) oldMosaic
} where
oldMosaic = userMosaic d
oldVal = getElem row col $ userMosaic d
getMosaicLine :: Int -> ChessBoard -> ChessBoard
getMosaicLine n c
| n <= ((nrows . userMosaic) c) = getMosaicRow n c
| otherwise = getMosaicCol (n - ((nrows . userMosaic) c)) c
getMosaicCol :: Int -> ChessBoard -> ChessBoard
getMosaicCol col d
| not (isInRange 1 ((ncols . userMosaic) d) col) = d
| otherwise = ChessBoard {
name = name d,
vHeader = vHeader d,
hHeader = hHeader d,
goldenMosaic = goldenMosaic d,
userMosaic = changeRow oldUserMosaic
} where
oldUserMosaic = userMosaic d
changeRow = mapCol goldenCol col
goldenCol = \row _ -> getElem row col $ goldenMosaic d
getMosaicRow :: Int -> ChessBoard -> ChessBoard
getMosaicRow row d
| not (isInRange 1 ((nrows . userMosaic) d) row) = d
| otherwise = ChessBoard {
name = name d,
vHeader = vHeader d,
hHeader = hHeader d,
goldenMosaic = goldenMosaic d,
userMosaic = changeRow oldUserMosaic
} where
oldUserMosaic = userMosaic d
changeRow = mapRow goldenRow row
goldenRow = \col _ -> getElem row col $ goldenMosaic d
checkMosaic :: ChessBoard -> Bool
checkMosaic d = goldenMosaic d == (userMosaic d)
cleanMosaic :: ChessBoard -> ChessBoard
cleanMosaic d = ChessBoard {
name = name d,
vHeader = vHeader d,
hHeader = hHeader d,
goldenMosaic = goldenMosaic d,
userMosaic = newUserMosaic
} where
newUserMosaic = matrix row col (\(_, _) -> Unknown)
row = nrows $ goldenMosaic d
col = ncols $ goldenMosaic d
-------------Toolkit functions----------------
--This function expand a partial chess board to a entire one
--partial chess board must have a name and a userMosaic
--and this function will rebuild the headers according to the userMosaic
expandChessBoard :: ChessBoard -> ChessBoard
expandChessBoard raw = ChessBoard {
name = name raw,
vHeader = summaryMtrix (userMosaic raw),
hHeader = (transpose . summaryMtrix) ((transpose . userMosaic) raw),
goldenMosaic = userMosaic raw,
userMosaic = matrix row col (\(_, _) -> Unknown)
} where
row = (nrows . userMosaic) raw
col = (ncols . userMosaic) raw
summary :: [Status] -> [Int]
summary l = map length $ filter ((== Set) . head) $ L.group l
allignSummary :: Int -> [Int] -> [Int]
allignSummary len l
| length l == len = l
| otherwise = (replicate (len - (length l)) 0) ++ l
summaryMtrix :: Matrix Status -> Matrix Int
summaryMtrix m = fromLists (map (allignSummary maxL) s) where
s = map summary $ toLists m
maxL = maximum (map length s)
isInRange :: Int -> Int -> Int -> Bool
isInRange start end pos = pos `elem` [start .. end]
isValid :: Int -> Int ->ChessBoard -> Bool
isValid x y c = (isInRange 1 colNum x) && (isInRange 1 rowNum y)
where
colNum = (ncols . userMosaic) c
rowNum = (nrows . userMosaic) c
-----------------test of load-------------------------
testOfLoad = do
inh <- S.openBinaryFile "u.cxm" ReadMode
instr <- B.hGetContents inh
hClose inh
case parse parseCMX instr of
Right c -> return (Just( loadChessBoard c))
Left err -> do
S.putStrLn err
return (Nothing)