def dijkstra(graph, start): prev = {} costs = {} costs[start] = 0 visited = set() pq = PriorityQueue() for node in graph.nodes(): if node != -1: pq.insert(float('inf'), node) pq.insert(0, start) while not pq.is_empty(): cost, ele = pq.delete_min() visited.add(ele) for successor in graph.get_successors(ele): new_cost = cost + graph.get_cost(ele, successor) if successor not in visited and (successor not in costs or new_cost < costs[successor]): costs[successor] = new_cost prev[successor] = ele pq.update(new_cost, successor) res = {} for key in costs: res[(start, key)] = costs[key] return res
def prim(graph, start): # heap to have the vertex that are not added # key is the cheapest edge edge = set() overall_cost = 0 prev = {} prev[start] = start costs = {} costs[start] = 0 pq = PriorityQueue() visited = set() for node in graph.nodes(): pq.insert(float('inf'), node) pq.insert(0, start) while not pq.is_empty(): cost, ele = pq.delete_min() edge.add((prev[ele], ele)) overall_cost += cost visited.add(ele) for successor, edge_cost in graph.get_successors(ele): new_cost = edge_cost if successor not in visited and (successor not in costs or new_cost < costs[successor]): costs[successor] = new_cost prev[successor] = ele pq.update(new_cost, successor) return edge, overall_cost
def make_queue(self, score_arr): q = PriorityQueue() score_arr = score_arr.tocoo() for i, j, v in itertools.izip(score_arr.row, score_arr.col, score_arr.data): inverted_score = -v item = (i, j) q.put((inverted_score, item)) return q
def pq_sort(self, test_array): pq = PriorityQueue() for x in test_array: pq.insert(x) pq_size = pq.size() return [pq.extract_min() for x in range(pq_size)]
def __init__(self, lst=[]): self.minHeap = PriorityQueue() self.maxHeap = MaxHeap() self.size = len(lst) if lst: lst = sorted(lst) mid = len(lst) // 2 self.minHeap = PriorityQueue(lst[mid:]) self.maxHeap = MaxHeap(lst[0:mid])
def djikstra(start, neighbor_func, distance_func, goal_pred): visited = set() parents = {start: None} distances = {start: 0} queue = PQ() queue.add_task(start, distances[start]) while not queue.empty(): current = queue.pop_task() for neighbor in neighbor_func(current): if neighbor in visited: continue tentative_distance = distances[current] + distance_func( current, neighbor) if neighbor not in distances: queue.add_task(neighbor, tentative_distance) distances[neighbor] = tentative_distance parents[neighbor] = current elif tentative_distance < distances[neighbor]: queue.update_task(neighbor, tentative_distance) distances[neighbor] = tentative_distance parents[neighbor] = current visited.add(current) if goal_pred(current): return { "distance": distances[current], "path": reconstruct_path(current, parents), "parents": parents } return {"distance": float("inf"), "path": None, "parents": parents}
def run_dijkstra(graph, source, target): """Dijkstra's shortest path algorithm""" queue = PriorityQueue() dist = {source: 0} prev = {} for vertex in graph: if vertex != source: dist[vertex] = float("inf") queue.insert(vertex, dist[vertex]) while not queue.is_empty(): u_dist, u = queue.pop() u_node = graph[u] if u == target: break for v in u_node['linkTo']: if queue.is_node_in_queue(v): alt = dist[u] + \ calc_distance(int(u_node['x']), int(u_node['y']), int(graph[v]['x']), int(graph[v]['y'])) if alt < dist[v]: dist[v] = alt prev[v] = u queue.insert(v, alt) path = [] curr = target while curr in prev: path.append(curr) curr = prev[curr] path.append(source) return path[::-1]
def insert(self, item, priority): ''' Overrides the insert method in the 'PriorityQueue' class so that if a duplicate item is added, it changes the priority rather than inserting a copy. This will solve the problem that the given implementation can lose track of an item in the itemmap if it is inserted twice. ''' if item in self._itemmap: self.changepriority(item, priority) else: PriorityQueue.insert(self, item, priority)
def __init__(self, initial_state, goal_state, verbose=False): self.node_expansions = 0 self.unique_states = {} self.unique_states[initial_state.dictkey()] = True self.q = PriorityQueue() self.goal_state = goal_state self.q.enqueue(InformedNode(initial_state, None, 0, self.goal_state)) self.verbose = verbose solution = self.execute() if solution is None: print("Search failed") else: self.showPath(solution)
class MaxHeap(object): def __init__(self, lst=[]): lst = [(-prio, ele) for (prio, ele) in lst] self.maxHeap = PriorityQueue(lst) def insert(self, priority, ele): self.maxHeap.insert(-priority, ele) def delete_max(self): prio, ele = self.maxHeap.delete_min() return -prio, ele def get_max(self): prio, ele = self.maxHeap.get_min() return -prio, ele def size(self): return self.maxHeap.size()
def get_huffman_tree(frequency_lst): frequency_lst = Counter(s) pq = PriorityQueue() for char, freq in frequency_lst: pq.insert(freq, TreeNode(char)) while pq.size() > 1: freq1, node1 = pq.delete_min() freq2, node2 = pq.delete_min() internal_node = TreeNode(node1.val + node2.val, node1, node2) pq.insert(freq1 + freq2, internal_node) _, root = pq.delete_min() return get_code(root)
def Dijkstra(G, src): #initialization dist = {} # prev = {} Q = PriorityQueue() # print(g["home"].keys()) #출발노드 s는 자신까지의 거리가 0이고 자신의 predecessor dist[src] = 0 # prev[s] = None #다른 노드들은 모두 거리를 infinity로 설정하고 predecessor는 일단 None으로 설정하고 '''for n in g: dist[n[0]] = float('inf') prev[n[0]] = None dist[n[1]] = float('inf') prev[n[1]] = None ''' #그러면서 PQ에다가 노드들을 넣어줍니다. for node in G.keys(): if node != src: dist[node] = float('inf') #prev[n] = None ''' if n in g[s].keys(): dist[n] = float('inf') prev[n] = None ''' Q.insert(dist[node], node) # n이 우선순위 dist가 value #PQ가 빌때까지 계속 루프를 돌면서, while Q.size() > 0: p, u = Q.pop() #현재까지 가장 짧은 거리를 갖고 있는 노드를 pop #꺼낸 노드의 각 이웃들까지의 거리를 현재 자신까지의 minimum cost와 더한 후 #이웃들이 가지고 있는 거리보다 작으면 이것으로 업데이트 시키고 다시 PQ에 넣거나 update합니다 #pd insert 기능에 포함되어 있다고 한다. '''for v in g[u].keys(): # alt = dist[u] + g[u][v].get('weight',1) alt = dist[u] + g[u][v] if alt < dist[v]: dist[v] = alt prev[v] = u Q.insert(dist[v],v) #for v in g.neighbors(u): ''' for v in G[u].keys(): #alt = dist[u] + g[u][v].get('weight',1) alt = dist[u] + G[u][v] if alt < dist[v]: dist[v] = alt Q.insert(dist[v], v) return dist
def dijkstra(graph, start): prev = {} costs = {} costs[start] = 0 pq = PriorityQueue() for node in graph.nodes(): pq.insert(float('inf'), node) pq.insert(0, start) while not pq.is_empty(): cost, ele = pq.delete_min() for successor, edge_cost in graph.get_successors(ele): new_cost = cost + edge_cost if successor not in costs or new_cost < costs[successor]: costs[successor] = new_cost prev[successor] = ele pq.update(new_cost, successor) return prev, costs
def test_size_remove(self): pq = PriorityQueue() for i in range(100): pq.insert(i) for i in range(100): pq.extract_min() self.assertEqual(pq.size(), 0)
def __init__(self, turn=0, prob_power=1., max_uncertainty=1., training_nodes=None, utility_cap=1e-1, q=0.5): self.turn = turn self.prob_power = prob_power self.max_uncertainty = max_uncertainty self.training_nodes = training_nodes if self.training_nodes is None: self.training_nodes = PriorityQueue( lambda x: x[1].compressed, lambda x: x[0]) # TODO: implement max items self.utility_cap = utility_cap self.q = q
def __init__(self, dm, level_num, length, width, category): self.dm = dm self.eventQueue = PriorityQueue() self.cameras = {} self.light_sources = [] self.security_lockdown = False self.upStairs = '' self.downStairs = '' self.map = [] self.lvl_length = length self.lvl_width = width self.level_num = level_num self.category = category self.initialize_dungeon_locs() self.monsters = [] self.melee = MeleeResolver(dm, dm.dui) self.subnet_nodes = [] self.cameras_active = random() < 0.8 self.security_active = True
class InformedSearch(Search): """ Implement this. """ def __init__(self, initial_state, goal_state, verbose=False): self.node_expansions = 0 self.unique_states = {} self.unique_states[initial_state.dictkey()] = True self.q = PriorityQueue() self.goal_state = goal_state self.q.enqueue(InformedNode(initial_state, None, 0, self.goal_state)) self.verbose = verbose solution = self.execute() if solution is None: print("Search failed") else: self.showPath(solution) def execute(self): while not self.q.empty(): current = self.q.dequeue() self.node_expansions += 1 if self.goal_state.equals(current.state): return current else: successors = current.state.applyOperators() for next_state in successors: if next_state.dictkey() not in self.unique_states.keys(): n = InformedNode(next_state, current, current.depth + 1, self.goal_state) self.q.enqueue(n) self.unique_states[next_state.dictkey()] = True if self.verbose: print("Expanded:", current) print("Number of successors:", len(successors)) print("Queue length: ", self.q.size()) print("-------------------------------") return None def get_expansions(self): return self.node_expansions
def astar_search(initial_state): """ A* search algorithm for single-player Chexers. Conducts a full A* search to the nearest goal state from `initial_state`. """ # store the current best-known partial path cost to each state we have # encountered: g = {initial_state: 0} # store the previous state in this least-cost path, along with action # taken to reach each state: prev = {initial_state: None} # initialise a priority queue with initial state (f(s) = 0 + h(s)): queue = PriorityQueue() queue.update(initial_state, g[initial_state] + h(initial_state)) # (concurrent iteration is allowed on this priority queue---this will loop # until the queue is empty, and we may modify the queue inside) for state in queue: # if we are expanding a goal state, we can terminate the search! if state.is_goal(): return reconstruct_action_sequence(state, prev) # else, consider all successor states for addition to the queue (if # we see a cheaper path) # for our problem, all paths through state have the same path cost, # so we can just compute it once now: g_new = g[state] + 1 for (action, successor_state) in state.actions_successors(): # if this is the first time we are seeing the state, or if we # have found a new path to the state with lower cost, we must # update the priority queue by inserting/modifying this state with # the appropriate f-cost. # (note: since our heuristic is consistent we should never discover # a better path to a previously expanded state) if successor_state not in g or g[successor_state] > g_new: # a better path! save it: g[successor_state] = g_new prev[successor_state] = (state, action) # and update the priority queue queue.update(successor_state, g_new + h(successor_state)) # if the priority queue ever runs dry, then there must be no path to a goal # state. return None
def run_astar(start_dict, h, start_name): hname = h.__name__ print("running astar with " + hname) def get_f(state): return h(state) + state.get_g() start_state = State(start_dict) q = PriorityQueue(get_f) q.put(start_state) popped = 0 while not q.empty(): state = q.get() popped += 1 if state.is_solved(): log_result("astar_" + hname + "_results.txt", start_state, start_name, state, popped, heuristic=h) return popped moves = state.get_moves() for move in moves: q.put(state.make_move(move)) print("failed to solve!")
def test_size_initial(self): pq = PriorityQueue() self.assertEqual(pq.size(), 0)
class Median(object): def __init__(self, lst=[]): self.minHeap = PriorityQueue() self.maxHeap = MaxHeap() self.size = len(lst) if lst: lst = sorted(lst) mid = len(lst) // 2 self.minHeap = PriorityQueue(lst[mid:]) self.maxHeap = MaxHeap(lst[0:mid]) def get_median(self): if self.size == 0: raise IndexError("empty heap") if self.size == 1 or self.size % 2 != 0: return self.minHeap.get_min()[0] else: return self.maxHeap.get_max()[0] def insert(self, prio, ele): if self.size == 0: self.minHeap.insert(prio, ele) elif self.size == 1: self.minHeap.insert(prio, ele) prio, ele = self.minHeap.delete_min() self.maxHeap.insert(prio, ele) else: min_in_minHeap = self.minHeap.get_min()[0] max_in_maxHeap = self.maxHeap.get_max()[1] if prio >= min_in_minHeap: self.minHeap.insert(prio, ele) else: self.maxHeap.insert(prio, ele) if not self.is_balanced(): self.balance() self.size += 1 def is_balanced(self): return self.minHeap.size() <= self.maxHeap.size() + 1 and \ self.minHeap.size() >= self.maxHeap.size() def balance(self): while not self.is_balanced(): if self.minHeap.size() >= self.maxHeap.size() + 1: prio, ele = self.minHeap.delete_min() self.maxHeap.insert(prio, ele) else: prio, ele = self.maxHeap.delete_max() self.minHeap.insert(prio, ele)
def __init__(self, lst=[]): lst = [(-prio, ele) for (prio, ele) in lst] self.maxHeap = PriorityQueue(lst)
def test_size_insert(self): pq = PriorityQueue() for i in range(100): self.assertEqual(pq.size(), i) pq.insert(i)
class GameLevel: def __init__(self, dm, level_num, length, width, category): self.dm = dm self.eventQueue = PriorityQueue() self.cameras = {} self.light_sources = [] self.security_lockdown = False self.upStairs = '' self.downStairs = '' self.map = [] self.lvl_length = length self.lvl_width = width self.level_num = level_num self.category = category self.initialize_dungeon_locs() self.monsters = [] self.melee = MeleeResolver(dm, dm.dui) self.subnet_nodes = [] self.cameras_active = random() < 0.8 self.security_active = True # It would be nice if instead of alerting all monsters within a # certain radius, if the sound were blocked by walls, muffled by # doors etc. A flood-fill algorithm of some sort? def handle_stealth_check(self, player): _loudness = do_d10_roll(1,1) _roll = player.stealth_roll() _roll = int(round(_roll / 10.0)) _volume = _loudness - _roll if _roll < 1: _roll = 1 _radius = 6 - _roll if _radius < 1: _radius = 1 _noise = Noise(_volume, player, player.row, player.col, 'walking') self.monsters_react_to_noise(_radius, _noise) def monsters_react_to_noise(self, radius, noise): for _m in self.monsters: _d = calc_distance(noise.row, noise.col, _m.row, _m.col) if _d <= radius: _spotted = _m.react_to_noise(noise) # I can later use success or failure of action to count # as practice toward the player improving his skills # ie., if noise.description == 'walking'... # is a location a valid square in the current map def in_bounds(self,r,c): return r >= 0 and r < self.lvl_length and c >= 0 and c < self.lvl_width def is_cyberspace(self): return False def add_item_to_sqr(self, row, col, item): if not hasattr(self.dungeon_loc[row][col], 'item_stack'): setattr(self.dungeon_loc[row][col], 'item_stack', ItemStack()) self.dungeon_loc[row][col].item_stack.append(item) def size_of_item_stack(self, row, col): _loc = self.dungeon_loc[row][col] if not hasattr(_loc, 'item_stack'): return 0 return len(_loc.item_stack) def add_light_source(self, light_source): _sc = Shadowcaster(self.dm, light_source.radius, light_source.row, light_source.col) light_source.illuminates = _sc.calc_visible_list() light_source.illuminates[(light_source.row, light_source.col)] = 0 self.light_sources.append(light_source) def clear_bresenham_points(self, row, col, radius): _pts = [] x = radius y = 0 error = 0 sqrx_inc = 2 * radius - 1 sqry_inc = 1 while (y <= x): if self.is_clear(row+y, col+x): _pts.append((row+y, col+x)) if self.is_clear(row-y, col+x): _pts.append((row-y, col+x)) if self.is_clear(row+y, col-x): _pts.append((row+y, col-x)) if self.is_clear(row-y, col-x): _pts.append((row-y, col-x)) if self.is_clear(row+x, col+y): _pts.append((row+x, col+y)) if self.is_clear(row-x, col+y): _pts.append((row-x, col+y)) if self.is_clear(row+x, col-y): _pts.append((row+x, col-y)) if self.is_clear(row-x, col-y): _pts.append((row-x, col-y)) y += 1 error += sqry_inc sqry_inc = sqry_inc + 2 if error > x: x -= 1 error -= sqrx_inc sqrx_inc -= 2 return _pts def disable_lifts(self): if self.upStairs != '': _up = self.map[self.upStairs[0]][self.upStairs[1]] _up.activated = False if self.downStairs != '': _down = self.map[self.downStairs[0]][self.downStairs[1]] _down.activated = False def douse_squares(self, ls): self.eventQueue.pluck(('extinguish', ls.row, ls.col, ls)) self.light_sources.remove(ls) for _d in ls.illuminates: self.dungeon_loc[_d[0]][_d[1]].lit = False def end_of_turn(self): self.dm.meatspace_end_of_turn_cleanup() if self.dm.turn % 20 == 0: self.dm.player.add_hp(1) if self.dm.turn % 50 == 0: for m in self.monsters: m.add_hp(1) if random() < 0.5: self.add_monster() self.dm.turn += 1 def end_security_lockdown(self): self.security_lockdown = False def extinguish_light_source(self, light_source): stack = self.dungeon_loc[light_source.row][light_source.col].item_stack for item in stack: if item == light_source: self.douse_squares(light_source) if isinstance(item, Items.LitFlare): stack.remove(item) _msg = light_source.get_name() + ' has gone out.' self.dm.alert_player_to_event(light_source.row, light_source.col, self, _msg, True) # this could maybe be moved to GamePersistence? def generate_save_object(self): for m in self.monsters: m.dm = '' self.clear_occupants() _exit_point = (self.dm.player.row,self.dm.player.col) _save_obj = (self.map,self.dungeon_loc,self.eventQueue,self.light_sources,self.monsters, \ self.category,self.level_num,_exit_point,self.cameras,self.upStairs,self.downStairs,\ self.security_lockdown, self.subnet_nodes, self.cameras_active, self.security_active) return _save_obj # I'm going to use the Bresenham circle algorithm to generate # "circles" to check, and work my way out until I find a clear # space. # # Sanity check: if we've searched radius > 10 and not found # a clear spot, then we're probably not going to find one. def get_nearest_clear_space(self, r, c): _radius = 1 while True: _pts = self.clear_bresenham_points(r, c, _radius) if len(_pts) > 0: return choice(_pts) _radius += 1 if _radius > 10: return None def get_occupant(self, r, c): return self.dungeon_loc[r][c].occupant def is_clear(self,r,c): if not self.in_bounds(r,c): return False return self.map[r][c].is_passable() and self.dungeon_loc[r][c].occupant == '' def place_sqr(self, sqr, target_type): while True: r = randrange(1,self.lvl_length-1) c = randrange(1,self.lvl_width-1) if self.map[r][c].get_type() == target_type: break self.map[r][c] = sqr def remove_monster(self, monster, row, col): self.dungeon_loc[row][col].occupant = '' self.monsters.remove(monster) def resolve_events(self): while len(self.eventQueue) > 0 and self.eventQueue.peekAtNextPriority() <= self.dm.turn: event = self.eventQueue.pop() if event[0] == 'explosion': self.dm.handle_explosion(self, event[1],event[2],event[3]) # bomb is returned, return tile to what it was _sqr = self.map[event[1]][event[2]] if isinstance(_sqr,Terrain.Trap): self.map[event[1]][event[2]] = _sqr.previousTile self.dm.update_sqr(self, event[1], event[2]) elif event[0] == 'extinguish': self.extinguish_light_source(event[3]) def clear_occupants(self): for row in self.dungeon_loc: for cell in row: cell.occupant = '' def add_feature_to_map(self, feature): while True: r = randrange(1,self.lvl_length-1) c = randrange(1,self.lvl_width-1) if self.map[r][c].get_type() == FLOOR: feature.row = r feature.col = c self.map[r][c] = feature break def remove_light_source(self, light_source): _target = '' for _ls in self.light_sources: if _ls == light_source: _target = _ls if _target != '': self.light_sources.remove(_target) def add_item(self, _chart): _item = _chart.get_item(self.level_num) while True: r = randrange(self.lvl_length) c = randrange(self.lvl_width) if self.map[r][c].get_type() == FLOOR: self.add_item_to_sqr(r,c,_item) break def add_pack(self, monster_name, low, high, r, c): for j in range(randrange(low,high+1)): _sqr = self.get_nearest_clear_space(r,c) if _sqr != None: _monster = MonsterFactory.get_monster_by_name(self.dm, monster_name, _sqr[0], _sqr[1]) self.add_monster_to_dungeon(_monster, _sqr[0], _sqr[1]) def add_monster(self, monster=''): # This loop currently doesn't handle the oddball case where the dungeon is full! # Should be fixed, otherwise it will be an infinite loop, and unpleasant for the # player! while True: try_r = randrange(0,self.lvl_length) try_c = randrange(0,self.lvl_width) _sqr = self.map[try_r][try_c] # This'll prevent a monster from being generated where the player will # appear when first entering the level if _sqr.get_type() in (UP_STAIRS, DOWN_STAIRS): continue if self.is_clear(try_r,try_c): r = try_r c = try_c break if monster.level < self.level_num: monster.level = self.level_num self.add_monster_to_dungeon(monster, r, c) def add_monster_to_dungeon(self, monster, r, c): monster.row = r monster.col = c self.dungeon_loc[r][c].occupant = monster self.monsters.append(monster) def get_player_start_loc(self): return self.player_start_loc def initialize_dungeon_locs(self): self.dungeon_loc = [] for r in range(0,self.lvl_length): row = [] for c in range(0,self.lvl_width): row.append(DungeonSqr(False, False, False)) self.dungeon_loc.append(row) def begin_security_lockdown(self): pass
def test_empty_extract(self): pq = PriorityQueue() self.assertEqual(pq.extract_min(), None)
def getMove(self, state, nslaves=1): '''Make the AI make a move. Args: state: <State> Returns: <Move> in the move_list of 'state' ''' hash_fn = lambda node: node.state.compressed #TODO remove #value_fn = lambda node: node._global_log_prob #TODO strengthen value_fn = lambda node: node.depth pq = PriorityQueue(hash_fn, value_fn) player_info = PlayerInfo(turn=state.player_turn, prob_power=0.1, max_uncertainty=self._max_uncertainty, q=self.q_choice) root = StateNode(state, player_info) pq.add(root) redundant = dict() slave_procs = [] slave_pipes = [] for pidx in range(nslaves): slave_pipe, pipe = Pipe() proc = Process(target=AIPlayer.evalStates, args=(self, pipe)) slave_procs += [proc] slave_pipes += [slave_pipe] proc.start() nchecked = 0 target_slave = 0 flying_nodes = 0 while nchecked < self._max_states and len( pq) + flying_nodes: #terminal condition if len(pq): next = pq.pop() next_state = next.state compressed = next_state.compressed if compressed not in redundant: redundant[compressed] = next else: original = redundant[compressed] #next = redundant[compressed] #for new_node in next.parent._addChild(): for new_node in next.reportRedundant(original): pq.add(new_node) continue pipe = slave_pipes[target_slave] pipe.send(next_state) flying_nodes += 1 nchecked += 1 for pipe in slave_pipes: if pipe.poll(): try: obj = pipe.recv() flying_nodes -= 1 if not obj: print('ERROR: slave closed before master [E1]') heur_bundle, compressed = obj new_nodes = redundant[compressed].check(heur_bundle) for new_node in new_nodes: pq.add(new_node) except EOFError: print('ERROR: slave closed before master [E2]') for pipe in slave_pipes: pipe.send(None) active_pipes = copy.copy(slave_pipes) while active_pipes: for pipe in active_pipes: try: obj = pipe.recv() if not obj: active_pipes.remove(pipe) continue heur_bundle, compressed = obj redundant[compressed].check(heur_bundle) except EOFError: pipes.remove(pipe) if self.train_iterations: X = [] Y = [] while len(player_info.training_nodes): _, training_state, value, err = player_info.training_nodes.pop( ) #value = node._expected_value #err = (node._expected_value - node._self_value) ** 2 x = training_state.features() y = torch.FloatTensor([value, err]) X += [x] Y += [y] if self._model: self.train(X, Y) #cleanNode(root) #for child in root.children: # child.recalcValue(verbose=True) # find best move # PENDING: add randomness best_node = None moves = [] uprobs = [] for node in root.children: #print(node.value, node._self_value # TODO re add #print(node.state.toString()) # TODO re add if not best_node or (node.value - best_node.value) * ( 2 * state.player_turn - 1) > 0: best_node = node moves += [node.move] uprobs += [ get_uprob(get_utility(node.value, state.player_turn), node.uncertainty, player_info.q) ] if self.train_iterations > 0: prob_scale = random.uniform(0, sum(uprobs)) for i in range(len(uprobs)): prob_scale -= uprobs[i] if prob_scale <= 0: return moves[i] #return state.moves[0] #TEMP return best_node.move
def test_empty_peek(self): pq = PriorityQueue() self.assertEqual(pq.find_min(), None)