-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmoves.hs
291 lines (222 loc) · 11.7 KB
/
moves.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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
module Moves where
import Board
import Data.Bits
import Data.Function
import Data.List
import Data.Word
import Masks
----------- PUBLIC METHODS ------------
getActions :: Board -> Player -> [MoveHolder]
getActions board player = if not . null $ jumps' then jumps' else moves'
where
moves' = map NormalMove $ getMoves board player
jumps' = map JumpMove . filterJumps $ getJumps board player
filterJumps :: MovesList -> MovesList -- remove short jumps
filterJumps jumps
| null jumps = []
| otherwise = result
where
max' = length . maximumBy (compare `on` length) $ jumps
result = filter (\x -> length x == max') jumps
getMoves :: Board -> Player -> MovesList
getMoves board player
| player == White = getWhiteMovesList board
| otherwise = getBlackMovesList board
getJumps :: Board -> Player -> MovesList
getJumps board player
| player == White = getWhiteJumpsList board
| otherwise = getBlackJumpsList board
-- METHODS --
getWhiteMovesList :: Board -> MovesList -- return list of moves
getWhiteMovesList board =
let
movers = getWhiteMovers board
moveList = getWhiteMoveListRecur board movers
in moveList
getWhiteJumpsList :: Board -> MovesList
getWhiteJumpsList board =
let
jumpers = getWhiteJumpers board
jumpList = getJumpsListRecur board (empty board) jumpers (bp board)
in jumpList
getBlackMovesList :: Board -> MovesList -- return list of moves
getBlackMovesList board =
let
movers = getBlackMovers board
moveList = getBlackMoveListRecur board movers
in moveList
getBlackJumpsList :: Board -> MovesList
getBlackJumpsList board =
let
jumpers = getBlackJumpers board
jumpList = getJumpsListRecur board (empty board) jumpers (wp board)
in jumpList
---------- JUMP AND MOVE DETECTION ------------
getBlackMovers :: Board -> Word64 -- return pieces that can move
getBlackMovers board =
let
blackLeft = upRight (empty board) .&. bp board
blackRight = upLeft (empty board) .&. bp board
kingsMoves = (downRight (empty board) .&. blackKings board) .|. (downLeft (empty board) .&. blackKings board)
in blackLeft .|. blackRight .|. kingsMoves
getBlackJumpers :: Board -> Word64 -- return pieces that can jump
getBlackJumpers board = getJumpersKings (empty board) (blackKings board) (wp board) .|. getJumpersPieces (empty board) (bp board) (wp board)
getWhiteMovers :: Board -> Word64 -- return pieces that can move
getWhiteMovers board =
let
whiteLeft = downRight (empty board) .&. wp board
whiteRight = downLeft (empty board) .&. wp board
kingsMoves = (upRight (empty board) .&. whiteKings board) .|. (upLeft (empty board) .&. whiteKings board)
in whiteLeft .|. whiteRight .|. kingsMoves
getWhiteJumpers :: Board -> Word64 -- return pieces that can jump
getWhiteJumpers board = getJumpersKings (empty board) (whiteKings board) (bp board) .|. getJumpersPieces (empty board) (wp board) (bp board)
getJumpersPieces :: Word64 -> Word64 -> Word64 -> Word64 -- return pieces that can jump
getJumpersPieces empt me opponent =
let
leftUp = downRight (downRight empt .&. opponent) .&. me
rightUp = downLeft (downLeft empt .&. opponent) .&. me
leftDown = upRight (upRight empt .&. opponent) .&. me
rightDown = upLeft (upLeft empt .&. opponent).&. me
in leftUp .|. rightUp .|. leftDown .|. rightDown
getJumpersKings :: Word64 -> Word64 -> Word64 -> Word64 -- return kings that can jump
getJumpersKings empt me opponent =
let
enemyUpLeft = upLeft empt .&. opponent
enemyUpRight = upRight empt .&. opponent
enemyDownRight = downRight empt .&. opponent
enemyDownLeft = downLeft empt .&. opponent
in if me == 0 then 0 else getJumpersKingsRecur empt enemyUpLeft enemyUpRight enemyDownLeft enemyDownRight me 0
getJumpersKingsRecur :: Word64 -> Word64 -> Word64 -> Word64 -> Word64 -> Word64 -> Word64 -> Word64
getJumpersKingsRecur empt enemyUpLeft enemyUpRight enemyDownLeft enemyDownRight kings result
| (enemyUpLeft .|. enemyUpRight .|. enemyDownLeft .|. enemyDownRight) == 0 = result -- no moves possible
| otherwise = getJumpersKingsRecur empt newEnemyUpLeft newEnemyUpRight newEnemyDownLeft newEnemyDownRight kings (matchedKings .|. result)
where
enemyUpRight' = upRight enemyUpRight
enemyUpLeft' = upLeft enemyUpLeft
enemyDownLeft' = downLeft enemyDownLeft
enemyDownRight' = downRight enemyDownRight
matchedKings = kings .&. (enemyUpRight' .|. enemyUpLeft' .|. enemyDownLeft' .|. enemyDownRight') -- kings that can jump
newEnemyUpRight = enemyUpRight' .&. empt
newEnemyUpLeft = enemyUpLeft' .&. empt
newEnemyDownRight = enemyDownRight' .&. empt
newEnemyDownLeft = enemyDownLeft' .&. empt
----------- MOVES PIECES -------------
getBlackMoveListRecur :: Board -> Word64 -> MovesList
getBlackMoveListRecur board movers
| movers /= 0 = movesList ++ getBlackMoveListRecur board movers'
| otherwise = []
where
pieceIndex = s $ getIndex movers
movers' = movers `xor` pieceIndex
movesList = if isKing board pieceIndex then getMovesListKings (empty board) pieceIndex pieceIndex pieceIndex pieceIndex pieceIndex else getBlackMovesListPieces board pieceIndex
getBlackMovesListPieces :: Board -> Word64 -> MovesList
getBlackMovesListPieces board index =
let
leftDown = downLeft index .&. empty board
rightDown = downRight index .&. empty board
result = [[index, downLeft index] | leftDown /= 0]
result' = if rightDown /= 0 then [index, downRight index]:result else result
in result'
getWhiteMoveListRecur :: Board -> Word64 -> MovesList
getWhiteMoveListRecur board movers
| movers /= 0 = movesList ++ getWhiteMoveListRecur board movers'
| otherwise = []
where
pieceIndex = s $ getIndex movers
movers' = movers `xor` pieceIndex
movesList = if isKing board pieceIndex then getMovesListKings (empty board) pieceIndex pieceIndex pieceIndex pieceIndex pieceIndex else getWhiteMovesListPieces board pieceIndex
getWhiteMovesListPieces :: Board -> Word64 -> MovesList
getWhiteMovesListPieces board index =
let
leftUp = upLeft index .&. empty board
rightUp = upRight index .&. empty board
result = [[index, upLeft index] | leftUp /= 0]
result' = if rightUp /= 0 then [index, upRight index]:result else result
in result'
--------------- MOVES KINGS ---------------
getMovesListKings :: Word64 -> Word64 -> Word64 -> Word64 -> Word64 -> Word64 -> MovesList
getMovesListKings empt source leftUp rightUp leftDown rightDown
| (leftUp .|. rightUp .|. leftDown .|. rightDown) == 0 = result4
| otherwise = result4 ++ getMovesListKings empt source leftUp' rightUp' leftDown' rightDown'
where
leftUp' = upLeft leftUp .&. empt
rightUp' = upRight rightUp .&. empt
leftDown' = downLeft leftDown .&. empt
rightDown' = downRight rightDown .&. empt
result1 = [[source, leftUp'] | leftUp' /= 0]
result2 = if rightUp' /= 0 then [source, rightUp']:result1 else result1
result3 = if leftDown'/= 0 then [source, leftDown']:result2 else result2
result4 = if rightDown' /= 0 then [source, rightDown']:result3 else result3
---------- JUMPS ------------
getJumpsListRecur :: Board -> Word64 -> Word64 -> Word64 -> MovesList
getJumpsListRecur board empt jumpers opponent
| jumpers /= 0 = jumpList ++ getJumpsListRecur board empt jumpers' opponent
| otherwise = []
where
pieceIndex = s $ getIndex jumpers
jumpers' = jumpers `xor` pieceIndex
jumpList = if isKing board pieceIndex
then getJumpsListKings empt opponent pieceIndex
else getJumpsListPieces empt opponent pieceIndex
----------- JUMPS PIECES -------------
getJumpsListPieces :: Word64 -> Word64 -> Word64 -> [[Word64]] -- return list of pieces that can jump
getJumpsListPieces empt opponent piece =
let
leftUp = upLeft (upLeft piece .&. opponent) .&. empt
rightUp = upRight (upRight piece .&. opponent) .&. empt
rightDown = downRight (downRight piece .&. opponent) .&. empt
leftDown = downLeft (downLeft piece .&. opponent) .&. empt
newEmpty = empt .|. piece
leftUpNewOpponent = removePieceByIndex opponent (downRight leftUp)
rightUpNewOpponent = removePieceByIndex opponent (downLeft rightUp)
rightDownNewOpponent = removePieceByIndex opponent (upLeft rightDown)
leftDownNewOpponent = removePieceByIndex opponent (upRight leftDown)
recurLeftUp = if leftUp == 0 then [] else getJumpsListPieces newEmpty leftUpNewOpponent leftUp
recurRightUp = if rightUp == 0 then [] else getJumpsListPieces newEmpty rightUpNewOpponent rightUp
recurRightDown = if rightDown == 0 then [] else getJumpsListPieces newEmpty rightDownNewOpponent rightDown
recurLeftDown = if leftDown == 0 then [] else getJumpsListPieces newEmpty leftDownNewOpponent leftDown
recurLeftUp' = if leftUp /= 0 && null recurLeftUp then [[piece, leftUp]] else map (piece:) recurLeftUp
recurRightUp' = if rightUp /= 0 && null recurRightUp then [[piece, rightUp]] else map (piece:) recurRightUp
recurRightDown' = if rightDown /= 0 && null recurRightDown then [[piece, rightDown]] else map (piece:) recurRightDown
recurLeftDown' = if leftDown /= 0 && null recurLeftDown then [[piece, leftDown]] else map (piece:) recurLeftDown
in
if leftUp == 0 && rightUp == 0 && rightDown == 0 && leftDown == 0 then []
else recurLeftUp' ++ recurRightUp' ++ recurRightDown' ++ recurLeftDown'
getJumpsListKings :: Word64 -> Word64 -> Word64 -> MovesList -- return list of kings that can jump
getJumpsListKings empt opponent piece =
let
leftUp = moveUntilOpponent piece empt opponent upLeft
rightUp = moveUntilOpponent piece empt opponent upRight
rightDown = moveUntilOpponent piece empt opponent downRight
leftDown = moveUntilOpponent piece empt opponent downLeft
newEmpty = empt .|. piece
leftUpNewBlack = if null leftUp then 0 else (downRight . head $ leftUp) `xor` opponent
rightUpNewBlack = if null rightUp then 0 else (downLeft . head $ rightUp) `xor` opponent
rightDownNewBlack = if null rightDown then 0 else (upLeft . head $ rightDown) `xor` opponent
leftDownNewBlack = if null leftDown then 0 else (upRight . head $ leftDown) `xor` opponent
recurLeftUp = concatMap (getJumpsListKings newEmpty leftUpNewBlack) leftUp
recurRightUp = concatMap (getJumpsListKings newEmpty rightUpNewBlack) rightUp
recurRightDown = concatMap (getJumpsListKings newEmpty rightDownNewBlack) rightDown
recurLeftDown = concatMap (getJumpsListKings newEmpty leftDownNewBlack) leftDown
f x = [piece, x]
recurLeftUp' = if null recurLeftUp then map f leftUp else map (piece:) recurLeftUp
recurRightUp' = if null recurRightUp then map f rightUp else map (piece:) recurRightUp
recurRightDown' = if null recurRightDown then map f rightDown else map (piece:) recurRightDown
recurLeftDown' = if null recurLeftDown then map f leftDown else map (piece:) recurLeftDown
result = recurLeftUp' ++ recurRightUp' ++ recurRightDown' ++ recurLeftDown'
in result
getAllFreeSquares :: Word64 -> Word64 -> (Word64 -> Word64) -> [Word64]
getAllFreeSquares piece empt moveFunction
| nextEmptySquare == 0 = [piece]
| otherwise = piece:getAllFreeSquares nextEmptySquare empt moveFunction
where
nextEmptySquare = moveFunction piece .&. empt
moveUntilOpponent :: Word64 -> Word64 -> Word64 -> (Word64 -> Word64) -> [Word64]
moveUntilOpponent piece empt opponent moveFunction
-- we have a jump? return all possible endings for this jump
| isNextMoveAJump /= 0 = getAllFreeSquares isNextMoveAJump empt moveFunction
-- if we don't have a jump, can we move a to the next square?
| otherwise = if nextSquare /= 0 then moveUntilOpponent nextSquare empt opponent moveFunction else []
where
isNextMoveAJump = moveFunction (moveFunction piece .&. opponent) .&. empt
nextSquare = moveFunction piece .&. empt