4
4
{-# LANGUAGE DeriveDataTypeable #-}
5
5
{-# LANGUAGE TemplateHaskell #-}
6
6
{-# LANGUAGE FlexibleInstances #-}
7
+
8
+ {-
9
+ - This module contains an implementation of alpha-beta-pruning algorithm
10
+ - with small improvements.
11
+ -}
12
+
7
13
module AI.AlphaBeta where
8
14
9
15
import Control.Monad
@@ -101,6 +107,7 @@ putMoves First board moves memo =
101
107
putMoves Second board moves memo =
102
108
memo {mmSecond = putBoardMap board moves (mmSecond memo)}
103
109
110
+ -- | Calculate score of the board
104
111
doScore :: (GameRules rules , Evaluator eval ) => rules -> eval -> AICacheHandle rules -> AlphaBetaParams -> Side -> DepthParams -> Board -> Checkers Score
105
112
doScore rules eval var params side dp board =
106
113
fixSign <$> evalStateT (cachedScoreAB var params side dp (- max_score) max_score board) initState
@@ -150,13 +157,15 @@ instance HasLogContext (StateT (ScoreState rules eval) Checkers) where
150
157
put st'
151
158
return result
152
159
160
+ -- | Calculate score of the board.
161
+ -- This uses the cache. It is called in the recursive call also.
153
162
cachedScoreAB :: forall rules eval . (GameRules rules , Evaluator eval )
154
163
=> AICacheHandle rules
155
164
-> AlphaBetaParams
156
165
-> Side
157
166
-> DepthParams
158
- -> Score
159
- -> Score
167
+ -> Score -- ^ Alpha
168
+ -> Score -- ^ Beta
160
169
-> Board
161
170
-> ScoreM rules eval Score
162
171
cachedScoreAB var params side dp alpha beta board = do
@@ -179,6 +188,12 @@ cachedScoreAB var params side dp alpha beta board = do
179
188
isTargetDepth :: DepthParams -> Bool
180
189
isTargetDepth dp = dpCurrent dp >= dpTarget dp
181
190
191
+ -- | Increase current depth as necessary.
192
+ -- If there is only 1 move currently possible, this can increase
193
+ -- the target depth, up to dpMax.
194
+ -- If there are a lot of moves possible, this can decrease the
195
+ -- target depth, down to dpMin.
196
+ -- Otherwise, this just increases dpCurrent by 1.
182
197
updateDepth :: (Monad m , HasLogging m , MonadIO m ) => Int -> DepthParams -> m DepthParams
183
198
updateDepth nMoves dp
184
199
| nMoves == 1 = do
@@ -195,17 +210,19 @@ updateDepth nMoves dp
195
210
return $ dp {dpCurrent = dpCurrent dp + 1 , dpTarget = target}
196
211
| otherwise = return $ dp {dpCurrent = dpCurrent dp + 1 }
197
212
213
+ -- | Calculate score for the board
198
214
scoreAB :: forall rules eval . (GameRules rules , Evaluator eval )
199
215
=> AICacheHandle rules
200
216
-> AlphaBetaParams
201
217
-> Side
202
218
-> DepthParams
203
- -> Score
204
- -> Score
219
+ -> Score -- ^ Alpha
220
+ -> Score -- ^ Beta
205
221
-> Board
206
222
-> ScoreM rules eval (Score , [Move ])
207
223
scoreAB var params side dp alpha beta board
208
224
| isTargetDepth dp = do
225
+ -- target depth is achieved, calculate score of current board directly
209
226
evaluator <- gets ssEvaluator
210
227
let score0 = evalBoard evaluator First side board
211
228
$ trace " X Side: {}, A = {}, B = {}, score0 = {}" (show side, alpha, beta, score0)
@@ -216,6 +233,7 @@ scoreAB var params side dp alpha beta board
216
233
$ trace " {}V Side: {}, A = {}, B = {}" (indent, show side, alpha, beta)
217
234
moves <- possibleMoves' board
218
235
236
+ -- this actually means that corresponding side lost.
219
237
when (null moves) $
220
238
$ trace " {}| No moves left." (Single indent)
221
239
0 commit comments