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 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
| #coding=utf-8
#Author: Yan
#Date: 2012/4/18
MAX_LINE = 15
EMPTY = '0'
MYSELF = '1'
RIVAL = '2'
INIT_MAX = 2147483647
#棋型
FIVE = 1
FOUR = 2
SLEEP_FOUR = 3
THREE = 4
SLEEP_THREE = 5
TWO = 6
SLEEP_TWO = 7
UNANALYSED = 0
ANALYSED = 10
WIN = 1
LOSE = -1
TIE = 0
#越往中心估值越大
NODE_VALUE = \
[ \
[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ,\
[ 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 ] ,\
[ 0 , 1 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 1 , 0 ] ,\
[ 0 , 1 , 2 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 2 , 1 , 0 ] ,\
[ 0 , 1 , 2 , 3 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 3 , 2 , 1 , 0 ] ,\
[ 0 , 1 , 2 , 3 , 4 , 5 , 5 , 5 , 5 , 5 , 4 , 3 , 2 , 1 , 0 ] ,\
[ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 6 , 6 , 5 , 4 , 3 , 2 , 1 , 0 ] ,\
[ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 6 , 5 , 4 , 3 , 2 , 1 , 0 ] ,\
[ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 6 , 6 , 5 , 4 , 3 , 2 , 1 , 0 ] ,\
[ 0 , 1 , 2 , 3 , 4 , 5 , 5 , 5 , 5 , 5 , 4 , 3 , 2 , 1 , 0 ] ,\
[ 0 , 1 , 2 , 3 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 3 , 2 , 1 , 0 ] ,\
[ 0 , 1 , 2 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 2 , 1 , 0 ] ,\
[ 0 , 1 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 1 , 0 ] ,\
[ 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 ] ,\
[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] \
]
#对每一种状态所对应的分数
STATE_SCORE = [ 0 , 100000 , 10000 , 5000 , 3000 , 500 , 100 , 50 ]
#记录走的一步
class Node( object ):
def __init__( self ):
self.x = -1
self.y = -1
self.value = 0
self.win = TIE
#评估值类
class Evaluate( object ):
def __init__( self ):
self.numOfState = [ [ 0 for i in range( 0 , 8 ) ] for j in range( 0 , 2 ) ]
def analyseLine( self , player , line ):
enemy = RIVAL if player == MYSELF else MYSELF
current_player = int( player ) - 1
line_size = len( line )
nodeStates = [ UNANALYSED for i in range( 0 , MAX_LINE ) ]
leftEdge = -1
rightEdge = -1
for i in range( 0 , line_size ):
if line[ i ] == player and nodeStates[ i ] == UNANALYSED:
leftEdge = rightEdge = i
#向左搜索
while( leftEdge >= 0 ):
if line[ leftEdge ] != player:
break
leftEdge -= 1
#向右搜索
while( rightEdge < line_size ):
if line[ rightEdge ] != player:
break
rightEdge += 1
leftEdge += 1
rightEdge -= 1
for index in range( leftEdge , rightEdge + 1 , 1 ):
nodeStates[ index ] = ANALYSED
if leftEdge == rightEdge:
nodeStates[ leftEdge ] = UNANALYSED
#如果是5连 xxxxx
if rightEdge - leftEdge > 3:
self.numOfState[ current_player ][ FIVE ] += 1
#如果是4连
elif rightEdge - leftEdge == 3:
#如果是活四
if ( leftEdge > 0 and rightEdge < line_size - 1 and line[ leftEdge - 1 ] == EMPTY and line[ rightEdge + 1 ] == EMPTY ):
self.numOfState[ current_player ][ FOUR ] += 1
#如果是冲四,则有且仅有一侧空,另一侧或者为边界或者为敌方棋子 _xxxxo或者oxxxx_
elif ( ( ( leftEdge == 0 or (leftEdge > 0 and line[ leftEdge - 1 ] == enemy ) ) and (rightEdge < line_size - 1 and line[ rightEdge + 1 ] == EMPTY) ) or ( (rightEdge == line_size - 1 or ( rightEdge < line_size - 1 and line[ rightEdge + 1 ] == enemy )) and ( leftEdge > 0 and line[ leftEdge - 1 ] == EMPTY) ) ):
self.numOfState[ current_player ][ SLEEP_FOUR ] += 1
#如果是3连
elif rightEdge - leftEdge == 2:
#如果是冲四 xxx_x或x_xxx
if ( (leftEdge > 1 and line[ leftEdge - 2 ] == player and nodeStates[ leftEdge - 2 ] == UNANALYSED and line[ leftEdge - 1 ] == EMPTY) or (rightEdge < line_size - 2 and line[ rightEdge + 1 ] == EMPTY and line[ rightEdge + 2 ] == player and nodeStates[ rightEdge + 2 ] == UNANALYSED ) ):
self.numOfState[ current_player ][ SLEEP_FOUR ] += 1
#如果是活三 _xxx__或__xxx_
elif ( leftEdge > 0 and rightEdge < line_size - 1 and line[ leftEdge - 1 ] == EMPTY and line[ rightEdge + 1 ] == EMPTY and ( (leftEdge > 1 and line[ leftEdge - 2 ] == EMPTY) or ( rightEdge < line_size - 2 and line[ rightEdge + 2 ] == EMPTY ) ) ):
self.numOfState[ current_player ][ THREE ] += 1
#如果是眠三
else:
#第一种形式 oxxx__或__xxxo
if( ((leftEdge == 0 or (leftEdge > 0 and line[ leftEdge - 1 ] == enemy)) and ( rightEdge < line_size - 2 and line[ rightEdge + 1 ] == EMPTY and line[ rightEdge + 2 ] == EMPTY )) or ( (leftEdge > 1 and line[ leftEdge - 1 ] == EMPTY and line[ leftEdge - 2 ] == EMPTY) and (rightEdge == line_size - 1 or (rightEdge < line_size - 1 and line[ rightEdge + 1 ] == enemy ) ) ) ):
self.numOfState[ current_player ][ SLEEP_THREE ] += 1
#第二种形式o_xxx_o
elif ( leftEdge > 0 and line[ leftEdge - 1 ] == EMPTY and rightEdge < line_size - 1 and line[ rightEdge + 1 ] == EMPTY and ( leftEdge == 1 or (leftEdge > 1 and line[ leftEdge - 2 ] == enemy)) and ( rightEdge == line_size - 2 or ( rightEdge < line_size - 2 and line[ rightEdge + 2 ] == enemy ))):
self.numOfState[ current_player ][ SLEEP_THREE ] += 1
#如果是2连
elif rightEdge - leftEdge == 1:
#冲四 oxx_xx或xx_xxo
if ( ((leftEdge == 0 or (leftEdge > 0 and line[ leftEdge - 1 ] == enemy )) and ( rightEdge < line_size - 3 and line[ rightEdge + 1 ] == EMPTY and line[ rightEdge + 2 ] == player and nodeStates[ rightEdge + 2 ] == UNANALYSED and line[ rightEdge + 3 ] == player and nodeStates[ rightEdge + 3 ] == UNANALYSED )) or ( (rightEdge == line_size - 1 or (rightEdge < line_size - 1 and line[ rightEdge + 1 ] == enemy )) and leftEdge > 2 and line[ leftEdge - 1 ] == EMPTY and line[ leftEdge - 2 ] == player and nodeStates[ leftEdge - 2 ] == UNANALYSED and line[ leftEdge - 3 ] == player and nodeStates[ leftEdge - 3 ] == UNANALYSED ) ):
self.numOfState[ current_player ][ SLEEP_FOUR ] += 1
#如果是跳活三 _xx_x_或_x_xx_
elif ( leftEdge > 0 and line[ leftEdge - 1 ] == EMPTY and rightEdge < line_size - 1 and line[ rightEdge + 1 ] == EMPTY and ( (rightEdge < line_size - 3 and line[ rightEdge + 2 ] == player and nodeStates[ rightEdge + 2 ] == UNANALYSED and line[ rightEdge + 3 ] == EMPTY ) or ( leftEdge > 2 and line[ leftEdge - 2 ] == player and nodeStates[ leftEdge - 2 ] == UNANALYSED and line[ leftEdge - 3 ] == EMPTY ) )):
self.numOfState[ current_player ][ THREE ] += 1
#如果是眠三 oxx_x_或_x_xxo
elif ( ( (leftEdge == 0 or (leftEdge > 0 and line[ leftEdge - 1 ] == enemy )) and rightEdge < line_size - 3 and line[ rightEdge + 1 ] == EMPTY and line[ rightEdge + 2 ] == player and nodeStates[ rightEdge + 2 ] == UNANALYSED and line[ rightEdge + 3 ] == EMPTY) or ( ( rightEdge == line_size - 1 or ( rightEdge < line_size - 1 and line[ rightEdge + 1 ] == enemy )) and leftEdge > 2 and line[ leftEdge - 1 ] == EMPTY and line[ leftEdge - 2 ] == player and nodeStates[ leftEdge - 2 ] == UNANALYSED and line[ leftEdge - 3 ] == EMPTY ) ):
self.numOfState[ current_player ][ SLEEP_THREE ] += 1
#如果是眠三 oxx__x或x__xxo
elif ( ( (leftEdge == 0 or (leftEdge > 0 and line[ leftEdge - 1 ] == enemy )) and rightEdge < line_size - 3 and line[ rightEdge + 1 ] == EMPTY and line[ rightEdge + 2 ] == EMPTY and line[ rightEdge + 3 ] == player and nodeStates[ rightEdge + 3 ] == UNANALYSED ) or ( ( rightEdge == line_size - 1 or ( rightEdge < line_size - 1 and line[ rightEdge + 1 ] == enemy )) and leftEdge > 2 and line[ leftEdge - 1 ] == EMPTY and line[ leftEdge - 2 ] == EMPTY and line[ leftEdge - 3 ] == player and nodeStates[ leftEdge - 3 ] == UNANALYSED ) ) :
self.numOfState[ current_player ][ SLEEP_THREE ] += 1
#如果是眠三 ox__xx或xx__xo
elif ( (leftEdge > 2 and line[ leftEdge - 1 ] == EMPTY and line[ leftEdge - 2 ] == EMPTY and line[ leftEdge - 3 ] == player and ( leftEdge == 3 or ( leftEdge > 3 and line[ leftEdge - 4 ] == enemy )) ) or (rightEdge < line_size - 3 and line[ rightEdge + 1 ] == EMPTY and line[ rightEdge + 2 ] == EMPTY and line[ rightEdge + 3 ] == player and ( rightEdge == line_size - 4 or ( rightEdge < line_size - 4 and line[ rightEdge + 4 ] == enemy )))):
self.numOfState[ current_player ][ SLEEP_THREE ] += 1
#如果是活二 __xx__
elif ( leftEdge > 1 and rightEdge < line_size - 2 and line[ leftEdge - 1 ] == EMPTY and line[ leftEdge - 2 ] == EMPTY and line[ rightEdge + 1 ] == EMPTY and line[ rightEdge + 2 ] == EMPTY ):
self.numOfState[ current_player ][ TWO ] += 1
#如果是眠二 oxx___或___xxo
elif ( ( (leftEdge == 0 or (leftEdge > 0 and line[ leftEdge - 1 ] == enemy ) ) and rightEdge < line_size - 3 and line[ rightEdge + 1 ] == EMPTY and line[ rightEdge + 2 ] == EMPTY and line[ rightEdge + 3 ] == EMPTY ) or ( ( rightEdge == line_size - 1 or ( rightEdge < line_size - 1 and line[ rightEdge + 1 ] == enemy )) and leftEdge > 2 and line[ leftEdge - 1 ] == EMPTY and line[ leftEdge - 2 ] == EMPTY and line[ leftEdge - 3 ] == EMPTY)):
self.numOfState[ current_player ][ SLEEP_TWO ] += 1
def findStateNum( self , board ):
#水平和垂直方向搜索
for i in range( 0 , MAX_LINE ):
src_row = src_col = ''
for j in range( 0 , MAX_LINE ):
src_row += board[ i ][ j ]
src_col += board[ j ][ i ]
self.analyseLine( MYSELF , src_row )
self.analyseLine( MYSELF , src_col )
self.analyseLine( RIVAL , src_row )
self.analyseLine( RIVAL , src_col )
#左下-右上搜索
for sum in range( 4 , 25 , 1 ):
src = ''
i = sum if sum < = 14 else 14
j = sum - i
while( i >= 0 and j < = 14 ):
src += board[ i ][ j ]
i -= 1
j += 1
self.analyseLine( RIVAL , src )
self.analyseLine( MYSELF , src )
#左上-右下搜索
for sub in range( 10 , -11 , -1 ):
src = ''
i = sub if sub >= 0 else 0
j = i - sub
while( i < = 14 and j <= 14 ):
src += board[ i ][ j ]
i += 1
j += 1
self.analyseLine( MYSELF , src )
self.analyseLine( RIVAL , src )
#估值函数
def getValue( self , player , board ):
tmpNode = Node()
my_score = rival_score = 0
self.numOfState = [ [ 0 for i in range( 0 , 8 ) ] for j in range( 0 , 2 ) ]
self.findStateNum( board )
for i in range( 8 ):
tmp = self.numOfState[ 0 ][ i ] * STATE_SCORE[ i ]
my_score += self.numOfState[ 0 ][ i ] * STATE_SCORE[ i ]
rival_score += self.numOfState[ 1 ][ i ] * STATE_SCORE[ i ]
current_player = int( player ) - 1
other_player = 1 - current_player
if self.numOfState[ other_player ][ FIVE ] != 0:
tmpNode.value = -200000
tmpNode.win = LOSE
return tmpNode
elif self.numOfState[ current_player ][ FIVE ] != 0:
tmpNode.value = 200000
tmpNode.win = WIN
return tmpNode
elif self.numOfState[ other_player ][ FOUR ] != 0 or self.numOfState[ other_player ][ SLEEP_FOUR ] != 0:
tmpNode.value = -180000
tmpNode.win = LOSE
return tmpNode
elif self.numOfState[ current_player ][ FOUR ] != 0:
tmpNode.value = 180000
tmpNode.win = WIN
return tmpNode
elif ( self.numOfState[ current_player ][ SLEEP_FOUR ] + self.numOfState[ current_player ][ THREE ] > 1 ) and ( self.numOfState[ other_player ][ THREE ] == 0 ) and ( self.numOfState[ other_player ][ FOUR ] == 0 ) and ( self.numOfState[ other_player ][ SLEEP_FOUR ] == 0 ):
tmpNode.value = 100000
tmpNode.win = WIN
return tmpNode
for i in range( 0 , MAX_LINE ):
for j in range( 0 , MAX_LINE ):
if board[ i ][ j ] == MYSELF:
my_score += NODE_VALUE[ i ][ j ]
elif board[ i ][ j ] == RIVAL:
rival_score += NODE_VALUE[ i ][ j ]
tmpNode.value = ( my_score - rival_score ) if player == MYSELF else ( rival_score - my_score )
return tmpNode
#主要类
class Search( object ):
#depth:搜索深度 numofgoodnodes:搜索广度
def __init__( self , depth , numOfGoodNodes , chessBoard ):
self.depth = depth
self.numOfGoodNodes = numOfGoodNodes
self.chessBoard = chessBoard
self.bestMove = Node()
self.evaluate = Evaluate()
#找到几步比较好的走步
def search_several_good_nodes( self , player , board , numGoodNodes ):
#记录goodNodeArray里边已经存了多少个
countGood = 0
tmpNode = Node()
goodNodeArray = []
for i in range( 0 , MAX_LINE ):
for j in range( 0 , MAX_LINE ):
if board[ i ][ j ] == EMPTY:
board[ i ][ j ] = player
tmpNode = self.evaluate.getValue( player , board )
board[ i ][ j ] = EMPTY
tmpNode.x = i
tmpNode.y = j
countGood += 1
if countGood < = numGoodNodes:
goodNodeArray.append( tmpNode )
if( countGood == numGoodNodes ):
goodNodeArray = sorted( goodNodeArray , key = lambda node: -node.value )
else:
if tmpNode.value > goodNodeArray[ numGoodNodes - 1 ].value:
for k in range( numGoodNodes ):
if tmpNode.value > goodNodeArray[ k ].value:
goodNodeArray[ k ] = tmpNode
break
return goodNodeArray
#alpha-beta减枝搜索算法
def alphaBetaSearch( self , search_depth , alpha , beta , player ):
score = 0
goodNodes = []
badNodes = [ Node() ]
goodNodes = self.search_several_good_nodes( player , self.chessBoard , self.numOfGoodNodes )
badNodes = self.search_several_good_nodes( RIVAL if player == MYSELF else RIVAL , self.chessBoard , 1 )
if goodNodes[ 0 ].win == WIN:
if search_depth == 1:
self.bestMove.x = goodNodes[ 0 ].x
self.bestMove.y = goodNodes[ 0 ].y
return goodNodes[ 0 ].value
if badNodes[ 0 ].win == WIN:
if search_depth == 1:
self.bestMove.x = badNodes[ 0 ].x
self.bestMove.y = badNodes[ 0 ].y
return badNodes[ 0 ].value
if search_depth == self.depth:
return goodNodes[ 0 ].value if search_depth % 2 else -goodNodes[ 0 ].value
for i in range( self.numOfGoodNodes ):
self.chessBoard[ goodNodes[ i ].x ][ goodNodes[ i ].y ] = player
score = -self.alphaBetaSearch( search_depth + 1 , -beta , -alpha , RIVAL if player == MYSELF else MYSELF )
self.chessBoard[ goodNodes[ i ].x ][ goodNodes[ i ].y ] = EMPTY
if score >= beta:
return beta
if score > alpha:
alpha = score
if search_depth == 1:
self.bestMove.x = goodNodes[ i ].x
self.bestMove.y = goodNodes[ i ].y
return alpha
def test():
chessBoard = [ [ EMPTY for i in range( MAX_LINE ) ] for j in range( MAX_LINE ) ]
chessBoard[ 5 ][ 7 ] = chessBoard[ 6 ][ 7 ] = chessBoard[ 7 ][ 7 ] = MYSELF
chessBoard[ 5 ][ 8 ] = chessBoard[ 6 ][ 8 ] = RIVAL
#这里搜索深度和广度都为3,深度和广度越大,搜索时间越长,结果也越准确
search = Search( 3 , 3 , chessBoard )
for i in range( MAX_LINE ):
print search.chessBoard[ i ]
print 'it\'s my turn !'
print 'calculating...'
search.alphaBetaSearch( 1 , -INIT_MAX , INIT_MAX , RIVAL )
print search.bestMove.x , search.bestMove.y
chessBoard[ search.bestMove.x ][ search.bestMove.y ] = RIVAL
for i in range( MAX_LINE ):
print chessBoard[ i ]
print 'it\'s your turn !'
print 'calculating...'
search = Search( 3 , 3 , chessBoard )
search.alphaBetaSearch( 1 , -INIT_MAX , INIT_MAX , MYSELF )
print search.bestMove.x , search.bestMove.y
chessBoard[ search.bestMove.x ][ search.bestMove.y ] = MYSELF
for i in range( MAX_LINE ):
print chessBoard[ i ]
if __name__ == '__main__':
test() |