def findPower(self, state, play_num): # a kind of bfs for the nearest powerup board = state.board origin = state.player_locs[play_num] visited = set() Q = queue.Queue() visited.add(origin) start_moves = list(TronProblem.get_safe_actions(board, origin)) for direction in start_moves: neighbor = TronProblem.move(origin, direction) r, c = neighbor if board[r][c] == '*': # powerup return direction Q.put((neighbor, direction)) while not Q.empty(): curr, initdir = Q.get() r, c = curr valid_moves = list(TronProblem.get_safe_actions(board, curr)) for direction in valid_moves: neighbor = TronProblem.move(curr, direction) r, c = neighbor if board[r][c] == '*': # powerup return initdir if neighbor not in visited: visited.add(neighbor) Q.put((neighbor, initdir)) # we couldn't find a powerup possibilities = list(TronProblem.get_safe_actions(board, origin)) if possibilities: return random.choice(possibilities) return 'U'
def freedom(self, state, play_num): board = state.board origin = state.player_locs[play_num] freedom = 0 for d1 in list(TronProblem.get_safe_actions(board, origin)): n1 = TronProblem.move(origin, d1) for d2 in list(TronProblem.get_safe_actions(board, n1)): n2 = TronProblem.move(origin, d2) for d3 in list(TronProblem.get_safe_actions(board, n2)): freedom += 1 return freedom
def bfs(self,state,play_num): #a bounded search of how many tiles are accessible board = state.board newboard = [[ -1 for elt in row] for row in state.board] origin = state.player_locs[play_num] visited = set() Q = Queue.Queue() Q.put(origin) visited.add(origin) dis = 0 #print state.board while not Q.empty(): size = Q.qsize() for i in range(size): curr = Q.get() i,j = curr newboard[i][j] = dis valid_moves = list(TronProblem.get_safe_actions(board,curr)) for direction in valid_moves: neighbor = TronProblem.move(curr,direction) if neighbor not in visited: visited.add(neighbor) Q.put(neighbor) dis += 1 #print score return newboard
def bfs_with_powerup(self,state,play_num): #a bounded search of how many tiles are accessible board = state.board origin = state.player_locs[play_num] opponent = state.player_locs[(play_num+1)%2] connected = False visited = set() Q = Queue.Queue() Q.put(origin) visited.add(origin) level = 0 powerup = 0 #print state.board while not Q.empty(): size = Q.qsize() level += 1 for i in range(size): curr = Q.get() i,j = curr #print (i,j) if self.board[i][j] == '*': #print (i,j),origin powerup += 10*math.exp(-level) if self.manhattan_distance(curr, opponent) == 1: connected = True valid_moves = list(TronProblem.get_safe_actions(board,curr)) for direction in valid_moves: neighbor = TronProblem.move(curr,direction) if neighbor not in visited: visited.add(neighbor) Q.put(neighbor) score = len(visited) + powerup #print score return score,connected
def decide(self,asp): state = asp.get_start_state() locs = state.player_locs board = state.board ptm = state.ptm loc = locs[ptm] possibilities = list(TronProblem.get_safe_actions(board,loc)) if not possibilities: return 'U' decision = possibilities[0] for move in self.order: if move not in possibilities: continue next_loc = TronProblem.move(loc, move) if len(TronProblem.get_safe_actions(board,next_loc)) < 3: decision = move break return decision
def voronoi_heuristic(tron_state): ''' Calculates the difference between "zones of control" as defined by a voronoi diagram--zones defining squares that can be reached by p1 or p2 first. ''' # We make it so that p1 is the player to move and p2 is opponent player_locs = determine_players(tron_state) p1_loc = player_locs[0] p2_loc = player_locs[1] board = tron_state.board p1_visited = set([p1_loc]) p1_f = [] p1_f.append(p1_loc) p2_visited = set([p2_loc]) p2_f = [] p2_f.append(p2_loc) while p1_f or p2_f: n_p1_f = [] for loc in p1_f: moves = TronProblem.get_safe_actions(board, loc) for move in moves: next_loc = action_move(loc, move) if (next_loc not in p1_visited) and (next_loc not in p2_visited): n_p1_f.append(next_loc) p1_visited.add(next_loc) n_p2_f = [] for loc in p2_f: moves = TronProblem.get_safe_actions(board, loc) for move in moves: next_loc = action_move(loc, move) if (next_loc not in p1_visited) and (next_loc not in p2_visited): n_p2_f.append(next_loc) p2_visited.add(next_loc) p1_f = n_p1_f p2_f = n_p2_f return len(p1_visited) - len(p2_visited)
def decide(self,asp): state = asp.get_start_state() locs = state.player_locs board = state.board ptm = state.ptm loc = locs[ptm] possibilities = list(TronProblem.get_safe_actions(board,loc)) if possibilities: return random.choice(possibilities) return 'U'
def voronoi(self, state, play_num): """Basic voronoi implementation""" origin = state.player_locs[play_num] visited = {} Q = queue.Queue() Q.put(origin) visited[origin] = 0 while not Q.empty(): curr = Q.get() valid_moves = list(TronProblem.get_safe_actions(self.board, curr)) for direction in valid_moves: neighbor = TronProblem.move(curr, direction) if neighbor not in visited: visited[neighbor] = 1 + visited[curr] Q.put(neighbor) score = 0 opp_visited = {} origin = state.player_locs[1 - play_num] Q.put(origin) opp_visited[origin] = 0 while not Q.empty(): curr = Q.get() valid_moves = list(TronProblem.get_safe_actions(self.board, curr)) for direction in valid_moves: neighbor = TronProblem.move(curr, direction) if neighbor not in opp_visited: opp_visited[neighbor] = 1 + opp_visited[curr] if neighbor in visited: if opp_visited[neighbor] < visited[neighbor]: score -= 1 elif opp_visited[neighbor] > visited[neighbor]: score += 1 Q.put(neighbor) for pos in list(visited.keys()): if pos not in opp_visited: score += 1 for pos in list(opp_visited.keys()): if pos not in visited: score -= 1 return score
def decide(self, asp): """ Input: asp, a TronProblem Output: A direction in {'U','D','L','R'} """ state = asp.get_start_state() locs = state.player_locs board = state.board ptm = state.ptm loc = locs[ptm] possibilities = list(TronProblem.get_safe_actions(board, loc)) if not possibilities: return "U" decision = possibilities[0] for move in self.order: if move not in possibilities: continue next_loc = TronProblem.move(loc, move) if len(TronProblem.get_safe_actions(board, next_loc)) < 3: decision = move break return decision
def decide(self, asp): """ Input: asp, a TronProblem Output: A direction in {'U','D','L','R'} """ state = asp.get_start_state() locs = state.player_locs board = state.board ptm = state.ptm loc = locs[ptm] possibilities = list(TronProblem.get_safe_actions(board, loc)) if possibilities: return random.choice(possibilities) return "U"
def bfs(self,state,play_num): #a bounded search of how many tiles are accessible board = state.board origin = state.player_locs[play_num] visited = set() Q = Queue.Queue() Q.put(origin) visited.add(origin) while not Q.empty(): curr = Q.get() valid_moves = list(TronProblem.get_safe_actions(board,curr)) for direction in valid_moves: neighbor = TronProblem.move(curr,direction) if neighbor not in visited: visited.add(neighbor) Q.put(neighbor) return len(visited)
def alpha_beta_cutoff(asp, cutoff_turn, eval_func): """ An implementation of the alpha_beta_cutoff algorithm that is specifically written for the TronProblem (it only considers safe actions) """ state = asp.get_start_state() player = state.player_to_move() best_action = 'D' best_value = -float('inf') a = -float('inf') b = float('inf') for action in TronProblem.get_safe_actions(state.board, state.player_locs[player]): next_state = asp.transition(state, action) value = abchelper(asp, next_state, cutoff_turn - 1, a, b, False, eval_func, player) if value > best_value: best_value = value best_action = action a = max(a, best_value) if b <= a: break return best_action
def fillboard(self, state, me, enemy): board = state.board locs = state.player_locs myloc = locs[me] enemyloc = locs[enemy] floodboard = np.array(board) if floodboard[myloc] == '*': floodboard[myloc] = 'A' #my powerup else: floodboard[myloc] = 'M' #'M' for me if floodboard[enemyloc] == '*': floodboard[enemyloc] = 'B' #enemy powerup else: floodboard[enemyloc] = 'E' #'E' for enemy myvisited = {myloc} enemyvisited = {enemyloc} myQ = Queue.Queue() myQ.put(myloc) enemyQ = Queue.Queue() enemyQ.put(enemyloc) myneighbors = set() enemyneighbors = set() # keep going until no new positions are added to the queues while not myQ.empty() or not enemyQ.empty(): while not myQ.empty(): #I fill first mycur = myQ.get() valid_moves = list(TronProblem.get_safe_actions(board, mycur)) for direction in valid_moves: neighbor = TronProblem.move(mycur, direction) if neighbor not in myvisited and not ( floodboard[neighbor] == 'E' or floodboard[neighbor] == 'B'): if floodboard[neighbor] == '*': #if tile is a powerup floodboard[ neighbor] = 'A' #Let 'A' represent a 'M' space with powerup else: floodboard[neighbor] = 'M' myvisited.add(neighbor) myneighbors.add(neighbor) while not enemyQ.empty(): #Then enemy fills enemycur = enemyQ.get() valid_moves = list( TronProblem.get_safe_actions(board, enemycur)) for direction in valid_moves: neighbor = TronProblem.move(enemycur, direction) if neighbor not in enemyvisited and not ( floodboard[neighbor] == 'M' or floodboard[neighbor] == 'A'): if floodboard[neighbor] == '*': floodboard[ neighbor] = 'B' #Let 'B' represent a 'E' space with powerup else: floodboard[neighbor] = 'E' enemyvisited.add(neighbor) enemyneighbors.add(neighbor) map( myQ.put, myneighbors ) #put all the newfound neighbors onto queue for next iteration myneighbors = set() #reset neighbors set map(enemyQ.put, enemyneighbors) enemyneighbors = set() numM = np.count_nonzero( floodboard == 'M') #count the number of tiles I reach first numMpwr = np.count_nonzero( floodboard == 'A') #count the number of powerup tiles I reach first numE = np.count_nonzero( floodboard == 'E') #count the number of tiles that enemy reaches first numEpwr = np.count_nonzero( floodboard == 'B') #count the number of powerup tiles that enemy reaches first val = (numM + numMpwr) - ( numE + numEpwr) #maximize the difference between our spaces return val
def fillboard(self, state, me, enemy): board = state.board locs = state.player_locs myloc = locs[me] enemyloc = locs[enemy] enemyspace = self.get_surroundings(state, enemyloc, 2) floodboard = np.array(board) closebonus = 0 if floodboard[myloc] == '*': floodboard[myloc] = 'A' #my powerup closebonus += 2 else: floodboard[myloc] = 'M' #'M' for me if floodboard[enemyloc] == '*': floodboard[enemyloc] = 'B' #enemy powerup else: floodboard[enemyloc] = 'E' #'E' for enemy for direction in list(TronProblem.get_safe_actions(board, myloc)): neighbor = TronProblem.move(myloc, direction) if floodboard[neighbor] == '*': closebonus += 1 myvisited = {myloc} enemyvisited = {enemyloc} myQ = Queue.Queue() myQ.put(myloc) enemyQ = Queue.Queue() enemyQ.put(enemyloc) myneighbors = set() enemyneighbors = set() colored = False # KEY # A powerup # M colored tile me # N non-colored tile me # keep going until no new positions are added to the queues while not myQ.empty() or not enemyQ.empty(): while not myQ.empty(): #I fill first mycur = myQ.get() valid_moves = list(TronProblem.get_safe_actions(board, mycur)) for direction in valid_moves: neighbor = TronProblem.move(mycur, direction) if neighbor not in myvisited and not ( floodboard[neighbor] == 'E' or floodboard[neighbor] == 'F' or floodboard[neighbor] == 'B'): if floodboard[neighbor] == '*': #if tile is a powerup if colored: floodboard[ neighbor] = 'A' #Let 'A' represent a 'M' space with powerup else: floodboard[neighbor] = 'C' #not colored mine else: if colored: floodboard[neighbor] = 'M' else: floodboard[neighbor] = 'N' myvisited.add(neighbor) myneighbors.add(neighbor) while not enemyQ.empty(): #Then enemy fills enemycur = enemyQ.get() valid_moves = list( TronProblem.get_safe_actions(board, enemycur)) for direction in valid_moves: neighbor = TronProblem.move(enemycur, direction) if neighbor not in enemyvisited and not ( floodboard[neighbor] == 'M' or floodboard[neighbor] == 'N' or floodboard[neighbor] == 'A'): if floodboard[neighbor] == '*': if colored: floodboard[ neighbor] = 'B' #Let 'B' represent a 'E' space with powerup else: floodboard[neighbor] = 'D' #not colored enemy else: if colored: floodboard[neighbor] = 'E' else: floodboard[neighbor] = 'F' enemyvisited.add(neighbor) enemyneighbors.add(neighbor) colored = not colored map( myQ.put, myneighbors ) #put all the newfound neighbors onto queue for next iteration myneighbors = set() #reset neighbors set map(enemyQ.put, enemyneighbors) enemyneighbors = set() numM = np.count_nonzero( floodboard == 'M') #count the number of colored tiles I reach first numN = np.count_nonzero( floodboard == 'N') #count the number of non-colored tiles I reach first numMpwr = np.count_nonzero( floodboard == 'A') #count the number of powerup tiles I reach first numNpwr = np.count_nonzero(floodboard == 'C') numE = np.count_nonzero( floodboard == 'E') #count the number of colored tiles that enemy reaches first numF = np.count_nonzero( floodboard == 'F' ) #count the number of non-colored tiles that enemy reaches first numEpwr = np.count_nonzero( floodboard == 'B') #count the number of powerup tiles that enemy reaches first numFpwr = np.count_nonzero(floodboard == 'D') val = (min(numM + numMpwr * self.powerup_val, numN + numNpwr * self.powerup_val) + (numMpwr + numNpwr) * self.powerup_val) - ( min(numE + numEpwr * self.powerup_val, numF + numFpwr * self.powerup_val) + (numEpwr + numFpwr) * self.powerup_val ) #maximize the difference between our spaces return val + closebonus
def _get_safe_actions_random(board, loc): actions = list(TronProblem.get_safe_actions(board, loc)) random.shuffle(actions) return actions