def alphabeta(board, alpha, beta, depth, color, player): can_moves = [] for i in range(8): for j in range(8): if gamePlay.valid(board, player, (i,j)): can_moves.append((i,j)) if depth == 0 or len(can_moves) == 0: return calculate_heuristic(board, color) if(player == color):#Maximizing v = -999999 for can_move in can_moves: temp_board = copy.deepcopy(board) gamePlay.doMove(temp_board, player, can_move) v = max(v, alphabeta(temp_board, alpha, beta, depth-1, color, gamePlay.opponent(player))) alpha = max(alpha, v) if(alpha >= beta): break return v else:#Minimizing v = 999999 for can_move in can_moves: temp_board = copy.deepcopy(board) gamePlay.doMove(temp_board, player, can_move) v = min(v, alphabeta(temp_board, alpha, beta, depth-1, color, gamePlay.opponent(player))) beta = min(beta, v) if (alpha >= beta): break return v
def alphabeta(board, color, depth, alpha, beta, moveMade, isMax, timeoutAt=None): # alphabeta failed to find a solution in time alotted if timeoutAt and time.time() > timeoutAt: raise threading.ThreadError('alphabeta timed out before finding a solution') if depth == 0 or gameOver(board): #print 'bottomed out at %s' % str((simpleHeuristic(board), moveMade)) return (simpleHeuristic(board), moveMade) if isMax: for movePos in children(board, color): try: childScore, childMove = alphabeta(childBoard(board, color, movePos), opponent(color), depth-1, alpha, beta, movePos, False) except threading.ThreadError as e: raise e alpha = (childScore, movePos) if childScore > alpha[0] else alpha if beta[0] <= alpha[0]: break return alpha else: for movePos in children(board, color): try: childScore, childMove = alphabeta(childBoard(board, color, movePos), opponent(color), depth-1, alpha, beta, movePos, True) except threading.ThreadError as e: raise e beta = (childScore, movePos) if childScore < beta[0] else beta if beta[0] <= alpha[0]: break return beta
def nextMove(board, color, time, reversed = False): global myColor global opponentColor global alpha global beta global localalpha opponentColor=gamePlay.opponent(color) myColor=color moves=getMoves(board,color) #print "moves :",moves if len(moves) == 0: return "pass" childNodes=[] changeTime(time) changeWeight(board) bestMove=None bestValue=None #print "moves :",len(moves) for move in moves: parnt = makeNode(None,None,move[0],move[1]) childNodes.append(parnt) newBoard = deepcopy(board) gamePlay.doMove(newBoard,color,move) #gamePlay.printBoard(newBoard) #gamePlay.printBoard(newBoard) oppColor=gamePlay.opponent(color) traverseTree(parnt,newBoard,oppColor,1) #print "aaaaaaa ",aaaa if bestMove==None: bestMove=move bestValue=parnt[1] elif bestValue<parnt[1]: bestMove=move bestValue=parnt[1] if alpha == None: alpha=beta if alpha<beta: alpha=beta beta=None localalpha=None #print parnt[1] #for n in childNodes: # print "final value :",n[1] #print "bestValue ",bestValue #print "bestMove ",bestMove #iop=raw_input() return bestMove
def nextMove(board, color, time, reversed=False): global myColor global opponentColor global alpha global beta global localalpha opponentColor = gamePlay.opponent(color) myColor = color moves = getMoves(board, color) #print "moves :",moves if len(moves) == 0: return "pass" childNodes = [] changeTime(time) changeWeight(board) bestMove = None bestValue = None #print "moves :",len(moves) for move in moves: parnt = makeNode(None, None, move[0], move[1]) childNodes.append(parnt) newBoard = deepcopy(board) gamePlay.doMove(newBoard, color, move) #gamePlay.printBoard(newBoard) #gamePlay.printBoard(newBoard) oppColor = gamePlay.opponent(color) traverseTree(parnt, newBoard, oppColor, 1) #print "aaaaaaa ",aaaa if bestMove == None: bestMove = move bestValue = parnt[1] elif bestValue < parnt[1]: bestMove = move bestValue = parnt[1] if alpha == None: alpha = beta if alpha < beta: alpha = beta beta = None localalpha = None #print parnt[1] #for n in childNodes: # print "final value :",n[1] #print "bestValue ",bestValue #print "bestMove ",bestMove #iop=raw_input() return bestMove
def traverseTree(parnt, board, color, depth): #print "color",color global alpha global beta global localalpha global flag moves = getMoves(board, color) if depth == globalDepth or len(moves) == 0: value = valueBoard(board) parnt[1] = value return #print "moves",moves #if len(moves) == 0: # return #iCounter=0 for move in moves: #print "iCounter :",iCounter flag = True node = makeNode(parnt, None, move[0], move[1]) #print "a" newBoard = deepcopy(board) #print "b" gamePlay.doMove(newBoard, color, move) #print "c" #gamePlay.printBoard(newBoard) #print newBoard oppColor = gamePlay.opponent(color) traverseTree(node, newBoard, oppColor, depth + 1) #if traverseTreeReturn=="depth" or traverseTreeReturn=="pass": #gamePlay.printBoard(newBoard) #value=valueBoard(newBoard) #print "value",node[0][1] if node[0][1] == None: node[0][1] = node[1] if depth % 2 == 0: localalpha = node[1] if depth % 2 == 1: beta = node[1] elif node[0][1] <= node[1] and depth % 2 == 0: node[0][1] = node[1] if localalpha != None and localalpha < node[1]: localalpha = node[1] elif node[0][1] >= node[1] and depth % 2 == 1: node[0][1] = node[1] if beta != None and beta > node[1]: beta = node[1] if alpha != None and beta != None: if alpha >= beta and flag == True: flag = False break if localalpha != None and beta != None: if localalpha >= beta and flag == True: flag = False break return
def nextMove(board, color, time): best_val = None best_move = None moves = [] for row in range(8): for col in range(8): if gamePlay.valid(board, color, (row, col)): moves.append((row, col)) #shuffle the moves in case it places the same position in every game #shuffle(moves) if len(moves) == 0: return "pass" if moves == "pass": return "pass" opp = gamePlay.opponent(color) #evaluate max's position and choose the best value if color == "B": for move in moves: newBoard = board[:] gamePlay.doMove(newBoard, color, move) #alpha = - INFINITY beta = INFINITY #we want to choose the max one if best_val = max(best_val, alpha_beta(newBoard, opp, 3, -INFINITY, INFINITY)): #update best move best_move = move
def maxVal(node,color,depth,a,b): #if game is over or reached search depth, calculate score. #here, I simply use the score function provided in gameplay. if gameOver(node.state) or depth==0: black,white=score(node.state) if (color == "B"): node.value=black; return black elif (color == "W"): node.value=white; return white #set v value to a very small number v=-999; #populate children node.populateChildren(color); #if no children, just get value at current step if len(node.children)==0: return maxVal(node,color,0,a,b); #for each child in next depth, calculate opponent score for child in node.children: returnValue=minVal(child,opponent(color),depth-1,a,b); v=max(v,returnValue); node.value=v; if v>=b: return v; a=max(a,v); return v;
def minVal(node,color,depth,a,b): #if game is over or reached search depth, calculate score. if gameOver(node.state) or depth==0: black,white=score(node.state) if (color == "B"): node.value=black; return black elif (color == "W"): node.value=white; return white #set v value to a very large number v=999; #populate children node.populateChildren(color); #if no children, just get value at current step if len(node.children)==0: return minVal(node,color,0,a,b); #for each child in next depth, calculate opponent score for child in node.children: returnValue=maxVal(child,opponent(color),depth-1,a,b) v=min(v,returnValue); node.value=v; if v<=a: return v; b=min(b,v); return v
def minimax(board, color, depth, alpha, beta, maximizingPlayer): #By default if we do not get any move, we use "pass" bestMove = "pass" #Successor function called on current board moves = successor(board, color) if depth == 0 or moves== "pass": return value(board, color, maximizingPlayer),"pass" #Recursing over self and opponent if maximizingPlayer: for move in moves: newBoard = deepcopy(board) gamePlay.doMove(newBoard,color, move) child = newBoard x = minimax(child, gamePlay.opponent(color), depth - 1, alpha, beta, False)[0] #alpha will select the maximum value if alpha < x: alpha = x bestMove = move #pruning condition if beta <= alpha: break #maxplayer will always return the best move return alpha,bestMove #opponents best play else: for move in moves: newBoard = deepcopy(board) gamePlay.doMove(newBoard,color, move) child = newBoard y = minimax(child, gamePlay.opponent(color), depth - 1, alpha, beta, True)[0] #beta will select the minimum value if beta > y: beta = y #pruning condition if beta <= alpha: break #Doesn't matter what move we pass, this will never be returned to nextmove return beta, "pass"
def value(board, color, maximizingPlayer): new = deepcopy(board) #we use i and j to refer to indices at positional i=0 j=0 #values to calculate positional advantage of self and opponent valueSelf = 0 valueOpp = 0 #Traversing each board position to calculate the advantage based on the for row in board: j = 0 i += 1 for elem in row: value = positional[i][j] if elem == color: #if we are maximizing player, we keep adding advantage to self since it is self color # else add in opponent if maximizingPlayer: valueSelf = valueSelf + value else: valueOpp = valueOpp + value else: #if we are maximizing player, we keep subtracting since its not our color advantage to self #else subtract from opponent if maximizingPlayer: valueSelf = valueSelf - value else: valueOpp = valueOpp - value j +=1 #The positional advantage of whole board will be subtraction of self advantage and opponents advantage boardCount = valueSelf-valueOpp #calculating number of available moves in future; for self and opponent myMoves = successor(new, color) oppMoves = successor(new, opponent(color)) #Taking the ratio of moves #If opponent comes to "pass" in future; set m as 10 which is desirable #if self has "pass" in future; set m as -10 since it is undesirable if not myMoves=="pass" and not oppMoves=="pass": if len(myMoves) > len(oppMoves): m = len(myMoves) / float((len(myMoves) + len(oppMoves))) else: m = -(len(myMoves)) / float((len(myMoves) + len(oppMoves))) elif myMoves=="pass": m = -10 else: m = 10 #The heurisitic will scale mobility and add positional advantage heuristic = (100 * m) + boardCount return heuristic
def alphabeta(board, color, depth, alpha, beta, moveMade, isMax): if depth == 0 or gameOver(board): #print 'bottomed out at %s' % str((simpleHeuristic(board), moveMade)) return (simpleHeuristic(board, color), moveMade) if isMax: for movePos in children(board, color): childScore, childMove = alphabeta(childBoard(board, color, movePos), opponent(color), depth-1, alpha, beta, movePos, False) alpha = (childScore, movePos) if childScore > alpha[0] else alpha if beta[0] <= alpha[0]: break return alpha else: for movePos in children(board, color): childScore, childMove = alphabeta(childBoard(board, color, movePos), opponent(color), depth-1, alpha, beta, movePos, True) beta = (childScore, movePos) if childScore < beta[0] else beta if beta[0] <= alpha[0]: break return beta
def simpleHeuristic(board, myColor): value = 0 for row in board: for elem in row: if elem == opponent(myColor): value = value + 1 elif elem == myColor: value = value - 1 return value
def getWeight(self, color): # weight matrix의 놓인 위치를 비교하여 값 계산 acc = 0 opp = opponent(color) for i in range(8): for j in range(8): if self.board[i][j] == color or self.board[i][j] == color: acc += WEIGHT_BOARD[i][j] # 내가 놓았다면 plus elif self.board[i][j] == opp or self.board[i][j] == opp: acc -= WEIGHT_BOARD[i][j] # 상대가 놓았다면 minus return acc
def calcRatio(self, color): # 상대방의 돌과 내 돌의 비율을 계산 opp = opponent(color) my = 0 you = 0 for i in range(8): for j in range(8): if self.board[i][j] == color: my += 1 elif self.board[i][j] == opp: you += 1 return (float(my) / float(my + you)) * 10
def calculate_heuristic(board, color): player_pieces = 0 opponent_pieces = 0 for i in range(8): for j in range(8): if board[i][j]==color: player_pieces += 1 elif board[i][j]==gamePlay.opponent(color): opponent_pieces += 1 edge_pos = [(0,0), (0,7), (7,0), (7,7)] for edge in edge_pos: if board[edge[0]][edge[1]] == color: player_pieces += 999 elif board[edge[0]][edge[1]] == gamePlay.opponent(color): opponent_pieces += 999 side_pos = [0,7] for side in side_pos: for k in range(8): if board[side][k] == color: player_pieces += 5 elif board[side][k] == gamePlay.opponent(color): opponent_pieces += 5 elif board[k][side] == color: player_pieces += 5 elif board[k][side] == gamePlay.opponent(color): opponent_pieces += 5 weak_pos= [(1,1),(1,0),(0,1),(6,6),(0,6),(6,0),(1,6),(6,7),(7,6),(6,1),(7,1),(1,7)] for weak in weak_pos: if board[weak[0]][weak[1]] == color: opponent_pieces += 5 elif board[weak[0]][weak[1]] == gamePlay.opponent(color): player_pieces += 5 count_eval = player_pieces - opponent_pieces return count_eval
def alpha_beta(board, color): '''Alpha-beta pruning''' next_positions = get_successors(board, color) if len(next_positions) == 0: return "pass" next_color = gamePlay.opponent(color) best_value = -100000 best_move = (-1, -1) '''This for loop works as max_value(), so here starts the recursion with min_value()''' for pos in next_positions: tempboard = deepcopy(board) gamePlay.doMove(tempboard, color, pos) val = min_value(tempboard, next_color, 6) # Search depth is 6. If it is deeper, we need to wait too long for result if val >= best_value: best_value = val best_move = pos return best_move
def makeTree(root, color, depth): # 트리 생성 함수 if depth >= limitDepth: # 한계 깊이 이상이면 종료 return moveslen = len(root.children) for k in range(moveslen): child = root.children[k] # 움직일 수 있는 곳을 하나씩 움직여봄 another = opponent(color) for i in range(8): for j in range(8): if valid(child.board, another, (i, j)): # 다음 턴에 놓을 수 있는 곳이면 자식으로 추가 temp = Node() temp.data = (i,j) temp.board = deepcopy(child.board) doMove(temp.board, another, temp.data) child.children.append(temp) if len(child.children) != 0: makeTree(child, another, depth + 1) # 재귀적으로 자식을 확장
def min_value(board, color, depth): '''Calculate the min value. The comments are the same as in max_value()''' global alpha, beta if gamePlay.gameOver(board) or depth == 0: return evaluation(board, color) depth -= 1 val = 100000 next_positions = get_successors(board, color) next_color = gamePlay.opponent(color) if len(next_positions) == 0: return evaluation(board, color) for pos in next_positions: tempboard = deepcopy(board) gamePlay.doMove(tempboard, color, pos) val = min(val, max_value(tempboard, next_color, depth)) if val <= alpha: return val beta = min(beta, val) # Update beta value return val
def alpha_beta(board, color, depth, alpha, beta): """Find the utility value of the game and the best_val move in the game.""" if depth == 0: return eval_fn(board, color) if gamePlay.gameOver(board): return gamePlay.score(board) moves = [] for row in range(8): for col in range(8): if gamePlay.valid(board, color, (row, col)): moves.append((row, col)) #shuffle the moves in case it places the same position in every game #shuffle(moves) if len(moves) == 0: return "pass" if moves == "pass": return eval_fn(board, color) opp = gamePlay.opponent(color) # try each move #evaluate max's position and choose the best value if color == "B": for move in moves: newBoard = board[:] gamePlay.doMove(newBoard, color, move) #cut off the branches alpha = max(alpha, alpha_beta(newBoard, opp, depth-1, alpha, beta)) if beta <= alpha: return return alpha #evaluate min's position and choose the best value if color == "W": for move in moves: newBoard = board[:] gamePlay.doMove(newBoard, color, move) #cut off the branches beta = min(beta, alpha_beta(newBoard, opp, depth-1, alpha, beta)) if beta <= alpha: return return beta
def minimax(board, color, depth): #Find the best move in the game #if depth = 0, we calculate the score if depth == 0: return eval_fn(board, color) #if game is over, we calculate the score if gamePlay.gameOver(board): return gamePlay.score(board) best_val = None best_move = None opp = gamePlay.opponent(color) # valid moves moves = [] for row in range(8): for col in range(8): if gamePlay.valid(board, color, (row,col)): moves.append((row,col)) #shuffle the moves in case it places the same position in every game #shuffle(moves) if len(moves) == 0: return "pass" if move == "pass": return eval_fn(board, color) #try each move in valid moves #evaluate max's position and choose the best value if color == "B": for move in moves: newBoard = board[:] gamePlay.doMove(newboard, color, move) val = minimax(newBoard, opp, depth-1) if best_val is None or val > (best_val, best_move)[0]: (best_val, best_move) = (val, move) #evaluate min's position and choose the best value if color == "W": for move in moves: newBoard = board[:] gamePlay.doMove(newboard, color, move) val = minimax(newBoard, opp, depth-1) if best_val is None or val < (best_val, best_move)[0]: (best_val, best_move) = (val, move) return (best_val, best_move)[0]
def max_value(board, color, depth): '''Calculate the max value''' global alpha, beta if gamePlay.gameOver(board) or depth == 0: '''If the game board is full of pieces, or reach the search depth, give the evaluation of the situation''' return evaluation(board, color) depth -= 1 val = -100000 next_positions = get_successors(board, color) # Get the child nodes next_color = gamePlay.opponent(color) # Get the opponent's color if len(next_positions) == 0: return evaluation(board, color) # If no child node, return the evaluation for pos in next_positions: tempboard = deepcopy(board) # Create a new board for mock moves gamePlay.doMove(tempboard, color, pos) # Do a mock move val = max(val, min_value(tempboard, next_color, depth)) '''Alpha-beta pruning''' if val >= beta: return val alpha = max(alpha, val) # Update alpha value return val
def children(board, myColor): """Yields all child nodes worth exploring""" opponentTiles = [] opponentMarker = opponent(myColor) # define what tiles are on the board for x in range(8): for y in range(8): if board[x][y].upper() == opponentMarker: opponentTiles.append((x, y)) alreadyYielded = set() for tile in opponentTiles: # for each opponent tile on board neighbors = filter(lambda pos: isValid(board, myColor, pos), _surrounding(tile)) # only valid neighbors of this tile for move in neighbors: if move not in alreadyYielded: # yield each possible move only once alreadyYielded.add(move) yield move
def eval_fn(board, color): # if the game is over, give a 100 point bonus to the winning player if gamePlay.gameOver(board): point = gamePlay.score(board) if point > 0: return 100 elif point < 0: return -100 else: return 0 point = 0 #find the color of the opponent opp = gamePlay.opponent(color) for row in range(8): for col in range(8): #calculate the point of current player if board[row][col] == color: point += gradingStrategy[(row+1)*10+1+col] #calculate the point of the opponent elif board[row][col] == opp: point -= gradingStrategy[(row+1)*10+1+col] return point
def traverseTree(parnt,board,color,depth): #print "color",color global alpha global beta global localalpha global flag moves=getMoves(board,color) if depth==globalDepth or len(moves) == 0: value=valueBoard(board) parnt[1]=value return #print "moves",moves #if len(moves) == 0: # return #iCounter=0 for move in moves: #print "iCounter :",iCounter flag= True node =makeNode(parnt,None,move[0],move[1]) #print "a" newBoard = deepcopy(board) #print "b" gamePlay.doMove(newBoard,color,move) #print "c" #gamePlay.printBoard(newBoard) #print newBoard oppColor=gamePlay.opponent(color) traverseTree(node,newBoard,oppColor,depth+1) #if traverseTreeReturn=="depth" or traverseTreeReturn=="pass": #gamePlay.printBoard(newBoard) #value=valueBoard(newBoard) #print "value",node[0][1] if node[0][1]==None: node[0][1]=node[1] if depth%2==0: localalpha=node[1] if depth%2==1: beta=node[1] elif node[0][1]<=node[1] and depth%2==0: node[0][1]=node[1] if localalpha!=None and localalpha<node[1]: localalpha=node[1] elif node[0][1]>=node[1] and depth%2==1: node[0][1]=node[1] if beta!=None and beta >node[1]: beta=node[1] if alpha !=None and beta !=None: if alpha>=beta and flag ==True: flag=False break if localalpha!=None and beta !=None: if localalpha>=beta and flag==True: flag=False break return
def nextMove(board, color, time): limit_depth = 4 max_value = -999999 min_value = 99999 valid_count = 0 for i in range(8): for j in range(8): if gamePlay.valid(board ,color, (i,j)): valid_count += 1 temp_board = copy.deepcopy(board) gamePlay.doMove(temp_board, color, (i,j)) v = alphabeta(temp_board, max_value, min_value, limit_depth-1, color, gamePlay.opponent(color)) if v >= max_value: next_move = (i, j) max_value = v if valid_count == 0: return "pass" #gamePlay.printBoard(board) return next_move